Spaces:
Sleeping
Database Migrations Guide
Overview
Database migrations are manual scripts that create and update database tables. They must be run once during initial setup or when deploying updates.
Quick Start
Run All Migrations (Recommended)
python migrate_all_tables.py
This will create all 6 tables:
trans.scm_attendance- Check-in/out recordstrans.scm_tasks- Task assignmentstrans.scm_task_attachments- Task photos/signaturestrans.scm_location_points- GPS tracking (TimescaleDB hypertable)trans.scm_geofences- Work zone definitionstrans.scm_trips- Business trip tracking
Tables Created
1. Attendance Table
- Table:
trans.scm_attendance - Purpose: Employee check-in/check-out records
- Indexes: 2 (employee_work_date, merchant_date)
2. Tasks Table
- Table:
trans.scm_tasks - Purpose: Task assignments and tracking
- Indexes: 1 (assigned_to, scheduled_at)
3. Task Attachments Table
- Table:
trans.scm_task_attachments - Purpose: Task photos and signatures
- Indexes: 1 (task_id)
- Foreign Key: References scm_tasks(id)
4. Location Points Table (TimescaleDB)
- Table:
trans.scm_location_points - Purpose: GPS location tracking
- Type: TimescaleDB hypertable (if extension available)
- Indexes: 2 (user_time, merchant_time)
- Partitioning: 1-day chunks
5. Geofences Table
- Table:
trans.scm_geofences - Purpose: Work zone definitions
- Indexes: 2 (merchant, merchant_active)
- Constraints: 3 (radius, latitude, longitude)
6. Trips Table
- Table:
trans.scm_trips - Purpose: Business trip tracking
- Indexes: 3 (user_status, merchant_date, status)
- Constraints: 6 (status, coordinates, distance)
Migration Behavior
Idempotent Operations
All migrations use CREATE TABLE IF NOT EXISTS and CREATE INDEX IF NOT EXISTS, making them safe to run multiple times.
What Happens
- Creates
transschema if not exists - Creates each table if not exists
- Creates indexes if not exist
- Adds constraints (silently skips if exist)
- Converts location table to hypertable (if TimescaleDB available)
When to Run Migrations
Initial Setup
Run migrations once when setting up the application for the first time:
python migrate_all_tables.py
After Git Pull
If new tables were added, run migrations again:
git pull
python migrate_all_tables.py
Production Deployment
- Backup database first
- Run migrations on staging
- Test thoroughly
- Run on production
- Verify tables exist
Checking Migration Status
Check if tables exist
-- Connect to database
psql $DATABASE_URL
-- List all tables in trans schema
\dt trans.*
-- Check specific table
\d trans.scm_trips
Verify all tables
SELECT
schemaname,
tablename
FROM pg_tables
WHERE schemaname = 'trans'
ORDER BY tablename;
Expected output:
- scm_attendance
- scm_geofences
- scm_location_points
- scm_task_attachments
- scm_tasks
- scm_trips
Troubleshooting
Error: "Could not connect to database"
Check:
.envfile exists with correct credentials- Database is accessible
- Network connection is working
# Test connection
psql "postgresql://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/$DB_NAME?sslmode=require"
Error: "TimescaleDB extension not found"
Solution: The location table will be created as a regular PostgreSQL table. To enable TimescaleDB:
-- Connect to database
psql <connection_string>
-- Enable TimescaleDB
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
-- Re-run migrations
python migrate_all_tables.py
Error: "Permission denied"
Solution: Your database user needs these permissions:
- CREATE SCHEMA
- CREATE TABLE
- CREATE INDEX
- INSERT, SELECT, UPDATE, DELETE
Migration Fails Midway
Solution:
- Check error message
- Fix the issue
- Re-run the migration (it's idempotent)
Manual Migration (Advanced)
If you need to run migrations manually:
# Connect to database
psql $DATABASE_URL
# Copy SQL from migrate_all_tables.py and run
Rollback (CAUTION: Destroys Data)
To drop all tables and start fresh:
-- Drop all tables
DROP TABLE IF EXISTS trans.scm_task_attachments CASCADE;
DROP TABLE IF EXISTS trans.scm_tasks CASCADE;
DROP TABLE IF EXISTS trans.scm_attendance CASCADE;
DROP TABLE IF EXISTS trans.scm_location_points CASCADE;
DROP TABLE IF EXISTS trans.scm_geofences CASCADE;
DROP TABLE IF EXISTS trans.scm_trips CASCADE;
-- Drop schema
DROP SCHEMA IF EXISTS trans CASCADE;
-- Re-run migrations
python migrate_all_tables.py
Adding New Tables
To add a new table to the migration system:
- Add function to
migrate_all_tables.py:
async def create_new_table(conn):
"""Create new_table"""
await conn.execute("""
CREATE TABLE IF NOT EXISTS trans.new_table (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- your columns here
)
""")
await conn.execute("""
CREATE INDEX IF NOT EXISTS idx_new_table_field
ON trans.new_table (field_name)
""")
- Add to
_run_migrations()function:
async def _run_migrations(conn):
await create_attendance_table(conn)
await create_tasks_table(conn)
await create_task_attachments_table(conn)
await create_location_table(conn)
await create_geofences_table(conn)
await create_trips_table(conn)
await create_new_table(conn) # Add here
- Run migrations:
python migrate_all_tables.py
Best Practices
1. Always Backup First
# PostgreSQL backup
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME > backup_$(date +%Y%m%d).sql
2. Test on Staging First
# Run on staging
DB_HOST=staging.example.com python migrate_all_tables.py
# Test thoroughly
python test_trips_api.py
python test_location_api.py
python test_geofences_api.py
3. Use Idempotent Operations
Always use:
CREATE TABLE IF NOT EXISTSCREATE INDEX IF NOT EXISTS- Try-catch for constraints
4. Document Changes
Update this guide when adding new tables or making schema changes.
Environment Variables
Migrations use these environment variables from .env:
DB_USER=trans_owner
DB_PASSWORD=your_password
DB_HOST=your-host.aws.neon.tech
DB_PORT=5432
DB_NAME=cuatrolabs
FAQ
Q: Do migrations run automatically on server start?
A: No, migrations are manual. You must run them explicitly using python migrate_all_tables.py.
Q: Can I run migrations multiple times?
A: Yes, migrations are idempotent. They check if tables exist before creating them.
Q: What if I only want to create one table?
A: You can modify migrate_all_tables.py to comment out the tables you don't need, or copy the specific function and run it separately.
Q: How do I verify migrations completed successfully?
A: Check the output for "✅ SUCCESS" message, or query the database:
SELECT COUNT(*) FROM pg_tables WHERE schemaname = 'trans';
-- Should return 6
Next Steps
After running migrations:
Verify tables:
\dt trans.*Start server:
python -m uvicorn app.main:app --port 8003 --reloadTest APIs:
python test_trips_api.py python test_location_api.py python test_geofences_api.pyView API docs: http://localhost:8003/docs
Support
- Migration script:
migrate_all_tables.py - Documentation: This file
- Database access: Use psql or pgAdmin
- Logs: Check console output during migration