You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Get the internal codeplug model to a pristine, format- and radio-agnostic state ahead of the MVP import → modify → export → write-to-radio loop, without regressing the OpenGD77/Baofeng 1701 round-trip. Radio-specific wire mapping is the adapter's job; the internal model owes nothing to any vendor. This is the umbrella for the data-model refactor that pays down OpenGD77 leakage so adding a second radio/format later is cheap.
Also folded in under this epic (no separate child tickets): convert FKs to UUID (discriminated { kind: 'talkGroup' | 'contact'; id } refs), and move import provenance into per-entity meta + rename vendorExtras → opengd77Extras.
Locked decisions
Delivered as a phased epic across separate agent sessions; each phase is its own subplan + branch + PR, merged to main sequentially.
Dual-kind FK = discriminated ref { kind: 'talkGroup' | 'contact'; id }; TalkGroup and Contact stay separate entities.
scanSkip first-class; zoneSkip stays an OpenGD77 extra.
Field types: frequencies as integer Hz; power / squelch as percent with null = master; tones as a CTCSS/DCS string enum; colourCode / timeslot / dmrId / transmitTimeout nullable numbers/enums; rxOnly boolean.
aprsConfigName stays a string FK until APRS is modelled.
Vendor cardinality/limits belong at export only — never in model / mutations / validation / CRUD UI.
Epic
Get the internal codeplug model to a pristine, format- and radio-agnostic state ahead of the MVP import → modify → export → write-to-radio loop, without regressing the OpenGD77/Baofeng 1701 round-trip. Radio-specific wire mapping is the adapter's job; the internal model owes nothing to any vendor. This is the umbrella for the data-model refactor that pays down OpenGD77 leakage so adding a second radio/format later is cheap.
Planning input / findings:
docs/features/data-model/vendor-agnostic-review.mdDefinition of done
metafield, not in load-bearing model fields.Channel.numberis gone from the model and assigned at OpenGD77 export.vendorExtrasrenamed toopengd77Extras; vendor specifics live only at the adapter.In-scope tickets
Channel.number, assign at exportAlso folded in under this epic (no separate child tickets): convert FKs to UUID (discriminated
{ kind: 'talkGroup' | 'contact'; id }refs), and move import provenance into per-entitymeta+ renamevendorExtras→opengd77Extras.Locked decisions
mainsequentially.{ kind: 'talkGroup' | 'contact'; id };TalkGroupandContactstay separate entities.scanSkipfirst-class;zoneSkipstays an OpenGD77 extra.power/squelchas percent withnull= master; tones as a CTCSS/DCS string enum;colourCode/timeslot/dmrId/transmitTimeoutnullable numbers/enums;rxOnlyboolean.aprsConfigNamestays a string FK until APRS is modelled.Phases
Channel.number(refactor: drop channel number from internal model (assign at export) #53).meta+opengd77Extrasrename.Each phase bumps
CODEPLUG_SCHEMA_VERSIONwith a migration + fixture.Tracking docs
docs/features/data-model/pristine-model-refactor-progress.mddocs/features/data-model/pristine-model-refactor-outstanding.mdRelated / out of scope