fix: all 5 high-severity bugs from codex review

- use sqlx migrate!() instead of broken split(';') — triggers now work
- seq via AUTOINCREMENT — no race conditions, monotonic ordering
- replace ?since= with ?after_seq= — cursor-based, no timestamp format issues
- replace all unwrap() with typed errors (404, 409, 400, 500)
- reply_to same-channel enforced in route handler
- add biome for frontend linting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 19:07:12 +02:00
parent e940afde52
commit b48232ca03
17 changed files with 331 additions and 88 deletions

View File

@@ -24,9 +24,11 @@ CREATE TABLE IF NOT EXISTS channels (
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
);
-- seq is INTEGER PRIMARY KEY AUTOINCREMENT = global monotonic, no race conditions
-- id is a separate UUID with a unique index
CREATE TABLE IF NOT EXISTS messages (
id TEXT PRIMARY KEY NOT NULL,
seq INTEGER NOT NULL,
seq INTEGER PRIMARY KEY AUTOINCREMENT,
id TEXT UNIQUE NOT NULL,
channel_id TEXT NOT NULL REFERENCES channels(id),
user_id TEXT NOT NULL REFERENCES users(id),
type TEXT NOT NULL CHECK (type IN ('text', 'code', 'result', 'error', 'plan')),
@@ -36,40 +38,18 @@ CREATE TABLE IF NOT EXISTS messages (
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
updated_at TEXT,
deleted_at TEXT
-- reply_to same-channel constraint enforced in application layer (routes.rs)
);
CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages(channel_id, seq);
CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(channel_id, created_at);
CREATE INDEX IF NOT EXISTS idx_messages_channel_seq ON messages(channel_id, seq);
-- Auto-increment seq per channel using a trigger
CREATE TABLE IF NOT EXISTS channel_seq (
channel_id TEXT PRIMARY KEY NOT NULL REFERENCES channels(id),
next_seq INTEGER NOT NULL DEFAULT 1
);
CREATE TRIGGER IF NOT EXISTS trg_message_seq
AFTER INSERT ON messages
BEGIN
INSERT INTO channel_seq (channel_id, next_seq) VALUES (NEW.channel_id, 2)
ON CONFLICT(channel_id) DO UPDATE SET next_seq = next_seq + 1;
END;
-- Enforce reply_to same-channel constraint
CREATE TRIGGER IF NOT EXISTS trg_reply_same_channel
BEFORE INSERT ON messages
WHEN NEW.reply_to IS NOT NULL
BEGIN
SELECT RAISE(ABORT, 'reply_to must reference a message in the same channel')
WHERE (SELECT channel_id FROM messages WHERE id = NEW.reply_to) != NEW.channel_id;
END;
-- Seed user for development (no auth yet)
-- Seed users
INSERT OR IGNORE INTO users (id, username, display_name, role)
VALUES ('00000000-0000-0000-0000-000000000001', 'benji', 'Benji', 'ape');
INSERT OR IGNORE INTO users (id, username, display_name, role)
VALUES ('00000000-0000-0000-0000-000000000002', 'neeraj', 'Neeraj', 'ape');
-- Seed a general channel
-- Seed general channel
INSERT OR IGNORE INTO channels (id, name, description, created_by)
VALUES ('00000000-0000-0000-0000-000000000010', 'general', 'General discussion', '00000000-0000-0000-0000-000000000001');