fix(migrations): add missing 0127_workitemfield_external_ids + idempotent custom-field token API#20
Merged
Conversation
…ken API
The public token custom-field API (/api/v1/.../projects/<id>/fields/)
already existed but lacked the external-id idempotency convention every
other tick_client write uses (Issue: GET-then-create / 409+id). External
agents' ensure_* therefore couldn't safely create field/option schema.
Mirror the Issue pattern exactly:
- WorkItemField + WorkItemFieldOption: add external_source/external_id
CharField(255, null, blank) (identical decl to Issue/IssueType).
Migration 0127, additive + nullable, no data migration. (Value layer
unchanged: PUT upsert is already idempotent via the (issue,field)
unique key.)
- Token serializers expose external_source/external_id (writable).
- WorkItemFieldListAPIEndpoint / WorkItemFieldOptionListAPIEndpoint:
GET ?external_source=&external_id= single lookup (mirrors Issue list);
POST returns 409 + {error, id:<existing>} when the external keys
already exist (mirrors Issue create), scoped to project / field.
Pre-existing automation RenameIndex drift detected by makemigrations is
deliberately excluded from 0127 (not ours; documented in the migration).
Verified end-to-end on the local stack: 15/15 acceptance probes pass
(LD_Offset number create/list/set-value/read + idempotent 409+id; Tier
single_select + PS/S/A/B options idempotent). No new migration on the
prod line beyond 0127; frontend untouched.
4 tasks
ruff check enforces 120-char max on apps/api; the inline 123-char error string in WorkItemFieldOptionListAPIEndpoint POST tripped Lint API CI. Wrap into a multi-line string literal — no behavior change.
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.
Why (urgency)
origin/previewis currently in a broken migration state:0128_apiactivitylog_on_behalf_of.pyalready declaresdependencies = [('db', '0127_workitemfield_external_ids')]0127_workitemfield_external_ids.pyitself was never merged topreviewpython manage.py migratefrompreviewfails on missing migrationProduction isn't seeing this because the
lark-stableimage lane is built fromfeature/lark-oauth-provider, which carries0127. This PR restores parity sopreviewactually applies.What
Cherry-picks commit
f29db3d9f8from the (never-pushed-as-its-own-PR) local branchfeature/customfield-api-idempotency. Backend-only change, no frontend touched.0127_workitemfield_external_ids— addsexternal_sourceandexternal_idnullable CharFields + composite unique constraint onWorkItemField(mirrors the same pattern Issue already uses for external import idempotency).WorkItemFieldSerializer/WorkItemFieldOptionSerializerexposeexternal_sourceandexternal_idas writable fields.WorkItemFieldListAPIEndpointandWorkItemFieldOptionListAPIEndpoint:GET ?external_source=&external_id=returns the single existing record (mirrors Issue list endpoint).POSTreturnsHTTP 409 + {"error": "...", "id": "<existing-uuid>"}when both external keys already exist for the same project+field scope. Lets idempotent re-imports converge without surprise duplicates.Files
Test plan
python manage.py migratefrom a clean preview-based DB now applies 0127 → 0128 in sequence (the bug)0126_project_personal(it does — verified in file header)Note on the automation-RenameIndex drift
makemigrationson this codebase also flags two pre-existingRenameIndexdrifts onautomationrule/automationruleruntables. Those are unrelated upstream drifts and are deliberately excluded from 0127 — scope of this migration is strictly theWorkItemFieldexternal-id keys. See note in the migration file.