Skip to content

docs: Storage Migration Protocol (issue #27)#382

Open
nycomp wants to merge 2 commits intoweeklyfrom
feat/storage-migration-protocol
Open

docs: Storage Migration Protocol (issue #27)#382
nycomp wants to merge 2 commits intoweeklyfrom
feat/storage-migration-protocol

Conversation

@nycomp
Copy link
Contributor

@nycomp nycomp commented Mar 13, 2026

Summary

Adds documentation for a storage migration protocol to address issue #27.

Details

The proposed protocol includes:

  • Migration files - Simple Python modules with upgrade()/downgrade() functions
  • State tracking - _migrations table records applied migrations
  • CLI interface - campus migrate and campus rollback commands
  • Yapper integration - Events for audit logging (migration.applied, migration.rolled_back)
  • Multi-storage support - Works with PostgreSQL tables and MongoDB documents

Design Philosophy

For ~2000 users, prioritizes simplicity and explicitness over framework complexity. Avoids heavy tools like Alembic/Flyway while still providing proper versioning, rollback, and audit capabilities.

Test Plan

  • Review protocol document for completeness
  • Verify integration with existing storage layer
  • Confirm Yapper event logging approach
  • Review with team before implementation

Closes #27

🤖 Generated with Claude Code

Proposes a simple, explicit migration system for Campus storage:
- Migration files with upgrade()/downgrade() functions
- State tracking via _migrations table
- CLI: `campus migrate` and `campus rollback`
- Yapper integration for audit logging
- Supports PostgreSQL tables and MongoDB documents

Addresses requirements from issue #27:
1. Initialize app via auto-run on deploy
2. Data migration support with batching
3. Cross-database migration handlers
4. Rollback capability with downgrade()
5. Audit logging via Yapper events

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nycomp nycomp mentioned this pull request Mar 13, 2026
47 tasks
Copy link
Contributor Author

@nycomp nycomp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the pros and cons of the following strategies:

  • autocommit while upgrade in progress, with downgrade option
  • atomic transaction, with all upgrade operations pending until explicitly committed

Assume database downtime while migration is in progress


def upgrade():
"""Add created_at field to existing responses."""
submissions = get_collection("submissions")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fragile to typos in collection/table names. Would it be a better idea to import the relevant resource(s) from campus.auth or campus.api?

Comment on lines +58 to +59
3. **upgrade()** - Forward transformation
4. **downgrade()** - Reverse transformation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are assuming upgrade from the previous schema version, e.g. Revision ID 002 right? So each upgrade/downgrade is only one revision step at a time?

Comment on lines +121 to +131
### PostgreSQL Schema (for state tracking)

```sql
CREATE TABLE IF NOT EXISTS "_migrations" (
"id" TEXT PRIMARY KEY, -- Revision ID (e.g., "001", "002")
"description" TEXT NOT NULL, -- Human-readable description
"storage_type" TEXT NOT NULL, -- "table", "document", "object"
"applied_at" TIMESTAMP NOT NULL, -- When migration was applied
"rollback_at" TIMESTAMP NULL -- When migration was rolled back (if applicable)
);
```
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a postgres table or JSON store (e.g. using bucket storage) be more appropriate for archival?

Does schema need a field for migration status/outcome? E.g. successful/committed, unsuccessful/rollback

Comment on lines +283 to +309
## CLI Interface

Add to `campus` CLI via `main.py`:

```python
# main.py additions

def migrate(target: str | None = None):
"""Run database migrations."""
from campus.storage.migrations import MigrationRunner
from pathlib import Path

migrations_dir = Path(__file__).parent / "storage" / "migrations" / "migrations"
runner = MigrationRunner(migrations_dir)
runner.upgrade(target)
print("Migration complete.")


def rollback(target: str):
"""Rollback to a specific migration."""
from campus.storage.migrations import MigrationRunner
from pathlib import Path

migrations_dir = Path(__file__).parent / "storage" / "migrations" / "migrations"
runner = MigrationRunner(migrations_dir)
runner.downgrade(target)
print("Rollback complete.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current plan is to execute the migration upon PR to staging branch (on a backup copy of database), with failure/rollback being flagged in deployment status and fixed until successful. Is the CLI interface necessary?


### Pre-Deployment Checklist

1. **Backup database** before running migrations in production
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be part of the migration runner?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants