Appearance
Runbook: Add messages.temp_id Column
This migration adds the temp_id column and its partial unique index to communications.messages. It is required for the outbound messaging feature — without it, idempotency enforcement does not exist and the persistence layer cannot store the client-side tempId.
When to run
Before deploying the build that includes outbound messaging (comunications-outbound-iter2).
The migration is ADDITIVE and NON-DESTRUCTIVE:
- Adds a nullable
textcolumn — all existing rows getNULL, which is valid. - Adds a partial unique index that excludes
NULLvalues — inbound messages (which have notempId) are unaffected.
No existing data is modified or deleted.
Step 1 — Generate the migration
bash
pnpm --filter api migration:generate communications/AddMessageTempIdColumnThis command reads the TypeORM entity diff and generates a timestamped migration file at:
apps/api/src/modules/communications/infrastructure/migrations/<timestamp>-AddMessageTempIdColumn.tsStep 2 — Review the generated SQL
The expected SQL is:
sql
ALTER TABLE communications.messages ADD COLUMN temp_id text NULL;
CREATE UNIQUE INDEX uq_messages_conversation_temp_id
ON communications.messages (conversation_id, temp_id)
WHERE temp_id IS NOT NULL;Verify:
- No
NOT NULLconstraint (would fail on existing rows). - The index has
WHERE temp_id IS NOT NULL(partial — inbound message rows must not conflict). - No other unexpected changes (only these two statements should be present).
Step 3 — Apply the migration
bash
pnpm --filter api migration:runVerify the migration completes without errors.
Step 4 — Verify
sql
-- Connect to the database and confirm:
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'communications'
AND table_name = 'messages'
AND column_name = 'temp_id';
-- Expected: column_name=temp_id, data_type=text, is_nullable=YES
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'communications'
AND tablename = 'messages'
AND indexname = 'uq_messages_conversation_temp_id';
-- Expected: partial unique index with WHERE (temp_id IS NOT NULL)Rollback
If a rollback is needed:
sql
DROP INDEX IF EXISTS communications.uq_messages_conversation_temp_id;
ALTER TABLE communications.messages DROP COLUMN IF EXISTS temp_id;This is safe — the column and index are only used by the outbound messaging feature.
Notes
- Migration generation is a developer/operator task. It is NOT automated by the CI pipeline.
- The TypeORM entity (
MessagePersistence) already includes the@Columndecorator fortempId. The migration will reflect this diff. - The partial unique index is NOT expressible via TypeORM's
@Uniquedecorator alone — verify that the generated migration correctly includes theWHEREclause before applying.