-- SlabUploader SQLite schema (S0) -- Every table/column from docs/contracts/DATA-MODEL.md using CREATE TABLE IF NOT EXISTS -- Taxonomy tables exist but remain EMPTY (S4 populates). Stdlib sqlite3 only. -- Pragmas applied by db factory: journal_mode=WAL, foreign_keys=ON, busy_timeout=5000, synchronous=NORMAL PRAGMA foreign_keys = ON; -- 2. slabs CREATE TABLE IF NOT EXISTS slabs ( id TEXT PRIMARY KEY, status TEXT NOT NULL DEFAULT 'draft' CHECK(status IN ('draft','calibrated','ready','publishing','published','failed')), sku TEXT UNIQUE CHECK(length(sku) BETWEEN 3 AND 24), length_in REAL, thickness_in REAL, sqft REAL, bdft REAL, width_min_in REAL, width_max_in REAL, width_avg_in REAL, species_id INTEGER, wood_category_ids TEXT, -- JSON array of leaf ids edge_type_term_id INTEGER, figure_term_ids TEXT, -- JSON array grade_term_id INTEGER, thickness_term_id INTEGER, moisture_term_id INTEGER, fig_tag_ids TEXT, -- JSON array optional feat_tag_ids TEXT, -- JSON array optional price REAL, price_source TEXT CHECK(price_source IN ('recommendation','override') OR price_source IS NULL), title TEXT, short_description TEXT, description TEXT, content_source TEXT CHECK(content_source IN ('manual','llm','template') OR content_source IS NULL), species_confidence REAL, figure_confidence REAL, grade_confidence REAL, inference_status TEXT CHECK(inference_status IN ('inferring','done','failed') OR inference_status IS NULL), calibration_photo_id TEXT, client_rev INTEGER NOT NULL DEFAULT 1, server_rev INTEGER NOT NULL DEFAULT 1, woo_product_id INTEGER, published_at TEXT, deleted_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (species_id) REFERENCES woo_categories(id), FOREIGN KEY (calibration_photo_id) REFERENCES slab_photos(id) ); -- 3. slab_photos CREATE TABLE IF NOT EXISTS slab_photos ( id TEXT PRIMARY KEY, slab_id TEXT NOT NULL, seq INTEGER NOT NULL, is_calibration INTEGER NOT NULL DEFAULT 0 CHECK(is_calibration IN (0,1)), original_blob BLOB, processed_blob BLOB, width_px INTEGER, height_px INTEGER, created_at TEXT NOT NULL, FOREIGN KEY (slab_id) REFERENCES slabs(id) ON DELETE CASCADE ); -- 4. pricing_rules CREATE TABLE IF NOT EXISTS pricing_rules ( id INTEGER PRIMARY KEY, species_id INTEGER NOT NULL UNIQUE, price_per_bdft REAL NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (species_id) REFERENCES woo_categories(id) ); -- 5. Taxonomy cache (empty at S0; columns chosen to support FKs + S4 sync; ambiguity resolved in learnings) CREATE TABLE IF NOT EXISTS woo_categories ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, parent_id INTEGER, woo_id INTEGER ); CREATE TABLE IF NOT EXISTS woo_attributes ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, woo_id INTEGER ); CREATE TABLE IF NOT EXISTS woo_attribute_terms ( id INTEGER PRIMARY KEY, attribute_id INTEGER NOT NULL, name TEXT NOT NULL, slug TEXT NOT NULL, woo_id INTEGER, FOREIGN KEY (attribute_id) REFERENCES woo_attributes(id) ); CREATE TABLE IF NOT EXISTS woo_tags ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, woo_id INTEGER ); -- 6. settings (key/value/value_enc per ยง6; secrets in value_enc = nonce||ciphertext) CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT, value_enc TEXT ); -- 7. prompts + prompt_revisions (append-only revisions) CREATE TABLE IF NOT EXISTS prompts ( id INTEGER PRIMARY KEY, name TEXT NOT NULL CHECK(name IN ('call1','call2')), active_revision_id INTEGER, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (active_revision_id) REFERENCES prompt_revisions(id) ); CREATE TABLE IF NOT EXISTS prompt_revisions ( id INTEGER PRIMARY KEY, prompt_id INTEGER NOT NULL, content TEXT NOT NULL, content_hash TEXT NOT NULL, created_at TEXT NOT NULL, created_by TEXT, FOREIGN KEY (prompt_id) REFERENCES prompts(id) ); -- 8. sync_log (append-only) CREATE TABLE IF NOT EXISTS sync_log ( id INTEGER PRIMARY KEY, slab_id TEXT, woo_product_id INTEGER, status TEXT NOT NULL CHECK(status IN ('success','failed')), payload_hash TEXT, message TEXT, created_at TEXT NOT NULL ); -- 9. inference_log (append-only audit) CREATE TABLE IF NOT EXISTS inference_log ( id INTEGER PRIMARY KEY, slab_id TEXT, call INTEGER NOT NULL CHECK(call IN (1,2)), prompt_revision_id INTEGER, model TEXT, request_payload TEXT, response_payload TEXT, latency_ms INTEGER, created_at TEXT NOT NULL, FOREIGN KEY (prompt_revision_id) REFERENCES prompt_revisions(id) );