feat: words table, M2M with pictures and categories

- words table with trilingual titles, status enum, difficulty level, timestamps
- word_pictures junction table (M2M words <-> pictures)
- categories placeholder table
- word_categories junction table (M2M words <-> categories)
- Auto-timestamps on status change (requested/published/blocked)
- Full CRUD + link/unlink endpoints for pictures and categories
- README updated with schema and endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 14:05:28 +02:00
parent b5f5745107
commit 8751d7ceae
4 changed files with 294 additions and 2 deletions

View File

@@ -34,7 +34,66 @@ async function migrate() {
FOR EACH ROW EXECUTE FUNCTION update_updated_at()
`);
console.log('Migration complete: pictures table ready');
// words
await query(`
CREATE TABLE IF NOT EXISTS words (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
titel_de TEXT,
titel_en TEXT,
titel_se TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'requested'
CHECK (status IN ('requested', 'translated', 'generated', 'blocked', 'published')),
difficulty_level SMALLINT CHECK (difficulty_level BETWEEN 1 AND 50),
requested_at TIMESTAMPTZ,
published_at TIMESTAMPTZ,
blocked_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`);
await query(`
DROP TRIGGER IF EXISTS words_updated_at ON words;
CREATE TRIGGER words_updated_at
BEFORE UPDATE ON words
FOR EACH ROW EXECUTE FUNCTION update_updated_at()
`);
// M2M: words <-> pictures
await query(`
CREATE TABLE IF NOT EXISTS word_pictures (
word_id UUID NOT NULL REFERENCES words(id) ON DELETE CASCADE,
picture_id UUID NOT NULL REFERENCES pictures(id) ON DELETE CASCADE,
PRIMARY KEY (word_id, picture_id)
)
`);
// categories (Platzhalter — Felder folgen im nächsten Schritt)
await query(`
CREATE TABLE IF NOT EXISTS categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`);
await query(`
DROP TRIGGER IF EXISTS categories_updated_at ON categories;
CREATE TRIGGER categories_updated_at
BEFORE UPDATE ON categories
FOR EACH ROW EXECUTE FUNCTION update_updated_at()
`);
// M2M: words <-> categories
await query(`
CREATE TABLE IF NOT EXISTS word_categories (
word_id UUID NOT NULL REFERENCES words(id) ON DELETE CASCADE,
category_id UUID NOT NULL REFERENCES categories(id) ON DELETE CASCADE,
PRIMARY KEY (word_id, category_id)
)
`);
console.log('Migration complete');
}
module.exports = migrate;