Phase 1 of v1.1.1 "Polish" release focusing on production readiness. Implements logging, connection pooling, validation, and error handling. Following specs in docs/design/v1.1.1/developer-qa.md and ADRs 052-055. **Structured Logging** (Q3, ADR-054) - RotatingFileHandler (10MB files, keep 10) - Correlation IDs for request tracing - All print statements replaced with logging - Context-aware correlation IDs (init/request) - Logs written to data/logs/starpunk.log **Database Connection Pooling** (Q2, ADR-053) - Connection pool with configurable size (default: 5) - Request-scoped connections via Flask g object - Pool statistics for monitoring - WAL mode enabled for concurrency - Backward compatible get_db() signature **Configuration Validation** (Q14, ADR-052) - Validates presence and type of all config values - Fail-fast startup with clear error messages - LOG_LEVEL enum validation - Type checking for strings, integers, paths - Non-zero exit status on errors **Centralized Error Handling** (Q4, ADR-055) - Moved handlers to starpunk/errors.py - Micropub spec-compliant JSON errors - HTML templates for browser requests - All errors logged with correlation IDs - MicropubError exception class **Database Module Reorganization** - Moved database.py to database/ package - Separated init.py, pool.py, schema.py - Maintains backward compatibility - Cleaner separation of concerns **Testing** - 580 tests passing - 1 pre-existing flaky test noted - No breaking changes to public API **Documentation** - CHANGELOG.md updated with v1.1.1 entry - Version bumped to 1.1.1 - Implementation report in docs/reports/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
85 lines
2.8 KiB
Python
85 lines
2.8 KiB
Python
"""
|
|
Database schema definition for StarPunk
|
|
|
|
Initial database schema (v1.0.0 baseline)
|
|
DO NOT MODIFY - This represents the v1.0.0 schema state
|
|
All schema changes after v1.0.0 must go in migration files
|
|
"""
|
|
|
|
INITIAL_SCHEMA_SQL = """
|
|
-- Notes metadata (content is in files)
|
|
CREATE TABLE IF NOT EXISTS notes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
slug TEXT UNIQUE NOT NULL,
|
|
file_path TEXT UNIQUE NOT NULL,
|
|
published BOOLEAN DEFAULT 0,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP,
|
|
content_hash TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_notes_created_at ON notes(created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_published ON notes(published);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_slug ON notes(slug);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_deleted_at ON notes(deleted_at);
|
|
|
|
-- Authentication sessions (IndieLogin)
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
session_token_hash TEXT UNIQUE NOT NULL,
|
|
me TEXT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
last_used_at TIMESTAMP,
|
|
user_agent TEXT,
|
|
ip_address TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(session_token_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_me ON sessions(me);
|
|
|
|
-- Micropub access tokens (secure storage with hashed tokens)
|
|
CREATE TABLE IF NOT EXISTS tokens (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
token_hash TEXT UNIQUE NOT NULL,
|
|
me TEXT NOT NULL,
|
|
client_id TEXT,
|
|
scope TEXT DEFAULT 'create',
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
last_used_at TIMESTAMP,
|
|
revoked_at TIMESTAMP
|
|
);
|
|
|
|
-- Authorization codes for IndieAuth token exchange
|
|
CREATE TABLE IF NOT EXISTS authorization_codes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
code_hash TEXT UNIQUE NOT NULL,
|
|
me TEXT NOT NULL,
|
|
client_id TEXT NOT NULL,
|
|
redirect_uri TEXT NOT NULL,
|
|
scope TEXT,
|
|
state TEXT,
|
|
code_challenge TEXT,
|
|
code_challenge_method TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
used_at TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_auth_codes_hash ON authorization_codes(code_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_auth_codes_expires ON authorization_codes(expires_at);
|
|
|
|
-- CSRF state tokens (for admin login flow)
|
|
CREATE TABLE IF NOT EXISTS auth_state (
|
|
state TEXT PRIMARY KEY,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
redirect_uri TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_auth_state_expires ON auth_state(expires_at);
|
|
"""
|