v2.0: SQLite statt PostgreSQL (keine externe DB nötig)
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
FROM node:22-alpine
|
FROM node:22-alpine
|
||||||
|
|
||||||
|
# better-sqlite3 braucht build tools
|
||||||
|
RUN apk add --no-cache python3 make g++
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
@@ -7,6 +10,9 @@ RUN npm install --production
|
|||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
# Datenverzeichnis für SQLite
|
||||||
|
RUN mkdir -p /data
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["node", "server.js"]
|
CMD ["node", "server.js"]
|
||||||
|
|||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "techno-todo",
|
"name": "techno-todo",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"description": "⚡ 90s Techno-Style Todo App",
|
"description": "⚡ 90s Techno-Style Todo App (SQLite edition)",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.21.0",
|
"express": "^4.21.0",
|
||||||
"pg": "^8.13.0",
|
"better-sqlite3": "^11.7.0",
|
||||||
"ejs": "^3.1.10"
|
"ejs": "^3.1.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,22 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { Pool } = require('pg');
|
const Database = require('better-sqlite3');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
|
||||||
// PostgreSQL connection
|
// SQLite – keine externe DB nötig
|
||||||
const pool = new Pool({
|
const db = new Database('/data/todos.db');
|
||||||
connectionString: process.env.DATABASE_URL,
|
db.pragma('journal_mode = WAL');
|
||||||
ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
|
db.exec(`
|
||||||
});
|
CREATE TABLE IF NOT EXISTS todos (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
// Initialize DB table
|
text TEXT NOT NULL,
|
||||||
async function initDB() {
|
done INTEGER DEFAULT 0,
|
||||||
const client = await pool.connect();
|
created_at TEXT DEFAULT (datetime('now'))
|
||||||
try {
|
)
|
||||||
await client.query(`
|
`);
|
||||||
CREATE TABLE IF NOT EXISTS todos (
|
console.log('⚡ DATABASE ONLINE (SQLite) ⚡');
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
text TEXT NOT NULL,
|
|
||||||
done BOOLEAN DEFAULT FALSE,
|
|
||||||
created_at TIMESTAMP DEFAULT NOW()
|
|
||||||
)
|
|
||||||
`);
|
|
||||||
console.log('⚡ DATABASE ONLINE ⚡');
|
|
||||||
} finally {
|
|
||||||
client.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
app.use(express.static(path.join(__dirname, 'public')));
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
@@ -35,44 +24,39 @@ app.set('view engine', 'ejs');
|
|||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.get('/', async (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
try {
|
try {
|
||||||
const result = await pool.query('SELECT * FROM todos ORDER BY created_at DESC');
|
const todos = db.prepare('SELECT * FROM todos ORDER BY created_at DESC').all();
|
||||||
res.render('index', { todos: result.rows, error: null });
|
res.render('index', { todos, error: null });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.render('index', { todos: [], error: 'DATABASE CONNECTION LOST ⚠' });
|
res.render('index', { todos: [], error: 'DATABASE ERROR ⚠' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/add', async (req, res) => {
|
app.post('/add', (req, res) => {
|
||||||
const { text } = req.body;
|
const { text } = req.body;
|
||||||
if (text && text.trim()) {
|
if (text && text.trim()) {
|
||||||
await pool.query('INSERT INTO todos (text) VALUES ($1)', [text.trim()]);
|
db.prepare('INSERT INTO todos (text) VALUES (?)').run(text.trim());
|
||||||
}
|
}
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/toggle/:id', async (req, res) => {
|
app.post('/toggle/:id', (req, res) => {
|
||||||
await pool.query('UPDATE todos SET done = NOT done WHERE id = $1', [req.params.id]);
|
db.prepare('UPDATE todos SET done = NOT done WHERE id = ?').run(req.params.id);
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/delete/:id', async (req, res) => {
|
app.post('/delete/:id', (req, res) => {
|
||||||
await pool.query('DELETE FROM todos WHERE id = $1', [req.params.id]);
|
db.prepare('DELETE FROM todos WHERE id = ?').run(req.params.id);
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Health check
|
app.get('/health', (req, res) => res.json({ status: 'ONLINE', db: 'SQLITE' }));
|
||||||
app.get('/health', (req, res) => res.json({ status: 'ONLINE', db: 'CONNECTED' }));
|
|
||||||
|
|
||||||
initDB().then(() => {
|
app.listen(PORT, () => {
|
||||||
app.listen(PORT, () => {
|
console.log(`╔══════════════════════════════════════╗`);
|
||||||
console.log(`╔══════════════════════════════════════╗`);
|
console.log(`║ ⚡ TECHNO-TODO v2.0 ONLINE ⚡ ║`);
|
||||||
console.log(`║ ⚡ TECHNO-TODO v1.0 ONLINE ⚡ ║`);
|
console.log(`║ PORT: ${PORT} ║`);
|
||||||
console.log(`║ PORT: ${PORT} ║`);
|
console.log(`║ DB: SQLite (no externals) ║`);
|
||||||
console.log(`╚══════════════════════════════════════╝`);
|
console.log(`╚══════════════════════════════════════╝`);
|
||||||
});
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('Failed to init DB:', err);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user