fix(deploy): resolve Docker startup and CSRF issues

- Rename TASKPLANER_DATA_DIR to DATA_DIR (avoid adapter-node envPrefix conflict)
- Add TASKPLANER_ORIGIN for CSRF protection in docker-compose.yml
- Add automatic database schema initialization on startup
- Add Playwright E2E tests for Docker deployment verification
- Update .env.example with correct variable names

Fixes container restart loop and 403 errors on form submission.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Thomas Richter
2026-02-01 15:54:44 +01:00
parent 89e703daa5
commit 84ad332737
11 changed files with 304 additions and 7 deletions

View File

@@ -4,7 +4,7 @@ import * as schema from './schema';
import { existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
const DATA_DIR = process.env.TASKPLANER_DATA_DIR || './data';
const DATA_DIR = process.env.DATA_DIR || './data';
const DB_PATH = join(DATA_DIR, 'taskplaner.db');
// Ensure data directory exists
@@ -18,6 +18,49 @@ const sqlite = new Database(DB_PATH);
// Enable WAL mode for better concurrent read performance
sqlite.pragma('journal_mode = WAL');
// Initialize schema if tables don't exist
const tableExists = sqlite
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entries'")
.get();
if (!tableExists) {
sqlite.exec(`
CREATE TABLE entries (
id TEXT PRIMARY KEY,
title TEXT,
content TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'thought' CHECK(type IN ('task', 'thought')),
status TEXT DEFAULT 'open' CHECK(status IN ('open', 'done', 'archived')),
pinned INTEGER DEFAULT 0,
due_date TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE images (
id TEXT PRIMARY KEY,
entry_id TEXT NOT NULL REFERENCES entries(id) ON DELETE CASCADE,
filename TEXT NOT NULL,
ext TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE TABLE tags (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE UNIQUE INDEX tagNameUniqueIndex ON tags(lower(name));
CREATE TABLE entry_tags (
entry_id TEXT NOT NULL REFERENCES entries(id) ON DELETE CASCADE,
tag_id TEXT NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (entry_id, tag_id)
);
`);
console.log('Database schema initialized');
}
export const db = drizzle(sqlite, { schema });
export { schema };

View File

@@ -1,7 +1,7 @@
import { mkdir, writeFile, unlink } from 'node:fs/promises';
import { join } from 'node:path';
const DATA_DIR = process.env.TASKPLANER_DATA_DIR || './data';
const DATA_DIR = process.env.DATA_DIR || './data';
export const UPLOAD_DIR = join(DATA_DIR, 'uploads');
export const ORIGINALS_DIR = join(DATA_DIR, 'uploads/originals');
export const THUMBNAILS_DIR = join(DATA_DIR, 'uploads/thumbnails');