Create, edit, and delete codeplug entities against the internal vendor-neutral model, with validation and reference consistency on rename/delete.
Tracking: codeplug-tool#11 · #12 · #13 · #14
| Area | Status | Notes |
|---|---|---|
| Channel CRUD | Complete | src/routes/channels/ — multi-mode editor (#46); ukrepeater (#92); BrandMeister (#167); duplicate (#179) |
| Zone CRUD | Complete | src/routes/zones/ + ZoneMemberPicker; zone from distance (#180); duplicate (#179) |
| Talk group CRUD | Complete | TalkGroupEdit, list/detail; duplicate (#179) |
| RX group list CRUD | Complete | RxGroupListEdit, RxGroupListMemberPicker; duplicate (#179) |
| Contact CRUD | Complete | ContactEdit, list/detail; duplicate (#179) |
| Member picker labels | Complete | Callsign in zone picker; DMR ID in RGL picker (#182) |
| Store mutations | Complete | codeplugMutations.ts, codeplugStore |
| Validation | Complete | src/lib/validation/ |
| Channel merge candidates | Complete | #116 — post-hoc multi-mode merge detection and apply |
| Talk group merge candidates | Complete | #142 — collapse per-slot TG duplicates import missed |
| RX group list member timeslots | Complete | #142 — per-member slot on RxGroupListMember |
Internal models, mutations, validation, and CRUD UI are vendor-neutral — no radio profile constants or member-count caps. Cardinality limits and vendor column mapping apply at the import/export boundary only. See AGENTS.md — Vendor boundaries and data-model.
TG/RGL/contact CRUD follows the same rule: unlimited RGL members in the internal model; export may truncate per radio profile.
| Doc | Role |
|---|---|
| crud-progress.md | Shipped slices and verify steps |
| crud-outstanding.md | Debt discovered during execution |
| channel-merge-candidates-progress.md | Channel merge candidates (#116) |
| channel-merge-candidates-outstanding.md | Merge candidates follow-ups |
| data-model | Entity shapes |
| bands reference | UK band ranges and pill colours |
| maidenhead | Locator conversion behaviour |
| report | Read-only list/detail pages extended by CRUD |
| repeater-directories | ukrepeater.net (#92); BrandMeister (#167) |
- Internal FKs: Zone membership uses
memberChannelIds(UUIDs). Channels usecontactRef(EntityRef | null) andrxGroupListId. RX group lists store orderedmemberRefs(EntityRef[]). Wire names from import live inmeta.importedprovenance only. - Rename/delete propagation: Mutations clear or update id-based refs when a talk group, contact, or RX group list is deleted; renames do not rewrite channel refs (ids are stable).
- Shared contact namespace:
TalkGroup.nameandContact.namemust be unique across both arrays (display/export label invariant). - Export round-trip: The export adapter serialises wire strings per target format; cardinality limits apply at export per radio profiles.
| Path | Page |
|---|---|
/channels/add-from-ukrepeater |
Search ukrepeater.net and add channels (#92) |
/channels/add-from-brandmeister |
Search BrandMeister and add DMR channels (#167) |
/channels/new |
Create channel |
/channels/:id/edit |
Edit channel |
/channels/:id |
Detail + edit/duplicate/delete |
/zones/from-distance |
Build a zone from channels within range (#180) |
/zones/new |
Create zone |
/zones/:id/edit |
Edit zone + members |
/zones/:id |
Detail + edit/duplicate/delete |
/talk-groups/new |
Create talk group |
/talk-groups/:id/edit |
Edit talk group |
/talk-groups/:id |
Detail + edit/duplicate/delete |
/rx-group-lists/new |
Create RX group list |
/rx-group-lists/:id/edit |
Edit list + members |
/rx-group-lists/:id |
Detail + edit/duplicate/delete |
/contacts/new |
Create contact |
/contacts/:id/edit |
Edit contact |
/contacts/:id |
Detail + edit/duplicate/delete |
- Import / export
- Branch:
13/paddy/tg-rgl-contacts-crud