# Unique ID Prefixes & Entity Renaming - Implementation Status ## Phase 1: ID Generation Infrastructure ✅ COMPLETE ### Completed Files - ✅ `/migrations/0009_id_sequences/up.sql` - Creates id_sequences table - ✅ `/migrations/0009_id_sequences/down.sql` - Rollback script - ✅ `/internal/idgen/generator.go` - ID generation service - ✅ `/internal/idgen/generator_test.go` - Comprehensive tests ### Verification - ✅ Migration applied successfully - ✅ All tests passing (including concurrency tests) - ✅ Manual verification complete - IDs generating correctly: - Customer: CR-0000003 - Project: PJ-0000003 - Asset: ME-0000004 - Component: PT-0000047 - Ticket: TT-0000002 - Failure Event: FE-0000001 ## Phase 2: Dual-Write Period ✅ COMPLETE ### Completed Files - ✅ `/migrations/0010_add_string_ids/up.sql` - Adds sid columns - ✅ `/migrations/0010_add_string_ids/down.sql` - Rollback script - ✅ **Migration Applied** - All existing data backfilled with formatted IDs - ✅ `/internal/domain/registry.go` - Updated all models (Customer, Project, Location, Lot, Asset, Component) - ✅ `/internal/domain/tickets.go` - Updated Ticket and TicketLink models - ✅ `/internal/domain/failure_events.go` - Updated FailureEvent model ### All Repositories Updated with Dual-Write - ✅ `/internal/repository/registry/customers.go` - Dual-write implemented - ✅ `/internal/repository/registry/projects.go` - Dual-write implemented - ✅ `/internal/repository/registry/locations.go` - Dual-write implemented - ✅ `/internal/repository/registry/lots.go` - Dual-write implemented - ✅ `/internal/repository/registry/assets.go` - Dual-write implemented (handles nullable location_sid) - ✅ `/internal/repository/registry/components.go` - Dual-write implemented (handles nullable lot_sid) - ✅ `/internal/repository/registry/installations.go` - Query updated to SELECT sid columns - ✅ `/internal/repository/tickets/tickets.go` - Upsert and LinkToAsset updated - ✅ `/internal/repository/failures/failures.go` - Upsert updated (handles nullable asset_sid) ### Verification Completed - ✅ Migration 0010 applied successfully - ✅ All existing data backfilled with formatted IDs (CR-0000001, PJ-0000001, etc.) - ✅ All code compiles without errors - ✅ Database schema verified with sid columns present ### API Layer Status - ⚠️ **Not required** - User confirmed backwards compatibility not needed - New records will have both `id` (int) and `sid` (string) in JSON responses - Future work: Can transition API to use string IDs as primary identifiers ## Phase 3: Entity Renaming ⏳ NOT STARTED **Breaking changes - requires maintenance window** - Rename tables: `assets` → `machines`, `components` → `parts` - Rename columns: `asset_id` → `machine_id`, `component_id` → `part_id`, `asset_tag` → `machine_tag` - Update all foreign keys - Rename Go types and files - Update API routes with redirects - Update UI templates ## Phase 4: Switch to String IDs Primary ⏳ NOT STARTED **Breaking changes - requires maintenance window** - Drop integer `id` columns - Promote `sid` to `id` - Update all foreign keys - Remove dual-write logic ## Phase 5: Cleanup ⏳ NOT STARTED - Remove temporary columns/indexes - Remove deprecated routes - Optimize indexes ## Pattern for Repository Updates Each repository needs this pattern: ```go // 1. Add to imports import "reanimator/internal/idgen" // 2. Update struct type XRepository struct { db *sql.DB idgen *idgen.Generator } // 3. Update constructor func NewXRepository(db *sql.DB) *XRepository { return &XRepository{ db: db, idgen: idgen.NewGenerator(db), } } // 4. Update Create() - example for projects func (r *XRepository) Create(ctx context.Context, ...) (domain.X, error) { // Generate SID sid, err := r.idgen.Generate(ctx, idgen.EntityType) if err != nil { return domain.X{}, err } // Lookup foreign key SIDs (if needed) var foreignSID string err = r.db.QueryRowContext(ctx, `SELECT sid FROM foreign_table WHERE id = ?`, foreignID).Scan(&foreignSID) if err != nil { return domain.X{}, classifyError(err) } // INSERT with both id (auto-increment) and sid result, err := r.db.ExecContext(ctx, `INSERT INTO table (sid, foreign_id, foreign_sid, ...) VALUES (?, ?, ?, ...)`, sid, foreignID, foreignSID, ..., ) // ... rest of create logic } // 5. Update all SELECT statements to include sid and *_sid columns // 6. Update all Scan() calls to include the new fields ``` ## Next Steps 1. **Complete Phase 2 repository updates** (7 more repositories) 2. **Update API layer** to accept both ID formats 3. **Apply migration 0010** 4. **Test dual-write** functionality 5. **Verify** both integer and string IDs work in API ## Migration Commands ```bash # Apply Phase 2 migration docker exec -i reanimator-mariadb mariadb -u reanimator -preanimator reanimator < migrations/0010_add_string_ids/up.sql # Rollback if needed docker exec -i reanimator-mariadb mariadb -u reanimator -preanimator reanimator < migrations/0010_add_string_ids/down.sql ``` ## Testing After Phase 2 ```bash # Run all tests go test ./... # Test ID generation go test ./internal/idgen/... -v # Create a customer via API curl -X POST http://localhost:9999/customers -d '{"name": "Test Corp"}' # Should return: {"id": 4, "sid": "CR-0000004", ...} # Verify database docker exec -i reanimator-mariadb mariadb -u reanimator -preanimator reanimator -e "SELECT id, sid, name FROM customers LIMIT 5" ```