- schema.sql: all user_id FKs now ON DELETE SET NULL (was RESTRICT)
- migrate_user_fk_set_null.py: drop+readd constraints on existing DBs
- entrypoint.sh: runs migration automatically on startup (non-fatal)
- db.py: rollback moved before FK check (cleanup)
Deleting a user now nullifies their references in audit_log,
project_context, context_files, change_requests, reviews instead of
blocking with a 409.
PostgreSQL enters 'current transaction is aborted' state after a
ForeignKeyViolation. Without rollback(), every subsequent query on the
shared connection fails with 'commands ignored until end of transaction
block'. Now both db.py and server.py rollback on the error path.
- New actions column (right of state) with inline buttons per row
- Manage form keeps save user + clear only (no duplicate action buttons)
- Themed to match admin dialog: JetBrains Mono, uppercase, square borders
- Delete uses danger styling
- OAuth read+write on /mcp; API key on /mcp still full internal tools (LAN)
- /readonly/mcp and /oauth/mcp remain OAuth aliases
- OAuth metadata and connector_url point to /mcp
- README + Traefik template: route Host without blocking /mcp
- Route public write at GET /write/sse and POST /write/messages (ctxd.write)
- Always require write token on /write/messages (was optional)
- Remove debug tracing; document SSE write surface in SKILL.md
- Add scripts/test_write_mcp.py for local OAuth write smoke test
Migration script now resets SERIAL sequences (audit_log, context_files, etc.)
to max(existing_id) after copying rows. Without this, the sequence is still at
its post-schema-creation value and every INSERT hits a duplicate key error.
- entrypoint.sh: use NEEDS_INIT variable instead of exit codes (set -e was killing the script)
- __main__.py: skip db_path.exists() check when using PostgreSQL
- cli.py: use dual-backend placeholders for _seed_context (was using SQLite ? syntax)
- cli.py: use 'admin' instead of 'system' for seed updated_by (FK constraint)