// Resources a user generated for themselves. // // Learning content is moderator-owned and published into categories for // everyone. This is the other thing people wanted: somewhere to generate a deck // for tomorrow's teaching session without it becoming institutional content, // and without needing to be a moderator to do it at all. // // Private by construction. Every query filters on user_id, and the foreign key // cascades, so deleting an account takes its drafts with it. There is no // category, no publish state and no sharing: this table is one person's // workspace, and adding sharing later should be a deliberate decision rather // than something that leaks out of a missing WHERE clause. exports.up = pgm => { pgm.sql(` CREATE TABLE IF NOT EXISTS user_resources ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, title TEXT NOT NULL DEFAULT 'Untitled', -- presentation | article. Decides which prompt writes it and which -- formats it exports to. kind TEXT NOT NULL DEFAULT 'presentation', -- Markdown is the artifact. Every export is rendered from it on demand, -- so refining means editing text rather than patching a binary. markdown TEXT NOT NULL DEFAULT '', topic TEXT NOT NULL DEFAULT '', -- How many corpus excerpts it was written from; 0 means the model alone. grounded_count INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_user_resources_owner ON user_resources(user_id, created_at DESC); `); }; exports.down = pgm => { pgm.sql('DROP TABLE IF EXISTS user_resources;'); };