Kansho/backend/schema.sql
Lars a65ea98b0c
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Test Suite / pytest-backend (push) Successful in 2m53s
Test Suite / smoke-dev (push) Successful in 0s
Test Suite / frontend-build (push) Successful in 15s
Store mask-review excerpts and bind kinship from local phrase context.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 21:34:27 +02:00

574 lines
21 KiB
SQL

CREATE TABLE IF NOT EXISTS schema_migrations (
id TEXT PRIMARY KEY,
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS tiers (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
active INTEGER NOT NULL DEFAULT 1,
sort_order INTEGER NOT NULL DEFAULT 0,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS features (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
category TEXT NOT NULL DEFAULT 'platform',
limit_type TEXT NOT NULL CHECK (limit_type IN ('boolean', 'count')),
default_limit INTEGER,
reset_period TEXT NOT NULL DEFAULT 'none' CHECK (reset_period IN ('none', 'day', 'month')),
active INTEGER NOT NULL DEFAULT 1,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS tier_limits (
tier_id TEXT NOT NULL REFERENCES tiers(id) ON DELETE CASCADE,
feature_id TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
limit_value INTEGER,
PRIMARY KEY (tier_id, feature_id)
);
CREATE TABLE IF NOT EXISTS profiles (
id TEXT PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
password_hash TEXT NOT NULL,
role TEXT NOT NULL CHECK (role IN ('user', 'admin')),
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
tier_id TEXT NOT NULL DEFAULT 'local' REFERENCES tiers(id),
session_days INTEGER NOT NULL DEFAULT 30,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
expires_at TEXT NOT NULL,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS user_feature_restrictions (
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
feature_id TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
limit_value INTEGER,
PRIMARY KEY (profile_id, feature_id)
);
CREATE TABLE IF NOT EXISTS user_feature_usage (
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
feature_id TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
period_key TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (profile_id, feature_id, period_key)
);
CREATE TABLE IF NOT EXISTS ai_prompts (
id TEXT PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
category TEXT NOT NULL DEFAULT 'uncategorized',
prompt_type TEXT NOT NULL DEFAULT 'base' CHECK (prompt_type IN ('base', 'pipeline', 'workflow')),
template TEXT NOT NULL DEFAULT '',
stages_json TEXT,
graph_json TEXT,
output_format TEXT NOT NULL DEFAULT 'text',
output_schema_json TEXT,
required_feature TEXT NOT NULL DEFAULT 'ai_calls',
active INTEGER NOT NULL DEFAULT 1,
is_system_default INTEGER NOT NULL DEFAULT 0,
default_template TEXT NOT NULL DEFAULT '',
seed_revision TEXT NOT NULL DEFAULT '',
sort_order INTEGER NOT NULL DEFAULT 0,
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS usage_sessions (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
intent TEXT NOT NULL DEFAULT '',
started_at TEXT NOT NULL DEFAULT (datetime('now')),
ended_at TEXT,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS conversations (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
usage_session_id TEXT REFERENCES usage_sessions(id),
title TEXT NOT NULL DEFAULT '',
space_id TEXT,
journal_day_id TEXT,
narrative_mode TEXT NOT NULL DEFAULT '',
reflection_depth TEXT NOT NULL DEFAULT '',
current_focus TEXT NOT NULL DEFAULT '',
emotional_intensity TEXT NOT NULL DEFAULT '',
long_story INTEGER NOT NULL DEFAULT 0,
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS messages (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
seq INTEGER NOT NULL,
role TEXT NOT NULL,
body TEXT NOT NULL,
created TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (conversation_id, seq)
);
CREATE TABLE IF NOT EXISTS threads (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
title TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'open',
visibility TEXT NOT NULL DEFAULT 'internal' CHECK (visibility IN ('internal', 'user')),
resurfacing_at TEXT,
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS conversation_threads (
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
thread_id TEXT NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
PRIMARY KEY (conversation_id, thread_id)
);
CREATE TABLE IF NOT EXISTS spaces (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
title TEXT NOT NULL DEFAULT '',
visibility TEXT NOT NULL DEFAULT 'internal' CHECK (visibility IN ('internal', 'user')),
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS thread_spaces (
thread_id TEXT NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
confidence REAL,
PRIMARY KEY (thread_id, space_id)
);
CREATE TABLE IF NOT EXISTS derived_records (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
kind TEXT NOT NULL,
subject_type TEXT NOT NULL,
subject_id TEXT NOT NULL,
source_message_ids TEXT NOT NULL,
as_of TEXT NOT NULL,
confidence REAL,
visibility TEXT NOT NULL DEFAULT 'internal' CHECK (visibility IN ('internal', 'user')),
body TEXT NOT NULL DEFAULT '',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS handoffs (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
target TEXT NOT NULL CHECK (target IN ('journal', 'memory', 'knowledge', 'action', 'mindnet', 'obsidian')),
status TEXT NOT NULL DEFAULT 'draft',
source_conversation_id TEXT REFERENCES conversations(id),
payload_json TEXT NOT NULL DEFAULT '{}',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS external_refs (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
target TEXT NOT NULL CHECK (target IN ('mindnet', 'obsidian')),
external_id TEXT NOT NULL DEFAULT '',
kansho_type TEXT NOT NULL,
kansho_id TEXT NOT NULL,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS re_grounding_events (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
subject_type TEXT NOT NULL,
subject_id TEXT NOT NULL,
reason TEXT NOT NULL DEFAULT '',
source_message_ids TEXT NOT NULL DEFAULT '[]',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS identity_mappings (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
token TEXT NOT NULL,
local_label TEXT NOT NULL DEFAULT '',
canonical_label TEXT NOT NULL DEFAULT '',
entity_type TEXT NOT NULL DEFAULT 'PERSON',
status TEXT NOT NULL DEFAULT 'legacy_review_required',
origin TEXT NOT NULL DEFAULT 'legacy_auto',
aliases_json TEXT NOT NULL DEFAULT '[]',
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now')),
confirmed_at TEXT,
UNIQUE (profile_id, token)
);
CREATE TABLE IF NOT EXISTS identity_review_proposals (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
observed_label TEXT NOT NULL DEFAULT '',
entity_type TEXT NOT NULL DEFAULT 'PERSON',
status TEXT NOT NULL DEFAULT 'unconfirmed',
origin TEXT NOT NULL DEFAULT 'detect_proposal',
last_seen TEXT NOT NULL DEFAULT (datetime('now')),
created TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (profile_id, observed_label, entity_type)
);
CREATE TABLE IF NOT EXISTS label_senses (
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
normalized_label TEXT NOT NULL,
identity_hits INTEGER NOT NULL DEFAULT 0,
non_identity_hits INTEGER NOT NULL DEFAULT 0,
updated TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (profile_id, normalized_label)
);
CREATE TABLE IF NOT EXISTS label_sense_cues (
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
normalized_label TEXT NOT NULL,
cue TEXT NOT NULL,
decision TEXT NOT NULL,
hits INTEGER NOT NULL DEFAULT 1,
excerpt TEXT NOT NULL DEFAULT '',
updated TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (profile_id, normalized_label, cue)
);
CREATE TABLE IF NOT EXISTS pending_mask_reviews (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
user_message_id TEXT NOT NULL,
payload_json TEXT NOT NULL DEFAULT '{}',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_pending_mask_reviews_conv
ON pending_mask_reviews (profile_id, conversation_id);
CREATE TABLE IF NOT EXISTS journal_days (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
calendar_date TEXT NOT NULL,
scratch_json TEXT NOT NULL DEFAULT '[]',
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (space_id, calendar_date)
);
CREATE TABLE IF NOT EXISTS journal_drafts (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
journal_day_id TEXT NOT NULL REFERENCES journal_days(id) ON DELETE CASCADE,
title TEXT NOT NULL DEFAULT '',
body TEXT NOT NULL DEFAULT '',
source_conversation_ids TEXT NOT NULL DEFAULT '[]',
source_message_ids TEXT NOT NULL DEFAULT '[]',
as_of TEXT NOT NULL,
superseded_at TEXT,
generation_snapshot TEXT NOT NULL DEFAULT '{}',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS journal_entries (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
journal_day_id TEXT NOT NULL REFERENCES journal_days(id) ON DELETE CASCADE,
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
current_version_id TEXT,
deleted_at TEXT,
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS journal_entry_versions (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
entry_id TEXT NOT NULL REFERENCES journal_entries(id) ON DELETE CASCADE,
title TEXT NOT NULL DEFAULT '',
body TEXT NOT NULL DEFAULT '',
source_conversation_ids TEXT NOT NULL DEFAULT '[]',
source_message_ids TEXT NOT NULL DEFAULT '[]',
origin TEXT NOT NULL CHECK (origin IN ('user_edit', 'accepted_draft', 'restore')),
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS journal_draft_source_refs (
draft_id TEXT NOT NULL REFERENCES journal_drafts(id) ON DELETE CASCADE,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
source_kind TEXT NOT NULL CHECK (source_kind IN ('conversation', 'message')),
source_id TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (draft_id, source_kind, source_id)
);
CREATE TABLE IF NOT EXISTS journal_entry_version_source_refs (
version_id TEXT NOT NULL REFERENCES journal_entry_versions(id) ON DELETE CASCADE,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
source_kind TEXT NOT NULL CHECK (source_kind IN ('conversation', 'message')),
source_id TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (version_id, source_kind, source_id)
);
CREATE TABLE IF NOT EXISTS media_assets (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
entry_id TEXT NOT NULL REFERENCES journal_entries(id) ON DELETE CASCADE,
entry_version_id TEXT REFERENCES journal_entry_versions(id),
filename TEXT NOT NULL DEFAULT '',
content_type TEXT NOT NULL,
rel_path TEXT NOT NULL,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS writing_profiles (
profile_id TEXT PRIMARY KEY REFERENCES profiles(id) ON DELETE CASCADE,
compiled_brief TEXT NOT NULL DEFAULT '',
governance TEXT NOT NULL DEFAULT 'learning' CHECK (governance IN ('learning', 'advising', 'frozen')),
lifecycle TEXT NOT NULL DEFAULT 'uninitialized' CHECK (lifecycle IN ('uninitialized', 'initial_pending', 'confirmed')),
version INTEGER NOT NULL DEFAULT 0,
review_ready INTEGER NOT NULL DEFAULT 0,
last_reviewed TEXT,
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS writing_profile_sources (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
kind TEXT NOT NULL CHECK (kind IN ('imported_text', 'journal_entry', 'dialogue_style')),
body TEXT NOT NULL DEFAULT '',
entry_id TEXT REFERENCES journal_entries(id),
weight REAL NOT NULL DEFAULT 1,
occurred_at TEXT,
context_hint TEXT NOT NULL DEFAULT '',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS writing_profile_facets (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
facet_key TEXT NOT NULL,
layer TEXT NOT NULL DEFAULT 'context' CHECK (layer IN ('core', 'context', 'output')),
value TEXT NOT NULL DEFAULT '',
evidence TEXT NOT NULL DEFAULT '',
origin TEXT NOT NULL DEFAULT 'manual' CHECK (origin IN ('manual', 'imported', 'accepted_suggestion', 'initial_build')),
locked INTEGER NOT NULL DEFAULT 0,
updated TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (profile_id, facet_key)
);
CREATE TABLE IF NOT EXISTS writing_profile_traits (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
facet_key TEXT NOT NULL,
slug TEXT NOT NULL,
label TEXT NOT NULL DEFAULT '',
statement TEXT NOT NULL DEFAULT '',
origin TEXT NOT NULL DEFAULT 'manual' CHECK (origin IN ('manual', 'imported', 'accepted_suggestion', 'initial_build')),
locked INTEGER NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'merged', 'split', 'retired')),
observed_from TEXT,
observed_to TEXT,
updated TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (profile_id, slug)
);
CREATE TABLE IF NOT EXISTS writing_profile_trait_refs (
id TEXT PRIMARY KEY,
trait_id TEXT NOT NULL REFERENCES writing_profile_traits(id) ON DELETE CASCADE,
source_id TEXT,
role TEXT NOT NULL CHECK (role IN ('evidence', 'exemplar')),
excerpt TEXT NOT NULL DEFAULT '',
occurred_at TEXT,
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS writing_profile_suggestions (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
facet_key TEXT NOT NULL DEFAULT '',
trait_slug TEXT NOT NULL DEFAULT '',
action TEXT NOT NULL DEFAULT 'update',
proposed_value TEXT NOT NULL DEFAULT '',
evidence TEXT NOT NULL DEFAULT '',
payload_json TEXT NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected')),
created TEXT NOT NULL DEFAULT (datetime('now')),
resolved TEXT
);
CREATE TABLE IF NOT EXISTS interaction_profiles (
profile_id TEXT PRIMARY KEY REFERENCES profiles(id) ON DELETE CASCADE,
governance TEXT NOT NULL DEFAULT 'advising' CHECK (governance IN ('learning', 'advising', 'frozen')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS interaction_preferences (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
scope TEXT NOT NULL DEFAULT 'global',
pref_key TEXT NOT NULL,
value TEXT NOT NULL DEFAULT '',
evidence TEXT NOT NULL DEFAULT '',
origin TEXT NOT NULL DEFAULT 'manual' CHECK (origin IN ('explicit', 'manual', 'accepted_suggestion')),
locked INTEGER NOT NULL DEFAULT 0,
updated TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (profile_id, scope, pref_key)
);
CREATE TABLE IF NOT EXISTS interaction_suggestions (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
scope TEXT NOT NULL DEFAULT 'global',
pref_key TEXT NOT NULL,
proposed_value TEXT NOT NULL DEFAULT '',
evidence TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected')),
created TEXT NOT NULL DEFAULT (datetime('now')),
resolved TEXT
);
CREATE TABLE IF NOT EXISTS writing_profile_evidence (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
trigger TEXT NOT NULL CHECK (trigger IN (
'user_edit_of_draft', 'heuristic_drift', 'dialogue_sample', 'periodic_batch', 'explicit_review'
)),
source_kind TEXT NOT NULL DEFAULT '',
source_id TEXT,
excerpt TEXT NOT NULL DEFAULT '',
local_signals_json TEXT NOT NULL DEFAULT '{}',
example_for_json TEXT NOT NULL DEFAULT '[]',
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'bundled', 'consumed', 'dismissed')),
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS writing_profile_reviews (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
target TEXT NOT NULL DEFAULT 'writing' CHECK (target IN ('writing', 'interaction')),
channel TEXT NOT NULL CHECK (channel IN ('api', 'paste')),
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'proposed', 'applied', 'dismissed')),
package_json TEXT NOT NULL DEFAULT '{}',
result_json TEXT,
created TEXT NOT NULL DEFAULT (datetime('now')),
resolved TEXT
);
CREATE TABLE IF NOT EXISTS writing_profile_versions (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
seq INTEGER NOT NULL,
governance TEXT NOT NULL DEFAULT '',
lifecycle TEXT NOT NULL DEFAULT '',
facets_json TEXT NOT NULL DEFAULT '[]',
traits_json TEXT NOT NULL DEFAULT '[]',
compiled_brief TEXT NOT NULL DEFAULT '',
cause TEXT NOT NULL DEFAULT '',
created TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (profile_id, seq)
);
CREATE TABLE IF NOT EXISTS llm_profiles (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL DEFAULT '',
model TEXT NOT NULL DEFAULT '',
zdr INTEGER NOT NULL DEFAULT 1,
no_train INTEGER NOT NULL DEFAULT 1,
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS provider_settings (
role TEXT PRIMARY KEY CHECK (role IN ('generate', 'detect')),
name TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL DEFAULT '',
model TEXT NOT NULL DEFAULT '',
zdr INTEGER NOT NULL DEFAULT 1,
no_train INTEGER NOT NULL DEFAULT 1,
profile_id TEXT,
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS journal_generation_selection (
profile_id TEXT PRIMARY KEY REFERENCES profiles(id) ON DELETE CASCADE,
transformation_id TEXT NOT NULL,
detail_id TEXT NOT NULL,
voice_id TEXT NOT NULL,
narrative_id TEXT NOT NULL,
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS generation_guidelines (
id TEXT PRIMARY KEY,
purpose TEXT NOT NULL,
slot TEXT NOT NULL,
guideline_key TEXT NOT NULL,
label TEXT NOT NULL,
summary TEXT NOT NULL DEFAULT '',
instruction TEXT NOT NULL,
style_context_json TEXT NOT NULL DEFAULT '{}',
sort_order INTEGER NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('draft', 'active', 'archived')),
revision INTEGER NOT NULL DEFAULT 1,
cloned_from TEXT,
is_default INTEGER NOT NULL DEFAULT 0,
is_system_seed INTEGER NOT NULL DEFAULT 0,
seed_id TEXT NOT NULL DEFAULT '',
seed_revision TEXT NOT NULL DEFAULT '',
used_at TEXT,
created TEXT NOT NULL DEFAULT (datetime('now')),
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS app_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL DEFAULT '',
updated TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS debug_runs (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
purpose TEXT NOT NULL,
layer TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'ok',
subject_type TEXT NOT NULL DEFAULT '',
subject_id TEXT NOT NULL DEFAULT '',
conversation_id TEXT,
message_id TEXT,
space_id TEXT,
journal_day_id TEXT,
space_title TEXT NOT NULL DEFAULT '',
calendar_date TEXT NOT NULL DEFAULT '',
conversation_title TEXT NOT NULL DEFAULT '',
payload_json TEXT NOT NULL DEFAULT '{}',
created TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_debug_runs_profile_created
ON debug_runs (profile_id, created DESC);
CREATE INDEX IF NOT EXISTS idx_debug_runs_conversation
ON debug_runs (profile_id, conversation_id, created);