# Project Costs Migration Instructions ## Overview This document provides instructions for migrating the database to add the `project_costs` table using Alembic. ## Migration File **Location:** `migrations/versions/018_add_project_costs_table.py` **Revision:** 018 **Previous Revision:** 017 **Description:** Adds project_costs table for tracking project expenses beyond hourly work ## Pre-Migration Checklist Before running the migration: 1. ✅ **Backup your database** ```bash # PostgreSQL backup example pg_dump -U timetracker timetracker > backup_before_project_costs_$(date +%Y%m%d).sql ``` 2. ✅ **Check current migration status** ```bash # In your project directory with Flask app context flask db current # Or using alembic directly alembic current ``` Expected output: `017 (head)` or similar 3. ✅ **Review the migration** ```bash cat migrations/versions/018_add_project_costs_table.py ``` ## Running the Migration ### Method 1: Using Flask-Migrate (Recommended) ```bash # Navigate to project directory cd /path/to/TimeTracker # Activate virtual environment if needed source venv/bin/activate # Linux/Mac # or .\venv\Scripts\activate # Windows # Run the migration flask db upgrade # Verify the migration flask db current ``` Expected output after upgrade: ``` INFO [alembic.runtime.migration] Running upgrade 017 -> 018, Add project costs table for tracking expenses ``` ### Method 2: Using Alembic Directly ```bash # Navigate to project directory cd /path/to/TimeTracker # Run the migration alembic upgrade head # Verify alembic current ``` ### Method 3: Using Docker ```bash # If running in Docker docker-compose exec app flask db upgrade # Or restart the container (if auto-migration is enabled) docker-compose restart app ``` ### Method 4: Python Script (Docker Environments) ```bash # If you prefer the standalone script python docker/migrate-add-project-costs.py ``` ### Method 5: Raw SQL (Manual) ```bash # Only if Alembic is not available psql -U timetracker -d timetracker -f migrations/add_project_costs.sql ``` ## Verification Steps After running the migration, verify it was successful: ### 1. Check Migration Status ```bash flask db current # Should show: 018 (head) ``` ### 2. Verify Table Creation ```bash psql -U timetracker -d timetracker -c "\d project_costs" ``` Expected output should show: - Columns: id, project_id, user_id, description, category, amount, etc. - Indexes: ix_project_costs_project_id, ix_project_costs_user_id, etc. - Foreign keys: fk_project_costs_project_id, fk_project_costs_user_id, etc. ### 3. Check Application Logs ```bash tail -f logs/timetracker.log ``` Look for any errors related to project_costs ### 4. Test in Application 1. Log in to TimeTracker 2. Navigate to any project 3. Look for "Project Costs & Expenses" section 4. Try adding a test cost ## Rollback (If Needed) If you need to rollback the migration: ```bash # Using Flask-Migrate flask db downgrade # Or using Alembic alembic downgrade -1 # To downgrade to a specific revision flask db downgrade 017 # or alembic downgrade 017 ``` **Warning:** Rolling back will **delete the project_costs table** and all data in it! ## Troubleshooting ### Issue: "Table already exists" **Problem:** The migration script tries to create a table that already exists. **Solution:** The migration includes a check for table existence. If you see this error: 1. Verify the table actually exists: `\d project_costs` in psql 2. If it exists and is correct, manually mark the migration as complete: ```bash alembic stamp 018 ``` ### Issue: "Cannot find revision 017" **Problem:** The previous migration (017) doesn't exist or wasn't run. **Solution:** 1. Check current revision: `flask db current` 2. Upgrade to 017 first: `flask db upgrade 017` 3. Then upgrade to 018: `flask db upgrade` ### Issue: Foreign key constraint fails **Problem:** Referenced tables (projects, users, invoices) don't exist. **Solution:** 1. Ensure you're at migration 017 before running this 2. The migration checks for invoices table existence before creating that FK 3. Run previous migrations first: `flask db upgrade` ### Issue: "Cannot connect to database" **Problem:** Database connection parameters are incorrect. **Solution:** 1. Check your `.env` file or environment variables 2. Verify database is running: `docker-compose ps` or `systemctl status postgresql` 3. Test connection: `psql -U timetracker -d timetracker` ### Issue: Permission denied **Problem:** Database user doesn't have permission to create tables. **Solution:** ```sql -- Grant necessary permissions (run as postgres superuser) GRANT CREATE ON DATABASE timetracker TO timetracker; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO timetracker; ``` ## Post-Migration After successful migration: 1. ✅ **Restart Application** ```bash # Docker docker-compose restart app # Systemd sudo systemctl restart timetracker # Manual # Stop and start your Flask application ``` 2. ✅ **Clear Application Cache** ```bash # If using Redis redis-cli FLUSHALL # Browser cache # Hard refresh: Ctrl+Shift+R (or Cmd+Shift+R on Mac) ``` 3. ✅ **Test Core Functionality** - [ ] View a project - [ ] Add a cost - [ ] Edit a cost - [ ] Delete a cost - [ ] Generate an invoice with costs - [ ] View project reports 4. ✅ **Update Documentation** - Inform team about new feature - Share `PROJECT_COSTS_FEATURE.md` with users - Update internal wiki/docs if applicable ## Migration Details ### What Gets Created **Table:** `project_costs` - Primary key: `id` - Foreign keys: `project_id`, `user_id`, `invoice_id` - Indexes: On project_id, user_id, cost_date, invoice_id **Columns:** - `id`: Integer, Primary Key - `project_id`: Integer, NOT NULL, Foreign Key to projects - `user_id`: Integer, NOT NULL, Foreign Key to users - `description`: String(500), NOT NULL - `category`: String(50), NOT NULL - `amount`: Numeric(10,2), NOT NULL - `currency_code`: String(3), NOT NULL, Default 'EUR' - `billable`: Boolean, NOT NULL, Default TRUE - `invoiced`: Boolean, NOT NULL, Default FALSE - `invoice_id`: Integer, NULL, Foreign Key to invoices - `cost_date`: Date, NOT NULL - `notes`: Text, NULL - `receipt_path`: String(500), NULL - `created_at`: DateTime, NOT NULL, Default CURRENT_TIMESTAMP - `updated_at`: DateTime, NOT NULL, Default CURRENT_TIMESTAMP ### Database Size Impact Estimated size per cost entry: ~300 bytes Example capacity: - 1,000 costs ≈ 300 KB - 10,000 costs ≈ 3 MB - 100,000 costs ≈ 30 MB ## Support For issues or questions: 1. Check `PROJECT_COSTS_FEATURE.md` for feature documentation 2. Review `PROJECT_COSTS_IMPLEMENTATION_SUMMARY.md` for technical details 3. Check application logs: `logs/timetracker.log` 4. Verify database state: `psql -U timetracker -d timetracker` ## Emergency Rollback Script If you need to manually remove the table: ```sql -- WARNING: This will delete all project cost data! -- Only use if rollback through Alembic fails -- Drop foreign keys first ALTER TABLE project_costs DROP CONSTRAINT IF EXISTS fk_project_costs_invoice_id; ALTER TABLE project_costs DROP CONSTRAINT IF EXISTS fk_project_costs_user_id; ALTER TABLE project_costs DROP CONSTRAINT IF EXISTS fk_project_costs_project_id; -- Drop indexes DROP INDEX IF EXISTS ix_project_costs_invoice_id; DROP INDEX IF EXISTS ix_project_costs_cost_date; DROP INDEX IF EXISTS ix_project_costs_user_id; DROP INDEX IF EXISTS ix_project_costs_project_id; -- Drop table DROP TABLE IF EXISTS project_costs; -- Mark migration as rolled back -- (Run this through Alembic, not SQL) -- alembic downgrade 017 ``` ## Next Steps After successful migration: - Read: `QUICK_START_PROJECT_COSTS.md` for usage guide - Read: `PROJECT_COSTS_FEATURE.md` for full feature documentation - Train users on the new functionality - Monitor application performance - Set up any necessary backups for the new data