rdev/internal/db/migrations/015_operations.sql
jordan c280a92012 feat: add operations audit system and template improvements
Operations Audit (new feature):
- Add Operation domain model with status tracking (pending, running, completed, failed, cancelled)
- Add OperationRepository with PostgreSQL implementation
- Add OperationService for CRUD and lifecycle management
- Add operations handlers (list, get, cancel endpoints)
- Add migration 015_operations.sql for operations table
- Add operation cleanup worker for stale operation handling
- Add ErrOperationNotFound to domain errors

Template Improvements:
- Add CLAUDE.md configuration files to astro-landing, default, and go-api templates
- Fix PORT template variable usage in nginx configs for app templates
- Add replace directives for local pkg module in Go templates
- Simplify Go service/worker Dockerfiles for workspace builds
- Fix TypeScript error in logger template

Other:
- Refactor landing-test.sh cookbook script
- Update CLAUDE.md version reference

Note: Some files exceed 500-line limit (pre-existing debt + new feature)
- component.go: 550 lines (unchanged, pre-existing)
- main.go: 522 lines (added operations wiring)
- operation_repo.go: 569 lines (new, needs splitting)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 19:08:57 -07:00

69 lines
3.4 KiB
SQL

-- Operations: Tracks all project operations for debugging
-- Operations capture what happened step-by-step with enough detail to pinpoint failures.
-- 30-day retention - operations are for debugging, not compliance.
CREATE TABLE IF NOT EXISTS operations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
project_id TEXT NOT NULL,
type TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
-- Correlation
request_id TEXT, -- HTTP request that initiated
triggered_by UUID REFERENCES operations(id) ON DELETE SET NULL,
commit_sha TEXT, -- Git commit this operation created/triggered
external_ref TEXT, -- Woodpecker build#, K8s deployment, etc.
-- Timing
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ,
duration_ms INT,
-- Content (JSONB for flexibility)
input JSONB, -- What was requested
output JSONB, -- What was produced
-- Error handling: essence + detail
error TEXT, -- One-line summary
error_detail TEXT, -- Full stack/output (truncated to 10KB)
-- Steps
steps JSONB NOT NULL DEFAULT '[]',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Index for listing operations by project (most common query)
CREATE INDEX IF NOT EXISTS idx_ops_project_time ON operations(project_id, started_at DESC);
-- Partial index for active/failed operations (status queries)
CREATE INDEX IF NOT EXISTS idx_ops_project_status ON operations(project_id, status)
WHERE status IN ('pending', 'running', 'failed');
-- Index for finding operations by commit SHA (build correlation)
CREATE INDEX IF NOT EXISTS idx_ops_commit ON operations(commit_sha)
WHERE commit_sha IS NOT NULL;
-- Index for cleanup worker (delete operations older than 30 days)
CREATE INDEX IF NOT EXISTS idx_ops_cleanup ON operations(started_at);
-- Comments
COMMENT ON TABLE operations IS 'Tracks project operations for debugging (30-day retention)';
COMMENT ON COLUMN operations.id IS 'Unique operation ID';
COMMENT ON COLUMN operations.project_id IS 'Project this operation belongs to';
COMMENT ON COLUMN operations.type IS 'Operation type: project.create, component.add, build, resource.provision';
COMMENT ON COLUMN operations.status IS 'Operation status: pending, running, completed, failed';
COMMENT ON COLUMN operations.request_id IS 'HTTP request ID that initiated this operation';
COMMENT ON COLUMN operations.triggered_by IS 'Parent operation that triggered this one';
COMMENT ON COLUMN operations.commit_sha IS 'Git commit this operation created or was triggered by';
COMMENT ON COLUMN operations.external_ref IS 'External reference (e.g., Woodpecker build#42)';
COMMENT ON COLUMN operations.started_at IS 'When the operation started';
COMMENT ON COLUMN operations.completed_at IS 'When the operation finished';
COMMENT ON COLUMN operations.duration_ms IS 'Total operation duration in milliseconds';
COMMENT ON COLUMN operations.input IS 'Operation input parameters as JSONB';
COMMENT ON COLUMN operations.output IS 'Operation output/result as JSONB';
COMMENT ON COLUMN operations.error IS 'One-line error summary';
COMMENT ON COLUMN operations.error_detail IS 'Full error detail (truncated to 10KB)';
COMMENT ON COLUMN operations.steps IS 'Operation steps as JSONB array';
COMMENT ON COLUMN operations.created_at IS 'When the record was created';