mirror of
https://github.com/wahyd4/you-music.git
synced 2026-08-09 05:06:44 +10:00
add db migration
This commit is contained in:
+264
@@ -0,0 +1,264 @@
|
||||
# Database Migrations Guide
|
||||
|
||||
YouMusic uses [Alembic](https://alembic.sqlalchemy.org/) for database schema migrations. This ensures safe schema changes without data loss.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### View Migration Status
|
||||
```bash
|
||||
cd backend
|
||||
./migrate.sh current
|
||||
```
|
||||
|
||||
### Create a New Migration
|
||||
When you modify database models in `app/models/models.py`:
|
||||
```bash
|
||||
cd backend
|
||||
./migrate.sh create "Add new field description"
|
||||
```
|
||||
|
||||
### Apply Migrations
|
||||
```bash
|
||||
cd backend
|
||||
./migrate.sh upgrade
|
||||
```
|
||||
|
||||
### Rollback a Migration
|
||||
```bash
|
||||
cd backend
|
||||
./migrate.sh downgrade # Go back one migration
|
||||
# or
|
||||
./migrate.sh downgrade <revision_id> # Go to specific version
|
||||
```
|
||||
|
||||
## Migration Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `./migrate.sh create "message"` | Create new migration with autogenerate |
|
||||
| `./migrate.sh upgrade` | Apply all pending migrations |
|
||||
| `./migrate.sh downgrade` | Rollback last migration |
|
||||
| `./migrate.sh history` | View migration history |
|
||||
| `./migrate.sh current` | Show current database version |
|
||||
| `./migrate.sh stamp head` | Mark database as current without running migrations |
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Models** - Define your schema in `app/models/models.py`
|
||||
2. **Generate Migration** - Alembic compares models to current DB and creates migration script
|
||||
3. **Review Migration** - Check `alembic/versions/*.py` file before applying
|
||||
4. **Apply Migration** - Run upgrade to apply changes to database
|
||||
|
||||
## Migration Workflow
|
||||
|
||||
### Adding a New Field
|
||||
|
||||
1. Add field to model:
|
||||
```python
|
||||
# app/models/models.py
|
||||
class Music(Base):
|
||||
# ... existing fields ...
|
||||
new_field: Mapped[Optional[str]] = mapped_column(String, nullable=True)
|
||||
```
|
||||
|
||||
2. Create migration:
|
||||
```bash
|
||||
./migrate.sh create "Add new_field to music table"
|
||||
```
|
||||
|
||||
3. Review generated migration in `alembic/versions/`
|
||||
|
||||
4. Apply migration:
|
||||
```bash
|
||||
./migrate.sh upgrade
|
||||
```
|
||||
|
||||
### Renaming a Field
|
||||
|
||||
Alembic may detect this as drop + add. Manually edit the migration:
|
||||
|
||||
```python
|
||||
# Before (auto-generated)
|
||||
def upgrade():
|
||||
batch_op.drop_column('old_name')
|
||||
batch_op.add_column(sa.Column('new_name', sa.String(), nullable=True))
|
||||
|
||||
# After (manual edit)
|
||||
def upgrade():
|
||||
batch_op.alter_column('old_name', new_column_name='new_name')
|
||||
```
|
||||
|
||||
### Deleting a Field
|
||||
|
||||
1. Remove from model
|
||||
2. Generate migration: `./migrate.sh create "Remove old_field"`
|
||||
3. Review - ensure data you want is preserved
|
||||
4. Apply: `./migrate.sh upgrade`
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### First Deployment (New Instance)
|
||||
```bash
|
||||
# Migrations will run automatically on startup
|
||||
# Or manually:
|
||||
./migrate.sh upgrade
|
||||
```
|
||||
|
||||
### Updating Existing Instance
|
||||
```bash
|
||||
# 1. Backup database
|
||||
cp data/youmusic.db data/youmusic.db.backup
|
||||
|
||||
# 2. Pull latest code
|
||||
git pull
|
||||
|
||||
# 3. Install dependencies
|
||||
uv pip install -r requirements.txt
|
||||
|
||||
# 4. Apply migrations
|
||||
./migrate.sh upgrade
|
||||
|
||||
# 5. Restart application
|
||||
```
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
Migrations run automatically when the container starts (via startup script).
|
||||
|
||||
To run manually in container:
|
||||
```bash
|
||||
docker exec -it youmusic /app/backend/migrate.sh current
|
||||
docker exec -it youmusic /app/backend/migrate.sh upgrade
|
||||
```
|
||||
|
||||
## Kubernetes Deployment
|
||||
|
||||
Migrations run as an init container before the main application starts.
|
||||
|
||||
Check migration status:
|
||||
```bash
|
||||
kubectl logs -f deployment/youmusic -c migrations
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Target database is not up to date"
|
||||
Your database is behind. Run:
|
||||
```bash
|
||||
./migrate.sh upgrade
|
||||
```
|
||||
|
||||
### "Can't locate revision identified by 'xyz'"
|
||||
Migration files are missing or database is inconsistent. Check:
|
||||
```bash
|
||||
./migrate.sh history
|
||||
./migrate.sh current
|
||||
```
|
||||
|
||||
### Rollback Failed Migration
|
||||
```bash
|
||||
# Downgrade to previous version
|
||||
./migrate.sh downgrade
|
||||
|
||||
# Or to specific version
|
||||
./migrate.sh downgrade <revision_id>
|
||||
```
|
||||
|
||||
### Reset Database (Dev Only - DATA LOSS!)
|
||||
```bash
|
||||
# Delete database
|
||||
rm data/youmusic.db
|
||||
|
||||
# Recreate with latest schema
|
||||
./migrate.sh upgrade
|
||||
```
|
||||
|
||||
### Manually Fix Database Version
|
||||
If migrations got out of sync:
|
||||
```bash
|
||||
# Stamp to specific version (doesn't run migrations)
|
||||
./migrate.sh stamp <revision_id>
|
||||
|
||||
# Or to latest
|
||||
./migrate.sh stamp head
|
||||
```
|
||||
|
||||
## Files and Directories
|
||||
|
||||
```
|
||||
backend/
|
||||
├── alembic/ # Migration configuration
|
||||
│ ├── versions/ # Migration scripts
|
||||
│ │ └── *.py # Individual migrations
|
||||
│ ├── env.py # Alembic environment config
|
||||
│ └── script.py.mako # Migration template
|
||||
├── alembic.ini # Alembic settings
|
||||
├── migrate.sh # Helper script
|
||||
└── app/
|
||||
└── models/
|
||||
└── models.py # SQLAlchemy models (source of truth)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always Review** - Check auto-generated migrations before applying
|
||||
2. **Test First** - Run migrations on dev/staging before production
|
||||
3. **Backup Data** - Always backup database before migrations in production
|
||||
4. **One Change Per Migration** - Keep migrations focused and atomic
|
||||
5. **Descriptive Messages** - Use clear migration messages
|
||||
6. **Version Control** - Commit migration files to git
|
||||
7. **Never Edit Applied Migrations** - Create new ones instead
|
||||
8. **Document Complex Changes** - Add comments in migration files
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Manual Migration (No Autogenerate)
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
alembic revision -m "Manual migration"
|
||||
# Edit the created file manually
|
||||
```
|
||||
|
||||
### Offline SQL Generation
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
alembic upgrade head --sql > migration.sql
|
||||
# Review migration.sql before applying
|
||||
```
|
||||
|
||||
### Branching and Merging
|
||||
```bash
|
||||
# Create branch-specific migration
|
||||
alembic revision -m "Feature branch change" --branch-label feature
|
||||
|
||||
# Merge branches
|
||||
alembic merge -m "Merge branches" head1 head2
|
||||
```
|
||||
|
||||
## SQLite Specific Notes
|
||||
|
||||
- Uses `batch_alter_table` for schema changes (required for SQLite)
|
||||
- Some operations may require table recreation
|
||||
- Foreign key constraints temporarily disabled during migrations
|
||||
- `render_as_batch=True` in env.py handles this automatically
|
||||
|
||||
## Migration History Example
|
||||
|
||||
```bash
|
||||
$ ./migrate.sh history
|
||||
|
||||
01209c730b33 -> (head), Initial migration
|
||||
<base> -> 01209c730b33, Initial migration
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Alembic Docs: https://alembic.sqlalchemy.org/
|
||||
- SQLAlchemy Docs: https://docs.sqlalchemy.org/
|
||||
- Project Issues: Check GitHub issues
|
||||
|
||||
## See Also
|
||||
|
||||
- `AGENTS.md` - AI/LLM context about the project
|
||||
- `DEV_QUICK_START.md` - Development setup guide
|
||||
- `DEPLOYMENT.md` - Deployment instructions
|
||||
Reference in New Issue
Block a user