Problem
Radio-specific limits (max channels, zone member slots, channel name display length, feature availability) are intentionally kept off the internal model and enforced at the import/export boundary — see data-model, radio profiles, and the make-a-plan vendor-neutral rule.
That remains the direction of travel for hard enforcement. In practice, operators often target one or two known radios (e.g. Baofeng 1701 + OpenGD77) and only discover length/capacity problems at export time — frustrating when editing channels, zones, and TG lists in CRUD.
We need optional, non-blocking validation hints in the UI, driven by radios the operator selects for the project.
Intended outcome
Let operators select one or more target radio profiles on a codeplug project. Those profiles drive warning-level validation hints across edit forms, detail pages, and list views — without preventing save or mutating the internal model.
Design principles
| Layer |
Role |
| Internal model + CRUD validation |
Vendor-neutral; errors only (required fields, duplicate names, FK integrity, parse failures) — unchanged |
| Import/export adapters |
Hard limits — truncate, reject, or warn in export report — unchanged |
| Radio hint validation (new) |
Warnings only — highlight fields/rows that exceed selected profile constraints; operator may ignore |
Hints must never block addChannel / updateChannel / save. Export may still emit errors/truncation independently.
Data model — CodeplugProject
Add optional target radio selection on the project wrapper (not on Codeplug):
// Illustrative — final shape TBD
targetRadioProfileIds: string[] // e.g. ['opengd77:baofeng-1701']
Machine-readable profile constraints
Markdown radio profiles are authoritative for humans; validation needs a code registry mirroring them:
- e.g.
src/lib/radioProfiles/ — registry.ts + per-profile modules
- MVP: Baofeng 1701 constraints (channel name ~16 chars, 1023 channels, 80 zone members, 32 TG list members, feature flags)
- Each rule:
{ id, field, check(entity, codeplug), message(profileId) }
- Docs in
radioProfiles must stay in sync with docs/reference/opengd77/radios/*.md (mirror pattern: bands.ts ↔ bands.md)
Multi-profile semantics: when several radios are selected, run checks against each profile; surface combined warnings (e.g. "Exceeds 16-char LCD limit (1701)" / "Exceeds 16 scan members (DM32)"). A field fails hint if any selected profile is violated.
Validation engine
New module e.g. src/lib/validation/radioHints.ts:
| Function |
Purpose |
validateChannelHints(channel, profiles) |
Per-channel warnings |
validateZoneHints(zone, codeplug, profiles) |
Member count, unresolved names |
validateRxGroupListHints(list, profiles) |
Member count cap |
validateCodeplugHints(codeplug, profiles) |
Project-level: total channel count, aggregate caps |
bulkValidateCodeplug(codeplug, profiles) |
Full scan — used when profiles change |
Reuse existing ValidationIssue shape (severity: 'warning') from src/lib/validation/channel.ts.
Bulk re-validation: when targetRadioProfileIds changes, run bulkValidateCodeplug once and cache results on project context (or memoize per entity id) so list pages stay performant.
UI surfaces
| Surface |
Behaviour |
| Edit forms (channel, zone, RGL, …) |
Inline field warning (Mantine Input error/warning styles or Text c="orange") on blur/submit; save still allowed |
| Detail pages |
Warning badge or row highlight on offending fields; summary strip "2 radio compatibility warnings" |
| List pages |
Row indicator (icon/badge) when entity has hints; optional filter "show warnings only"; project-level banner when channel count exceeds cap |
| Summary (#61) |
Optional compatibility summary when profiles set |
Style hints as compatibility warnings (amber/outline) — not error red, not unread-notification badges (#81).
Export relationship
- Export continues to enforce/truncate per target format/profile at serialisation.
- Optionally pre-export report: "12 hints would become export errors for Baofeng 1701" — nice-to-have, not required for v1.
- Hint profiles and export format picker (#43 follow-up) may diverge — hints are project-level; export is per-session format choice. Document that hints are advisory for selected project radios, not a guarantee export passes.
Affected
src/models/codeplugProject.ts + storage migration
src/state/codeplugStore.tsx — updateProject, hint cache invalidation
src/lib/radioProfiles/ (new registry)
src/lib/validation/radioHints.ts
- Edit/detail/list routes: channels, zones, rx group lists (extend to contacts/TG as rules exist)
- Project edit UI (#60 or settings)
docs/features/codeplug-project/, docs/reference/opengd77/radios/, docs/features/crud/
- Tests: profile rule unit tests, bulk validation, UI smoke for warning display
Notes / dependencies
Out of scope
- Blocking save on hint violations.
- Storing radio-specific fields on
Channel / Zone entities.
- Auto-selecting target radios from import source (optional follow-up).
- Validating against every known OpenGD77 radio without operator selection.
Manual verify
- Project with no target radios → no hint UI (unchanged).
- Select Baofeng 1701 → channel name 20 chars → edit form warning; save succeeds.
- Detail + list show same warning for that channel.
- Zone with 85 members → zone list/detail warning (80 cap).
- Change target radios → bulk re-validation updates list indicators without reload.
- Export still produces CSV (may truncate per adapter).
Workflow note
Multi-commit feature: branch from origin/main, atomic conventional commits (profile registry → project field → hint engine → channel UI → zone/RGL → bulk refresh → docs/tests), PR linking Closes #.
Problem
Radio-specific limits (max channels, zone member slots, channel name display length, feature availability) are intentionally kept off the internal model and enforced at the import/export boundary — see data-model, radio profiles, and the make-a-plan vendor-neutral rule.
That remains the direction of travel for hard enforcement. In practice, operators often target one or two known radios (e.g. Baofeng 1701 + OpenGD77) and only discover length/capacity problems at export time — frustrating when editing channels, zones, and TG lists in CRUD.
We need optional, non-blocking validation hints in the UI, driven by radios the operator selects for the project.
Intended outcome
Let operators select one or more target radio profiles on a codeplug project. Those profiles drive warning-level validation hints across edit forms, detail pages, and list views — without preventing save or mutating the internal model.
Design principles
Hints must never block
addChannel/updateChannel/ save. Export may still emit errors/truncation independently.Data model —
CodeplugProjectAdd optional target radio selection on the project wrapper (not on
Codeplug):[](no hints — current behaviour).docs/reference/opengd77/radios/today; registry must allow future vendors (DM32 feat: DM32 stock CPS CSV import and export #67) without coupling internal models.Machine-readable profile constraints
Markdown radio profiles are authoritative for humans; validation needs a code registry mirroring them:
src/lib/radioProfiles/—registry.ts+ per-profile modules{ id, field, check(entity, codeplug), message(profileId) }radioProfilesmust stay in sync withdocs/reference/opengd77/radios/*.md(mirror pattern:bands.ts↔bands.md)Multi-profile semantics: when several radios are selected, run checks against each profile; surface combined warnings (e.g. "Exceeds 16-char LCD limit (1701)" / "Exceeds 16 scan members (DM32)"). A field fails hint if any selected profile is violated.
Validation engine
New module e.g.
src/lib/validation/radioHints.ts:validateChannelHints(channel, profiles)validateZoneHints(zone, codeplug, profiles)validateRxGroupListHints(list, profiles)validateCodeplugHints(codeplug, profiles)bulkValidateCodeplug(codeplug, profiles)Reuse existing
ValidationIssueshape (severity: 'warning') fromsrc/lib/validation/channel.ts.Bulk re-validation: when
targetRadioProfileIdschanges, runbulkValidateCodeplugonce and cache results on project context (or memoize per entity id) so list pages stay performant.UI surfaces
Inputerror/warning styles orText c="orange") on blur/submit; save still allowedStyle hints as compatibility warnings (amber/outline) — not error red, not unread-notification badges (#81).
Export relationship
Affected
src/models/codeplugProject.ts+ storage migrationsrc/state/codeplugStore.tsx—updateProject, hint cache invalidationsrc/lib/radioProfiles/(new registry)src/lib/validation/radioHints.tsdocs/features/codeplug-project/,docs/reference/opengd77/radios/,docs/features/crud/Notes / dependencies
baofeng-1701.mdconstraints.Out of scope
Channel/Zoneentities.Manual verify
Workflow note
Multi-commit feature: branch from
origin/main, atomic conventional commits (profile registry → project field → hint engine → channel UI → zone/RGL → bulk refresh → docs/tests), PR linkingCloses #.