Files
CheckInApp/openspec/specs/backend-auto-migrations/spec.md
T
8a12744 3ab845798d feat(backend): add automatic DB migrations
Add a lightweight migration runner with schema_migrations tracking, run pending migrations during backend startup before the scheduler, and keep a manual backend-migrate entrypoint.

The change also moves the existing lockout and task-thread-ID schema steps into shared migration modules, updates docs, and archives the OpenSpec change.
2026-05-05 01:36:58 +08:00

76 lines
4.1 KiB
Markdown

# backend-auto-migrations Specification
## Purpose
Backend database migration contract for applying ordered schema changes during startup and through a manual operator command.
## Requirements
### Requirement: Ordered backend migration registry
The backend SHALL define a deterministic registry of database migrations with stable identifiers and execution order.
#### Scenario: Registry order is stable
- **WHEN** the migration runner loads available migrations
- **THEN** it SHALL evaluate them in the registered order using stable migration identifiers.
#### Scenario: Existing migrations are registered
- **WHEN** the backend migration registry is built
- **THEN** it SHALL include migrations for the existing account-lockout fields and task thread ID schema changes.
### Requirement: Applied migration tracking
The backend SHALL store applied migration records in the application database and use those records to skip completed migrations.
#### Scenario: Migration metadata is initialized
- **WHEN** the migration runner starts against a database without migration metadata
- **THEN** it SHALL create the migration metadata table before checking pending migrations.
#### Scenario: Pending migration is marked after success
- **WHEN** a pending migration completes successfully
- **THEN** the backend SHALL record that migration as applied with its stable identifier and applied timestamp.
#### Scenario: Completed migration is skipped
- **WHEN** a migration identifier is already present in the applied migration metadata
- **THEN** the backend SHALL skip that migration instead of executing it again.
#### Scenario: Failed migration is not marked
- **WHEN** a migration fails during execution
- **THEN** the backend SHALL NOT record that migration as applied.
### Requirement: Automatic startup migration execution
The backend SHALL run pending database migrations automatically during API startup before runtime background work begins.
#### Scenario: Startup applies migrations before scheduler
- **WHEN** the FastAPI lifespan startup runs
- **THEN** it SHALL initialize base database tables, run pending migrations, and only then start the scheduler.
#### Scenario: Startup stops on migration failure
- **WHEN** any pending migration fails during startup
- **THEN** the backend SHALL fail startup and SHALL NOT start the scheduler.
#### Scenario: Startup logs migration activity
- **WHEN** startup migration execution runs
- **THEN** the backend SHALL log whether migrations were applied, skipped, or failed with the relevant migration identifier.
### Requirement: Manual migration execution
The backend SHALL provide a manual command path that runs the same registered migrations used by automatic startup.
#### Scenario: Operator runs migrations manually
- **WHEN** an operator executes the documented backend migration command
- **THEN** the command SHALL apply pending registered migrations and skip already-applied migrations.
#### Scenario: Manual failure exits unsuccessfully
- **WHEN** a migration fails during manual execution
- **THEN** the command SHALL exit unsuccessfully after reporting the failing migration.
### Requirement: Existing migration behavior is preserved
The backend SHALL preserve the behavior of existing schema changes when they move into the automatic migration path.
#### Scenario: Account lockout fields are added
- **WHEN** the account-lockout migration runs against a database missing its fields
- **THEN** it SHALL add `failed_login_attempts`, `locked_until`, and `last_failed_login` to the users table.
#### Scenario: Task thread identity is backfilled
- **WHEN** the task thread ID migration runs against valid existing task payloads
- **THEN** it SHALL add or maintain `check_in_tasks.thread_id`, backfill it from `payload_config.ThreadId`, and ensure the per-user thread ID uniqueness index exists.
#### Scenario: Invalid legacy task payload blocks migration
- **WHEN** the task thread ID migration finds missing or duplicate `ThreadId` values that would make the schema invalid
- **THEN** it SHALL fail with a clear validation error instead of silently creating inconsistent task identity data.