Files
boc/packages/infrastructure/migrations/001_initial_schema.sql
T
Bernt 2f0ab18e81 PR-003A: PostgreSQL Repository Adapters + Persistence Independence Test
- 4 PostgreSQL adapter stubs (Session, Mission, DecisionCase, Artifact)
- Migration 001: Initial schema (sessions, missions, artifacts, decision_cases)
- Persistence Independence Test: 6 tests verifying same behavior
  across InMemory and PostgreSQL implementations
- ADR-008: PostgreSQL Adapters for Production
- ADR-009: Persistence Independence

Architecture Quality Gates:
- Domain unchanged
- Application unchanged
- Only adapter implementation changes
- Same test suite runs against both implementations

Next: PR-003B — Schema & Migrations, PR-003C — Integration Tests,
PR-003D — Unit of Work / Transactions
2026-07-02 15:57:23 +00:00

97 lines
3.3 KiB
PL/PgSQL

-- Migration 001: Initial Schema
--
-- Domain model mapped to PostgreSQL tables.
-- Domain does NOT know about this schema.
-- Schema is infrastructure concern.
-- Sessions
CREATE TABLE IF NOT EXISTS field_sessions (
id VARCHAR(32) PRIMARY KEY,
location_lat DECIMAL(10, 8) NOT NULL,
location_lng DECIMAL(11, 8) NOT NULL,
location_accuracy DECIMAL(10, 2),
date DATE NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'planned',
mission_ids TEXT[] DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Missions
CREATE TABLE IF NOT EXISTS missions (
id VARCHAR(32) PRIMARY KEY,
session_id VARCHAR(32) NOT NULL REFERENCES field_sessions(id),
location_lat DECIMAL(10, 8) NOT NULL,
location_lng DECIMAL(11, 8) NOT NULL,
location_accuracy DECIMAL(10, 2),
status VARCHAR(20) NOT NULL DEFAULT 'created',
device_model VARCHAR(100) NOT NULL,
device_os VARCHAR(100) NOT NULL,
device_app_version VARCHAR(50) NOT NULL,
artifact_ids TEXT[] DEFAULT '{}',
observation_ids TEXT[] DEFAULT '{}',
sequence_number INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Artifacts
CREATE TABLE IF NOT EXISTS artifacts (
id VARCHAR(32) PRIMARY KEY,
type VARCHAR(50) NOT NULL,
version_major INTEGER NOT NULL DEFAULT 1,
version_minor INTEGER NOT NULL DEFAULT 0,
version_patch INTEGER NOT NULL DEFAULT 0,
hash_algorithm VARCHAR(20) NOT NULL DEFAULT 'sha256',
hash_value VARCHAR(64) NOT NULL,
created_by VARCHAR(100) NOT NULL,
storage_protocol VARCHAR(20) NOT NULL,
storage_bucket VARCHAR(200),
storage_path TEXT NOT NULL,
parent_id VARCHAR(32) REFERENCES artifacts(id),
lineage TEXT[] DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Decision Cases
CREATE TABLE IF NOT EXISTS decision_cases (
id VARCHAR(32) PRIMARY KEY,
mission_id VARCHAR(32) NOT NULL REFERENCES missions(id),
title VARCHAR(500) NOT NULL,
description TEXT NOT NULL,
priority VARCHAR(20) NOT NULL,
confidence VARCHAR(20) NOT NULL,
recommended_action TEXT NOT NULL,
observation_ids TEXT[] DEFAULT '{}',
evidence_ids TEXT[] DEFAULT '{}',
finding_id VARCHAR(32) NOT NULL,
decision_id VARCHAR(32) NOT NULL,
review_id VARCHAR(32) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
version INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Indexes for common queries
CREATE INDEX IF NOT EXISTS idx_missions_session_id ON missions(session_id);
CREATE INDEX IF NOT EXISTS idx_missions_status ON missions(status);
CREATE INDEX IF NOT EXISTS idx_decision_cases_mission_id ON decision_cases(mission_id);
CREATE INDEX IF NOT EXISTS idx_decision_cases_status ON decision_cases(status);
CREATE INDEX IF NOT EXISTS idx_field_sessions_date ON field_sessions(date);
CREATE INDEX IF NOT EXISTS idx_field_sessions_status ON field_sessions(status);
-- Update trigger for updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_field_sessions_updated_at BEFORE UPDATE ON field_sessions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_missions_updated_at BEFORE UPDATE ON missions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();