fix(directus): ticket invoice schema follow-up (user_created FK, read-only invoice links) - #257
claude[bot] wants to merge 2 commits into
Conversation
- Add the missing ticket_invoices.user_created -> directus_users FK and relation (ON DELETE NO ACTION, like every other user_created relation in the snapshot), so the acting admin on corrections/cancellations is a real, referentially intact relation. - Make the ticket_orders.invoices O2M read-only in the App: documents must never be detached from their order (the order FK is NOT NULL, so a "nullify" deselect could only fail) or re-linked to another order. - Mark the ticket_orders.invoice_number / invoice_file pointers as read-only with a note: they are still written and read by the bundle (current-document pointer, numbering, backfill) and must not be edited by hand. No fields or data are removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G9qwzY9WrCDrT5NX7zNP1E
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved approval-blocking issues remain.
Review effort: Lite
Findings: None
What changed in this PR
Updates the Directus invoice schema to preserve creator attribution and prevent unsafe manual invoice edits.
Changes:
- Adds the
user_createdforeign key and relation. - Makes invoice links and legacy invoice pointers read-only.
| File | Description |
|---|---|
directus-cms/schema.json |
Adds the creator relation and read-only invoice metadata. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Closing: schema changes should come from the Directus UI, not hand-edits of Generated by Claude Code |
Requested by Dennis Becker · Slack thread
Before: In production,
ticket_invoices.user_createdis a bare UUID. It has no foreign key and no relation todirectus_users, even though #248's hand-written snapshot declared one. In the App, theticket_orders.invoicesO2M can be edited. Deselecting an invoice would try to set itsorderto null, which fails because the column is NOT NULL. "Select existing" could move an invoice document to a different order. The legacy pointersticket_orders.invoice_numberandinvoice_filecan also be edited by hand, although the bundle maintains them (current-document pointer, invoice numbering, backfill).After:
ticket_invoices.user_createdgets a real FK and relation todirectus_users.id.ticket_orders.invoices,invoice_numberandinvoice_fileare read-only in the App, with notes explaining why. No fields, relations or data are removed.How: These are hand edits to
directus-cms/schema.jsonon top of the production snapshot from #251, in the same format:user_created/user_updatedrelations. It uses the same<table>_user_created_foreignnaming,one_deselect_action: nullifyandON DELETE NO ACTION.foreign_key_table/foreign_key_columnis set to match.readonlyin field meta only affects the App. The bundle writes these fields throughItemsService, and that keeps working.Depends on #251. This branch is based on #251's snapshot commit, so please merge #251 first; this diff then shrinks to the single commit here. After merging, run
directus schema applyagainst production.Before applying, check that there are no orphaned creator IDs, otherwise adding the FK fails:
SELECT count(*) FROM ticket_invoices t LEFT JOIN directus_users u ON u.id = t.user_created WHERE t.user_created IS NOT NULL AND u.id IS NULL;(expected result: 0)Validation:
schema apply --dry-runlists exactly these field and relation changes, plus two baseline items that the chore(directus): update production schema snapshot #251 snapshot also shows (asset_templates.variables_schemaandsocial_media_posts.tags"special → null"). These two are unrelated to this PR.ticket_invoices_user_created_foreign.Review points
orderis non-nullable while the O2M usesnullify. Instead of changing the deselect action (the only other option,delete, would be destructive), the O2M is now read-only, so documents can't be detached or re-linked. The DB-levelON DELETE NO ACTIONonorderstays. Blocking the deletion of an order that has invoices is intended.issueOriginalInvoice,generateInvoiceNumber, lifecycle regenerate, backfill). They are now read-only and labelled as maintained automatically.sent_atread-only. The ticket-order-processing hook's Slack alert tells admins to setsent_atmanually when stamping it fails after the email went out, so it has to stay editable in the App.user_createdusesON DELETE NO ACTION, notSET NULL. This matches every other user relation in the schema and keeps the audit attribution. A user who created invoice documents has to be suspended rather than hard-deleted.archive_app_filterwithout an archive field, the column nameorder, the index ontype,invoice_numberbeing required and read-only). They are cosmetic or would mean a disruptive rename.🤖 Generated with Claude Code
https://claude.ai/code/session_01G9qwzY9WrCDrT5NX7zNP1E
Generated by Claude Code