fix(db): add AUTOINCREMENT to prevent SQLite ROWID reuse

Without AUTOINCREMENT, SQLite can reassign the highest deleted ROWID to
a new row. This is a data integrity bug: a deleted entity's ID could be
assigned to a completely different entity, breaking bookmarks, API
caches, and URL stability.
This commit is contained in:
Jon Seager 2026-02-06 10:09:13 +00:00
parent d9d87ef849
commit 97c46d034b
No known key found for this signature in database
4 changed files with 14 additions and 14 deletions

View file

@ -1,14 +1,14 @@
-- Authentication and authorisation tables
CREATE TABLE users (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
uuid TEXT,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
CREATE TABLE tokens (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
@ -20,7 +20,7 @@ CREATE INDEX idx_tokens_user_id ON tokens(user_id);
CREATE INDEX idx_tokens_token_hash ON tokens(token_hash);
CREATE TABLE sessions (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
session_token_hash TEXT NOT NULL,
created_at TEXT NOT NULL,
@ -31,7 +31,7 @@ CREATE INDEX idx_sessions_user_id ON sessions(user_id);
CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
CREATE TABLE passkey_credentials (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
credential_json TEXT NOT NULL,
name TEXT NOT NULL DEFAULT 'default',
@ -41,7 +41,7 @@ CREATE TABLE passkey_credentials (
CREATE INDEX idx_passkey_credentials_user_id ON passkey_credentials(user_id);
CREATE TABLE registration_tokens (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
token_hash TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
expires_at TEXT NOT NULL,

View file

@ -1,7 +1,7 @@
-- Coffee supply chain and equipment tables
CREATE TABLE roasters (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
country TEXT NOT NULL,
city TEXT,
@ -12,7 +12,7 @@ CREATE TABLE roasters (
CREATE UNIQUE INDEX idx_roasters_slug ON roasters(slug);
CREATE TABLE roasts (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
roaster_id INTEGER NOT NULL REFERENCES roasters(id) ON DELETE CASCADE,
name TEXT NOT NULL,
origin TEXT,
@ -27,7 +27,7 @@ CREATE INDEX idx_roasts_roaster_id ON roasts(roaster_id);
CREATE UNIQUE INDEX idx_roasts_roaster_slug ON roasts(roaster_id, slug);
CREATE TABLE bags (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
roast_id INTEGER NOT NULL REFERENCES roasts(id) ON DELETE CASCADE,
roast_date TEXT,
amount REAL NOT NULL,
@ -41,7 +41,7 @@ CREATE INDEX idx_bags_roast_id ON bags(roast_id);
CREATE INDEX idx_bags_closed ON bags(closed);
CREATE TABLE gear (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
category TEXT NOT NULL CHECK (category IN ('grinder', 'brewer', 'filter_paper')),
make TEXT NOT NULL,
model TEXT NOT NULL,

View file

@ -1,7 +1,7 @@
-- Brew, cafe, and cup tables
CREATE TABLE brews (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
bag_id INTEGER NOT NULL REFERENCES bags(id) ON DELETE CASCADE,
coffee_weight REAL NOT NULL,
grinder_id INTEGER NOT NULL REFERENCES gear(id) ON DELETE RESTRICT,
@ -18,7 +18,7 @@ CREATE INDEX idx_brews_bag_id ON brews(bag_id);
CREATE INDEX idx_brews_created_at ON brews(created_at DESC);
CREATE TABLE cafes (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
slug TEXT NOT NULL,
city TEXT NOT NULL,
@ -32,7 +32,7 @@ CREATE TABLE cafes (
CREATE UNIQUE INDEX idx_cafes_slug ON cafes(slug);
CREATE TABLE cups (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
roast_id INTEGER NOT NULL REFERENCES roasts(id) ON DELETE RESTRICT,
cafe_id INTEGER NOT NULL REFERENCES cafes(id) ON DELETE RESTRICT,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),

View file

@ -1,7 +1,7 @@
-- Timeline events and AI usage tracking
CREATE TABLE timeline_events (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
entity_type TEXT NOT NULL CHECK (entity_type IN ('roaster', 'roast', 'bag', 'gear', 'brew', 'cafe', 'cup')),
entity_id INTEGER NOT NULL,
action TEXT NOT NULL,
@ -17,7 +17,7 @@ CREATE INDEX idx_timeline_events_entity ON timeline_events(entity_type, entity_i
CREATE INDEX idx_timeline_events_occurred_at ON timeline_events(occurred_at DESC);
CREATE TABLE ai_usage (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
model TEXT NOT NULL,
endpoint TEXT NOT NULL,