verify
Pre-commit verification - checks changes won't break the deployed app or corrupt the database
SKILL.md.claude/skills/verify/SKILL.md
GitHubPre-Commit Verification
Before committing and pushing, verify that changes across all layers of the app are consistent and safe.
CRITICAL CONTEXT
This is a deployed production app with a live PostgreSQL database containing real data. The user NEVER runs commands directly on the live database. Schema changes happen automatically when the app restarts through the build/deploy process.
Deployment flow:
- Code is pushed to git
- Coolify rebuilds Docker container
- On startup,
main.pyruns:migrate_db()→init_db()→seed_db() - Migrations execute automatically against the live database
If a migration is wrong, data could be lost or corrupted with no easy recovery.
APP ARCHITECTURE
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND (React/TS) │
│ /frontend/src/types/*.ts ←→ /frontend/src/api/*.ts │
└─────────────────────────────────────────────────────────────┘
↓ REST API
┌─────────────────────────────────────────────────────────────┐
│ BACKEND (Python/FastAPI) │
│ /routes/*.py (REST) ←→ /tools/*.py (MCP for Claude) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ DATABASE LAYER │
│ /db/*.py ←→ /db/validation.py ←→ /db/connection.py │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ POSTGRESQL │
│ Schema defined in: /db/connection.py (init_db, migrate_db) │
│ Migrations in: /migrations/*.sql │
└─────────────────────────────────────────────────────────────┘
VERIFICATION CHECKLIST
Run through these checks based on what was changed:
1. DATABASE SCHEMA CHANGES
If any changes to /db/connection.py (init_db or migrate_db) or /migrations/*.sql:
Migration Safety Checks:
- Migration is idempotent (uses
IF EXISTS,IF NOT EXISTS, checks column existence) - Migration preserves existing data (no
DROP TABLEwithout migration, noTRUNCATE) - Migration handles NULL values when adding NOT NULL columns
- Foreign key order is correct (referenced tables must exist)
- Index names are unique and follow naming convention
idx_{table}_{column}
Data Migration Checks:
- If removing a column, data is migrated to new location FIRST
- If changing column type, existing data is safely converted
- If adding constraints, existing data satisfies them
Read these files to verify:
/db/connection.py- Checkmigrate_db()function around line 89/db/connection.py- Checkinit_db()function around line 610/migrations/*.sql- Any new or modified migration files/schema.sql- Reference for full schema (not used in prod, but documents intent)
2. TYPE CONSISTENCY
If any changes to types, ensure they match across all layers:
Frontend Types → Backend:
/frontend/src/types/*.ts ←→ /db/validation.py (constants)
←→ /db/*.py (function signatures)
←→ /routes/*.py (response structures)
←→ /tools/*.py (MCP tool returns)
Check these specific mappings:
CaseStatusvalues in/frontend/src/types/common.tsmatchCASE_STATUSESin/db/validation.pyTaskStatusvalues matchTASK_STATUSESPersonTypevalues matchDEFAULT_PERSON_TYPESPersonSidevalues matchPERSON_SIDES
Property name consistency:
- Frontend uses camelCase OR snake_case? (This app uses snake_case throughout)
- JSONB fields (phones, emails, attributes) have matching structures
- Date fields use ISO string format (YYYY-MM-DD or full ISO timestamp)
3. API CONTRACT CONSISTENCY
If any changes to API endpoints or their responses:
REST Routes (/routes/*.py):
- Response structure matches frontend type definition
- Error responses use format:
{"success": false, "error": {"message": "...", "code": "..."}} - All routes have
auth.require_auth(request)check - Query params and body parsing matches frontend API calls
MCP Tools (/tools/*.py):
- Return same data structure as equivalent REST endpoint
- Tool parameters have correct types and descriptions
- Error handling uses
error_response(),validation_error(),not_found_error()helpers
Frontend API (/frontend/src/api/*.ts):
- Function signatures match route parameters
- Return types match actual response structure
- New functions are exported from
/frontend/src/api/index.ts
4. BUILD VERIFICATION
Run these commands:
# Frontend TypeScript check
cd frontend && npm run build
# If build fails, fix TypeScript errors before proceeding
Common build issues:
- Unused imports (remove them)
- Type mismatches (check property names, optional vs required)
- Missing exports from barrel files (index.ts)
5. EXPORTS AND IMPORTS
If adding new functions or types:
Database layer:
- New db functions exported from
/db/__init__.py - New db functions added to
__all__list
Frontend types:
- New types exported from
/frontend/src/types/{domain}.ts - New types re-exported from
/frontend/src/types/index.ts
Frontend API:
- New API functions exported from
/frontend/src/api/{domain}.ts - New API functions re-exported from
/frontend/src/api/index.ts
Backend routes:
- New route module registered in
/routes/__init__.py
Backend tools:
- New tool module registered in
/tools/__init__.py
6. BACKWARDS COMPATIBILITY
If changing existing APIs or data structures:
- Existing frontend code still works with new backend
- Existing data in database is still valid
- No breaking changes to MCP tools (Claude integrations depend on them)
- Consider adding new fields as optional first, then migrating
MIGRATION SAFETY PATTERNS
Safe: Adding a new nullable column
ALTER TABLE foo ADD COLUMN IF NOT EXISTS bar TEXT;
Safe: Adding a new table
CREATE TABLE IF NOT EXISTS foo (...);
Safe: Adding an index
CREATE INDEX IF NOT EXISTS idx_foo_bar ON foo(bar);
DANGEROUS: Removing a column
-- MUST migrate data first, then drop
INSERT INTO new_location SELECT ... FROM old_table WHERE old_column IS NOT NULL;
ALTER TABLE foo DROP COLUMN IF EXISTS bar;
DANGEROUS: Adding NOT NULL without default
-- This will fail if table has rows
ALTER TABLE foo ADD COLUMN bar TEXT NOT NULL;
-- Safe version:
ALTER TABLE foo ADD COLUMN bar TEXT;
UPDATE foo SET bar = 'default' WHERE bar IS NULL;
ALTER TABLE foo ALTER COLUMN bar SET NOT NULL;
DANGEROUS: Changing column type
-- Check that all existing values can convert
ALTER TABLE foo ALTER COLUMN bar TYPE INTEGER USING bar::INTEGER;
FINAL VERIFICATION
Before committing, confirm:
- Build passes:
cd frontend && npm run buildsucceeds - No console errors: Check browser console in dev mode
- Migration is safe: Will not corrupt or lose production data
- Types are consistent: Frontend types match backend responses
- Exports are complete: New code is properly exported
QUICK REFERENCE: Key Files by Domain
| Domain | DB | Routes | Tools | API | Types |
|---|---|---|---|---|---|
| Cases | /db/cases.py |
/routes/cases.py |
/tools/cases.py |
/frontend/src/api/cases.ts |
/frontend/src/types/case.ts |
| Persons | /db/persons.py |
/routes/persons.py |
/tools/persons.py |
/frontend/src/api/persons.ts |
/frontend/src/types/person.ts |
| Tasks | /db/tasks.py |
/routes/tasks.py |
/tools/tasks.py |
/frontend/src/api/tasks.ts |
/frontend/src/types/task.ts |
| Events | /db/events.py |
/routes/events.py |
/tools/events.py |
/frontend/src/api/events.ts |
/frontend/src/types/event.ts |
| Proceedings | /db/proceedings.py |
/routes/proceedings.py |
/tools/proceedings.py |
/frontend/src/api/proceedings.ts |
/frontend/src/types/proceeding.ts |
| Activities | /db/activities.py |
/routes/activities.py |
/tools/activities.py |
/frontend/src/api/activities.ts |
/frontend/src/types/activity.ts |
| Notes | /db/notes.py |
/routes/notes.py |
/tools/notes.py |
/frontend/src/api/notes.ts |
/frontend/src/types/note.ts |
| Jurisdictions | /db/jurisdictions.py |
/routes/stats.py |
/tools/jurisdictions.py |
/frontend/src/api/stats.ts |
/frontend/src/types/common.ts |
Validation constants: /db/validation.py
DB exports: /db/__init__.py
Migration logic: /db/connection.py (migrate_db ~line 89, init_db ~line 610)
SQL migrations: /migrations/*.sql
Now review the git diff and verify each changed file against these checks. Report any concerns before proceeding with the commit.