feat(jira): mirror the board's own columns instead of asking for a mapping - #6720
Merged
Conversation
…pping The last piece: an org whose board is its own gets its columns from Jira, under the names its team gave them, with each card in the column Jira puts it in. Both come from one call. `getBoardColumns` already returns each column with the statuses it groups — Jira knows the mapping, so it is read rather than configured. That the mapping screen ever existed is the mistake this removes: it asked a team to restate, by hand and per lane, something their tracker already knew, and it is what made our vocabulary leak into everything downstream. `replaceAll` now keeps a column the tracker dropped when it still holds cards, appended after the mirrored set. That is the obligation the foreign key created, and honouring it is better than the alternatives: RESTRICT refuses the delete, and moving someone's cards to a column Studio picked is a worse answer than showing a column their tracker no longer has. It leaves on its own once the last card is out. Studio's own board is untouched: it still reads the hand-written mapping, since its lanes are ours and Jira has no idea what they mean.
decocms Bot
pushed a commit
that referenced
this pull request
Aug 28, 2026
PR: #6720 feat(jira): mirror the board's own columns instead of asking for a mapping Bump type: minor - decocms (apps/api/package.json): 4.300.0 -> 4.301.0 - @decocms/native (apps/native/package.json): 4.300.0 -> 4.301.0 Deploy-Scope: server
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last piece. An org whose board is its own now gets its columns from Jira, under the names its team gave them, with each card in the column Jira puts it in.
Both halves come from one call:
Jira already knows the mapping. That the mapping screen ever existed is the mistake this removes: it asked a team to restate, by hand and per lane, something their tracker already knew — and it is what made Studio's vocabulary leak into everything downstream, including the agent.
Studio's own board is untouched. It still reads the hand-written mapping, because its lanes are ours and Jira has no idea what they mean.
Honouring the foreign key, not working around it
replaceAllnow keeps a column the tracker dropped when it still holds cards, appended after the mirrored set.That is the obligation
ON DELETE RESTRICTcreated, and I said in #6710 that writing this sync without it would break production the first time someone tidied their Jira board. The alternatives are worse: RESTRICT refuses the delete outright, and relocating someone's cards to a column Studio picked is a worse answer than showing a column their tracker no longer has. It leaves on its own on the first sync after the last card is out.One implementation detail worth a reviewer's eye: I first made the delete a
not in [...kept, sentinel]to keep the list non-empty, using a NUL byte as the sentinel. Postgres rejects NUL in text, which the tests caught. It builds an explicit drop list now and skips the statement when it is empty — a sentinel there was a bad idea regardless of the encoding.How did you verify your code works?
The case the whole design turns on, against real Postgres: a dropped column that still holds cards survives, and disappears once emptied. Both halves in one test, because either alone passes a broken implementation — keeping forever, or dropping immediately.
apps/api/src: 4051 pass / 49 fail against a baseline of 4050 / 49, measured by checking outorigin/main's tree, re-running, and restoring. Same failures, one more test. (My first attempt at that measurement was worthless — I had already committed, so the stash was empty and I compared the change to itself. Worth saying because the number looked fine either way.)Every
*.integration.test.tsundertools/task-board,storageandjiraalso run individually infind | sortorder, the way CI runs them: all green.bun run check0 errors,lintat baseline,knipclean.Not verified, flagging honestly:
getBoardColumnscall and areplaceAll; the storage half is covered, the client call is not, and the suite has no fake Jira. The first real sync on an org board is genuinely the first run.board_column_orgis still never written, so the foreign key still sleeps even for these cards. That is the next thing, and until it lands the FK is protection we have paid for and are not using.in_reviewroles are still inert — settable since feat(task-board): let a column say what it means #6718, read by nothing.Screenshots/Demonstration
Not captured. With
org_board_columnsoff — every org today — the sync behaves exactly as before.How to Test
org_board_columnson, run a sync, and confirm the board shows that Jira board's columns, in its order, with its names.Migration Notes
None. No schema change.
status_mappingis still read for Studio's own board and is untouched; it becomes dead only once every Jira org is on its own board.Review Checklist
Summary by cubic
Org-owned boards now get their columns read from Jira instead of asking teams to hand-maintain a status mapping, placing each card in the column Jira's board config assigns its status. With the
org_board_columnsflag off, the hand-written mapping still drives everything, and Studio's own board is untouched.New Features
ON DELETE RESTRICTforeign key.Written for commit f9002bb. Summary will update on new commits.