summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorivar <i@oiee.no>2026-04-23 22:54:31 +0200
committerivar <i@oiee.no>2026-04-23 22:54:31 +0200
commit4817e77682fb05288496a6e2db6b1e1c9260aba9 (patch)
treee001e1d1ef15cc2e7f3380992f150112686dcf53 /docs
parent7f40b470a7d42a7674cc74309b210a968291ca23 (diff)
downloadiblog-4817e77682fb05288496a6e2db6b1e1c9260aba9.tar.xz
iblog-4817e77682fb05288496a6e2db6b1e1c9260aba9.zip
Redirect back to post on create/editHEADmaster
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/plans/2026-04-07-sql-migrations.md231
-rw-r--r--docs/superpowers/specs/2026-04-07-sql-migrations-design.md66
2 files changed, 0 insertions, 297 deletions
diff --git a/docs/superpowers/plans/2026-04-07-sql-migrations.md b/docs/superpowers/plans/2026-04-07-sql-migrations.md
deleted file mode 100644
index 60b2848..0000000
--- a/docs/superpowers/plans/2026-04-07-sql-migrations.md
+++ /dev/null
@@ -1,231 +0,0 @@
-# SQL Migrations Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Replace the inline `CREATE TABLE IF NOT EXISTS` block in `internal/db/db.go` with versioned SQL files managed by `golang-migrate/migrate`, applied automatically at startup.
-
-**Architecture:** Migration files live in `internal/db/migrations/` and are embedded into the binary via `embed.FS`. `db.Open` calls `migrate.Up()` after opening the database, ensuring the schema is always current before any caller uses `*DB`. golang-migrate tracks applied versions in a `schema_migrations` table it manages automatically.
-
-**Tech Stack:** `github.com/golang-migrate/migrate/v4`, `database/sqlite` (modernc.org/sqlite adapter), `source/iofs` (embed.FS source)
-
----
-
-## File Map
-
-| File | Action | Purpose |
-|---|---|---|
-| `internal/db/migrations/000001_init.up.sql` | Create | Full current schema |
-| `internal/db/migrations/000001_init.down.sql` | Create | Drop all tables in reverse order |
-| `internal/db/db.go` | Modify | Add `//go:embed`, wire up migrate, remove inline `Exec` block |
-| `go.mod` / `go.sum` | Modify | Add golang-migrate packages |
-
----
-
-### Task 1: Add golang-migrate dependency
-
-**Files:**
-- Modify: `go.mod`, `go.sum`
-
-- [ ] **Step 1: Fetch the packages**
-
-```bash
-go get github.com/golang-migrate/migrate/v4
-go get github.com/golang-migrate/migrate/v4/database/sqlite
-go get github.com/golang-migrate/migrate/v4/source/iofs
-```
-
-- [ ] **Step 2: Verify**
-
-```bash
-go list -m github.com/golang-migrate/migrate/v4
-```
-
-Expected output: `github.com/golang-migrate/migrate/v4 v4.x.x`
-
-- [ ] **Step 3: Commit**
-
-```bash
-git add go.mod go.sum
-git commit -m "chore: add golang-migrate dependency"
-```
-
----
-
-### Task 2: Create migration SQL files
-
-**Files:**
-- Create: `internal/db/migrations/000001_init.up.sql`
-- Create: `internal/db/migrations/000001_init.down.sql`
-
-- [ ] **Step 1: Create the up migration**
-
-`internal/db/migrations/000001_init.up.sql`:
-
-```sql
-CREATE TABLE pages (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- path TEXT NOT NULL UNIQUE,
- html_path TEXT NOT NULL,
- title TEXT NOT NULL DEFAULT '',
- date TEXT DEFAULT '',
- tags TEXT DEFAULT '[]',
- updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
-);
-CREATE INDEX idx_pages_path ON pages(path);
-CREATE INDEX idx_pages_date ON pages(date);
-
-CREATE TABLE posts (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- slug TEXT NOT NULL UNIQUE,
- title TEXT NOT NULL DEFAULT '',
- date TEXT DEFAULT '',
- tags TEXT DEFAULT '[]',
- draft INTEGER NOT NULL DEFAULT 0,
- blocks TEXT NOT NULL DEFAULT '[]',
- updated_at INTEGER NOT NULL DEFAULT (cast(strftime('%s','now') * 1000000 as integer))
-);
-CREATE INDEX idx_posts_slug ON posts(slug);
-CREATE INDEX idx_posts_date ON posts(date);
-
-CREATE TABLE redirects (
- from_slug TEXT PRIMARY KEY,
- to_slug TEXT NOT NULL
-);
-
-CREATE TABLE settings (
- key TEXT PRIMARY KEY,
- value TEXT NOT NULL DEFAULT ''
-);
-
-CREATE VIRTUAL TABLE pages_fts USING fts5(
- path UNINDEXED,
- title,
- content,
- tokenize = 'porter unicode61'
-);
-```
-
-Note: `IF NOT EXISTS` is intentionally absent — golang-migrate guarantees each migration runs exactly once.
-
-- [ ] **Step 2: Create the down migration**
-
-`internal/db/migrations/000001_init.down.sql`:
-
-```sql
-DROP TABLE IF EXISTS pages_fts;
-DROP TABLE IF EXISTS settings;
-DROP TABLE IF EXISTS redirects;
-DROP TABLE IF EXISTS posts;
-DROP TABLE IF EXISTS pages;
-```
-
-- [ ] **Step 3: Commit**
-
-```bash
-git add internal/db/migrations/
-git commit -m "feat: add initial schema migration files"
-```
-
----
-
-### Task 3: Wire golang-migrate into db.Open
-
-**Files:**
-- Modify: `internal/db/db.go`
-
-- [ ] **Step 1: Run existing tests to confirm baseline**
-
-```bash
-go test ./internal/db/... -v
-```
-
-Expected: all tests pass.
-
-- [ ] **Step 2: Replace db.go**
-
-Full new content of `internal/db/db.go`:
-
-```go
-package db
-
-import (
- "database/sql"
- "embed"
-
- "github.com/golang-migrate/migrate/v4"
- sqlitedriver "github.com/golang-migrate/migrate/v4/database/sqlite"
- "github.com/golang-migrate/migrate/v4/source/iofs"
- _ "modernc.org/sqlite"
-)
-
-//go:embed migrations
-var migrationsFS embed.FS
-
-type DB struct {
- db *sql.DB
-}
-
-func Open(path string) (*DB, error) {
- sqldb, err := sql.Open("sqlite", path)
- if err != nil {
- return nil, err
- }
- // SQLite works best with a single writer; also ensures in-memory DBs
- // (used in tests) share one connection across the migrate driver and
- // all application queries.
- sqldb.SetMaxOpenConns(1)
-
- if err := runMigrations(sqldb); err != nil {
- sqldb.Close()
- return nil, err
- }
- return &DB{db: sqldb}, nil
-}
-
-func runMigrations(sqldb *sql.DB) error {
- src, err := iofs.New(migrationsFS, "migrations")
- if err != nil {
- return err
- }
- driver, err := sqlitedriver.WithInstance(sqldb, &sqlitedriver.Config{})
- if err != nil {
- return err
- }
- m, err := migrate.NewWithInstance("iofs", src, "sqlite", driver)
- if err != nil {
- return err
- }
- if err := m.Up(); err != nil && err != migrate.ErrNoChange {
- return err
- }
- return nil
-}
-
-func (d *DB) Close() error { return d.db.Close() }
-
-// RawDB returns the underlying *sql.DB for advanced queries.
-func (d *DB) RawDB() *sql.DB { return d.db }
-```
-
-- [ ] **Step 3: Run tests**
-
-```bash
-go test ./internal/db/... -v
-```
-
-Expected: all tests pass (the `openTestDB` helper uses `:memory:`, `SetMaxOpenConns(1)` ensures the migrate driver and app queries share the same connection).
-
-- [ ] **Step 4: Build to confirm no compile errors**
-
-```bash
-go build ./cmd/iblog
-```
-
-Expected: exits with code 0, no output.
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add internal/db/db.go
-git commit -m "feat: wire golang-migrate into db.Open, remove inline schema"
-```
diff --git a/docs/superpowers/specs/2026-04-07-sql-migrations-design.md b/docs/superpowers/specs/2026-04-07-sql-migrations-design.md
deleted file mode 100644
index 8ce8622..0000000
--- a/docs/superpowers/specs/2026-04-07-sql-migrations-design.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# SQL Migrations Design
-
-**Date:** 2026-04-07
-**Status:** Approved
-
-## Goal
-
-Replace the inline `CREATE TABLE IF NOT EXISTS` block in `internal/db/db.go` with versioned SQL migration files managed by `golang-migrate/migrate`.
-
-## Constraints
-
-- Migrations run automatically at startup (inside `db.Open`) — no CLI subcommand needed.
-- Migration files are embedded into the binary via `embed.FS`.
-- Continue using the existing `modernc.org/sqlite` driver.
-- Existing databases can be discarded (clean start acceptable).
-
-## Migration Files
-
-New directory `internal/db/migrations/` holds numbered SQL files:
-
-```
-internal/db/migrations/
- 000001_init.up.sql — full current schema (tables, indexes, FTS5 virtual table)
- 000001_init.down.sql — DROP TABLE / DROP INDEX statements in reverse order
-```
-
-Future schema changes each get their own numbered pair. golang-migrate applies them in order and records applied versions in a `schema_migrations` table it manages automatically.
-
-## Embedding
-
-An `//go:embed migrations` directive in `internal/db/db.go` (package `db`) exposes the directory as an `embed.FS` variable `migrationsFS`.
-
-## Changes to `db.Open`
-
-After `sql.Open`, the existing inline `Exec` block is removed and replaced with:
-
-```go
-src, err := iofs.New(migrationsFS, "migrations")
-// handle err
-driver, err := sqlitedriver.WithInstance(sqldb, &sqlitedriver.Config{})
-// handle err
-m, err := migrate.NewWithInstance("iofs", src, "sqlite", driver)
-// handle err
-if err := m.Up(); err != nil && err != migrate.ErrNoChange {
- return nil, err
-}
-```
-
-`ErrNoChange` is silently ignored (DB is already at latest version).
-
-## New Dependencies
-
-| Package | Purpose |
-|---|---|
-| `github.com/golang-migrate/migrate/v4` | Core migration engine |
-| `github.com/golang-migrate/migrate/v4/database/sqlite` | modernc.org/sqlite driver adapter |
-| `github.com/golang-migrate/migrate/v4/source/iofs` | `embed.FS` migration source |
-
-## File Changes
-
-| File | Change |
-|---|---|
-| `internal/db/db.go` | Add `//go:embed migrations`, replace inline Exec with migrate wiring |
-| `internal/db/migrations/000001_init.up.sql` | New — current schema |
-| `internal/db/migrations/000001_init.down.sql` | New — reverse of init |
-| `go.mod` / `go.sum` | Add three golang-migrate packages |