Changeset 0.23.1 (#154)

This commit is contained in:
2026-03-06 13:26:25 +00:00
parent 2fc620e1ac
commit 4c6555cb06
38 changed files with 1536 additions and 4031 deletions

View File

@@ -17,6 +17,14 @@ import (
// DB is the application-wide database connection pool.
var DB *sql.DB
// rawDSN holds the Postgres connection string for LISTEN/NOTIFY consumers.
// Empty when running SQLite.
var rawDSN string
// DSN returns the raw Postgres connection string, or "" for SQLite.
// Used by the event broadcast layer to open a dedicated listener connection.
func DSN() string { return rawDSN }
// Connect opens a connection pool to the configured database.
// Driver is selected by DB_DRIVER env var: "postgres" (default) or "sqlite".
// For SQLite the DATABASE_URL is treated as a file path; ":memory:" is supported.
@@ -45,6 +53,7 @@ func connectPostgres(dsn string) error {
// Log the database name for operational clarity (never log credentials).
dbName = extractDBName(dsn)
rawDSN = dsn
log.Printf("Connecting to Postgres database %q ...", dbName)
var err error

View File

@@ -0,0 +1,46 @@
-- ==========================================
-- Chat Switchboard — 006 Multi-User: DMs + Channels
-- ==========================================
-- Extends channels with 'dm' and 'channel' types, ai_mode, and topic.
-- Adds presence tracking table.
-- ICD §3 (Channels & Conversations) — v0.23.1
-- ==========================================
-- ── Channel type extension ───────────────────────────────────────────
-- Add 'dm' (human-to-human, AI silent unless @mentioned)
-- Add 'channel' (named persistent space, configurable ai_mode)
-- Existing 'direct', 'group', 'workflow' are unchanged.
ALTER TABLE channels DROP CONSTRAINT IF EXISTS channels_type_check;
ALTER TABLE channels ADD CONSTRAINT channels_type_check
CHECK (type IN ('direct', 'dm', 'group', 'channel', 'workflow'));
-- ── ai_mode ──────────────────────────────────────────────────────────
-- auto : AI responds to every message (existing behavior for 'direct')
-- mention_only : AI silent unless @mentioned (default for 'dm')
-- off : AI disabled entirely
ALTER TABLE channels
ADD COLUMN IF NOT EXISTS ai_mode VARCHAR(20) NOT NULL DEFAULT 'auto'
CHECK (ai_mode IN ('auto', 'mention_only', 'off'));
-- Back-fill: DM channels should be mention_only
-- (No existing rows should have type='dm' yet, but be safe)
UPDATE channels SET ai_mode = 'mention_only' WHERE type = 'dm' AND ai_mode = 'auto';
-- ── topic ─────────────────────────────────────────────────────────────
ALTER TABLE channels
ADD COLUMN IF NOT EXISTS topic TEXT;
-- ── Presence (in-memory heartbeat, DB stores last_seen for persistence) ──
-- Not queried at high frequency — updated by heartbeat (30s), read on load.
CREATE TABLE IF NOT EXISTS user_presence (
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
last_seen TIMESTAMPTZ NOT NULL DEFAULT NOW(),
status VARCHAR(20) NOT NULL DEFAULT 'online'
CHECK (status IN ('online', 'away', 'offline'))
);
CREATE INDEX IF NOT EXISTS idx_user_presence_last_seen ON user_presence(last_seen DESC);
COMMENT ON TABLE user_presence IS 'Heartbeat-driven presence. Rows upserted every 30s by active clients.';
COMMENT ON COLUMN channels.ai_mode IS 'auto=respond always, mention_only=@mention required, off=AI disabled';
COMMENT ON COLUMN channels.topic IS 'Short channel description shown in header';

View File

@@ -0,0 +1,23 @@
-- ==========================================
-- Chat Switchboard — 006 Multi-User: DMs + Channels (SQLite)
-- ==========================================
-- SQLite does not support ALTER CONSTRAINT or DROP CONSTRAINT.
-- The type check is enforced by application logic for SQLite.
-- ==========================================
-- ── ai_mode ──────────────────────────────────────────────────────────
-- SQLite ignores CHECK constraints on existing rows; we add the column
-- and rely on app-layer validation for the enum values.
ALTER TABLE channels ADD COLUMN ai_mode TEXT NOT NULL DEFAULT 'auto';
-- ── topic ─────────────────────────────────────────────────────────────
ALTER TABLE channels ADD COLUMN topic TEXT;
-- ── Presence ──────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS user_presence (
user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
last_seen DATETIME NOT NULL DEFAULT (datetime('now')),
status TEXT NOT NULL DEFAULT 'online'
);
CREATE INDEX IF NOT EXISTS idx_user_presence_last_seen ON user_presence(last_seen DESC);