first commit

This commit is contained in:
Blake Ridgway
2026-03-27 23:18:17 -05:00
commit d8cb1d277f
19 changed files with 2557 additions and 0 deletions

88
internal/db/db.go Normal file
View File

@@ -0,0 +1,88 @@
package db
import (
"database/sql"
"fmt"
"log/slog"
_ "modernc.org/sqlite"
)
// Open opens (or creates) the SQLite database and runs schema migrations.
func Open(path string) (*sql.DB, error) {
db, err := sql.Open("sqlite", path+"?_journal_mode=WAL&_foreign_keys=on")
if err != nil {
return nil, fmt.Errorf("open db: %w", err)
}
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("ping db: %w", err)
}
if err := runSchema(db); err != nil {
return nil, fmt.Errorf("schema: %w", err)
}
slog.Info("database ready", "path", path)
return db, nil
}
func runSchema(db *sql.DB) error {
stmts := []string{
`CREATE TABLE IF NOT EXISTS customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
first_name TEXT NOT NULL DEFAULT '',
last_name TEXT NOT NULL DEFAULT '',
stripe_customer_id TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
)`,
`CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
)`,
`CREATE TABLE IF NOT EXISTS subscriptions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
stripe_subscription_id TEXT NOT NULL UNIQUE,
stripe_price_id TEXT NOT NULL DEFAULT '',
plan_name TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'active',
current_period_end TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
)`,
`CREATE TABLE IF NOT EXISTS invoices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
stripe_invoice_id TEXT NOT NULL UNIQUE,
amount_cents INTEGER NOT NULL DEFAULT 0,
currency TEXT NOT NULL DEFAULT 'usd',
status TEXT NOT NULL DEFAULT 'open',
invoice_pdf_url TEXT NOT NULL DEFAULT '',
period_start TEXT NOT NULL DEFAULT '',
period_end TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
)`,
`CREATE TABLE IF NOT EXISTS password_resets (
token TEXT PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
expires_at TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0
)`,
}
for _, s := range stmts {
if _, err := db.Exec(s); err != nil {
return fmt.Errorf("exec schema: %w", err)
}
}
return nil
}