// Package storage provides the SQLite-backed persistence layer for // multi-tenant user state. It owns the database connection, migrations, // and CRUD repositories. package storage import ( "database/sql" "fmt" _ "modernc.org/sqlite" ) // Open opens (or creates) the SQLite database at path, configures WAL // mode and pragmas suitable for concurrent reads, and applies migrations. func Open(path string) (*sql.DB, error) { dsn := fmt.Sprintf("file:%s?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)", path) db, err := sql.Open("sqlite", dsn) if err != nil { return nil, fmt.Errorf("open sqlite: %w", err) } if err := db.Ping(); err != nil { _ = db.Close() return nil, fmt.Errorf("ping sqlite: %w", err) } if err := migrate(db); err != nil { _ = db.Close() return nil, fmt.Errorf("migrate: %w", err) } return db, nil } func migrate(db *sql.DB) error { for _, stmt := range migrations { if _, err := db.Exec(stmt); err != nil { return fmt.Errorf("exec migration: %w\nstmt: %s", err, stmt) } } return nil } var migrations = []string{ `CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE, created_at INTEGER NOT NULL, last_login_at INTEGER, storage_path TEXT NOT NULL )`, `CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)`, }