# Phase 1: Project Scaffold & SQLite Store **Status:** ✅ Complete **Parent plan:** [PLAN.md](./PLAN.md) **Domain:** backend ## Objective Initialize the Go project, establish the directory structure, and implement the SQLite store with schema, migrations, and CRUD operations for all entities. ## Tasks - [x] Task 1: Initialize Go module (`go mod init`), create directory structure per PLAN.md - [x] Task 2: Add core dependencies to go.mod (sqlite, chi, yaml, uuid, cron) - [x] Task 3: Define SQLite schema — tables for projects, stages, registries, settings, instances, deploys, deploy_logs - [x] Task 4: Implement store initialization with auto-migration (create tables if not exist) - [x] Task 5: Implement projects CRUD (Create, GetByID, GetAll, Update, Delete) - [x] Task 6: Implement stages CRUD (Create, GetByProjectID, Update, Delete) - [x] Task 7: Implement registries CRUD (Create, GetByID, GetAll, Update, Delete) - [x] Task 8: Implement settings Get/Update (single-row config pattern) - [x] Task 9: Implement instances CRUD (Create, GetByStageID, GetByID, Update, Delete, UpdateStatus) - [x] Task 10: Implement deploys CRUD (Create, GetByProjectID, GetRecent, GetByID) + deploy_logs append - [x] Task 11: Create `cmd/server/main.go` entry point (minimal — just opens DB, defers close) ## Files to Modify/Create - `go.mod` — module definition and dependencies - `go.sum` — dependency checksums - `cmd/server/main.go` — entry point - `internal/store/store.go` — DB connection, schema, migrations - `internal/store/projects.go` — project queries - `internal/store/stages.go` — stage queries - `internal/store/registries.go` — registry queries - `internal/store/settings.go` — settings queries - `internal/store/instances.go` — instance queries - `internal/store/deploys.go` — deploy history queries ## Acceptance Criteria - `go mod tidy` succeeds - All store CRUD functions are implemented with proper error handling - Schema covers all entities from the architecture plan - Entry point compiles (may not fully run until later phases wire everything) ## Notes - Use `modernc.org/sqlite` for CGo-free SQLite - Use `go-chi/chi/v5` for routing (will be wired in Phase 8) - Settings table uses a single-row pattern (one row, upsert on update) - Instance status should be an enum-like string: "running", "stopped", "failed", "removing" - Deploy status: "pending", "pulling", "starting", "configuring_proxy", "health_checking", "success", "failed", "rolled_back" ## Review Checklist - [ ] All tasks completed - [ ] Code follows Go conventions (gofmt, proper error returns) - [ ] No unintended side effects - [ ] Schema is normalized and covers all planned entities - [ ] CRUD functions handle not-found cases properly ## Handoff to Next Phase ### What was built - Go module initialized at `github.com/alexei/docker-watcher` with all core dependencies - Full directory structure created: `cmd/server/`, `internal/store/`, plus empty dirs for config, docker, npm, registry, deployer, health, notify, webhook, api, crypto - SQLite store with 7 tables: projects, stages, registries, settings, instances, deploys, deploy_logs - Auto-migration runs on store initialization (CREATE TABLE IF NOT EXISTS) - WAL mode, foreign keys, and busy timeout pragmas enabled - Settings table uses single-row pattern with `INSERT OR IGNORE` seed - Models extracted to `internal/store/models.go` for clean separation ### Key files - `go.mod` — module definition with modernc.org/sqlite, chi, yaml, uuid, cron - `cmd/server/main.go` — entry point that creates data dir, opens store, defers close - `internal/store/store.go` — DB connection, pragmas, schema DDL, migration - `internal/store/models.go` — all entity structs (Project, Stage, Registry, Settings, Instance, Deploy, DeployLog) - `internal/store/projects.go` — full CRUD - `internal/store/stages.go` — full CRUD with bool-to-int conversion for SQLite - `internal/store/registries.go` — full CRUD - `internal/store/settings.go` — Get/Update (single-row upsert) - `internal/store/instances.go` — full CRUD + UpdateStatus - `internal/store/deploys.go` — Create, GetByID, GetByProjectID, GetRecent, UpdateDeployStatus, SetDeployInstanceID, AppendDeployLog, GetDeployLogs ### Conventions established - UUIDs generated via `github.com/google/uuid` on Create operations - Timestamps stored as `datetime('now')` defaults in schema, `time.Now().UTC().Format("2006-01-02 15:04:05")` in Go code - All query errors wrapped with `fmt.Errorf` and `%w` for unwrapping - Not-found cases return descriptive error strings (not sentinel errors yet — can be refined) - Boolean fields stored as INTEGER (0/1) in SQLite, converted via `boolToInt` helper - JSON-encoded maps stored as TEXT for env and volumes fields ### What Phase 2 needs to know - `store.New(dbPath)` returns a `*Store` that is ready to use — no additional init needed - The `settings` table is pre-seeded with a row (id=1) so `GetSettings` always works - Registry `token` and settings `npm_password` are stored as plain text — Phase 2 (Crypto) should add encryption/decryption around these fields - `go.sum` does not exist yet — run `go mod tidy` after Go is available to generate it