Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 48 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ If ANY test fails (even outside your changes), you MUST fix it before creating t
See `docs/MODELS.md` for complete specifications. Key models:

### User & Ownership
- `User` - Rails 8 authentication, owns codeplugs
- `User` - Rails 8 authentication, owns codeplugs and zones
- `Codeplug` - User's complete radio configuration (can be public/private)
- `Zone` - Standalone template owned by user (can be public/private)

### Radio Hardware (Shared/Universal)
- `Manufacturer` - Radio manufacturers (Motorola, Baofeng, etc.)
Expand All @@ -94,19 +95,24 @@ See `docs/MODELS.md` for complete specifications. Key models:
- `Network` - Talkgroup organization (Brandmeister, DMRVA, etc.)
- `TalkGroup` - Digital radio talkgroup

### Join Tables with Metadata
- `SystemNetwork` - Systems can be on multiple networks
- `SystemTalkGroup` - Talkgroup + timeslot per system
- `ChannelZone` - Channel position within zone
### Zone Architecture (Template-Based)
- `Zone` - Standalone template defining systems/talkgroups (owned by user, public/private)
- `ZoneSystem` - Systems in a zone (with position)
- `ZoneSystemTalkGroup` - Talkgroups for digital systems in a zone
- `CodeplugZone` - Links zones to codeplugs (with position)

### User's Configuration
- `Zone` - Logical grouping of channels (unlimited size in app)
- `Channel` - User's configuration to access a System (references System + adds settings)
### Channel Management
- `Channel` - Generated from zones or manually created (has `source_zone_id` for tracking)
- `ChannelZone` - Channel position within zone
- `SystemTalkGroup` - Talkgroup + timeslot per system

### Key Relationships
- Zone → ZoneSystem → ZoneSystemTalkGroup (defines what to generate)
- Codeplug → CodeplugZone → Zone (links zones to codeplugs)
- Channel → System (pulls in frequencies, tones)
- Channel → SystemTalkGroup (for digital: talkgroup + timeslot)
- Channel ↔ Zone (many-to-many with position)
- Channel → source_zone (tracks which zone generated this channel)
- Channel ↔ Zone via ChannelZone (many-to-many with position)
- System → ModeDetail (polymorphic: analog/DMR/P25/etc.)

---
Expand All @@ -117,7 +123,8 @@ See `docs/MODELS.md` for complete specifications. Key models:
- Complex multi-step operations
- CSV export/import logic
- Orchestrating multiple models
- Example: `CodeplugExporter`, `CsvImporter`
- Channel generation from zones
- Example: `ChannelGenerator`, `CodeplugExporter`, `CsvImporter`

### When to Use Form Objects
- Forms spanning multiple models
Expand Down Expand Up @@ -216,6 +223,35 @@ end

## Important Business Logic

### Zone Workflow (Template-Based Architecture)
Zones are standalone templates that define what channels should be generated:

1. **Create Zone**: User creates a zone (private by default, can be made public)
2. **Add Systems**: User adds systems to the zone via ZoneSystem
3. **Add Talkgroups**: For digital systems, user adds talkgroups via ZoneSystemTalkGroup
4. **Add to Codeplug**: User adds zones to codeplug via CodeplugZone
5. **Generate Channels**: User clicks "Generate Channels" to create channels from zones
6. **Customize**: User can edit generated channels (changes persist until regeneration)

### Channel Generation Logic
The `ChannelGenerator` service creates channels from zones:
- **Analog systems**: Creates one channel per system
- **Digital systems**: Creates one channel per ZoneSystemTalkGroup
- Sets `source_zone_id` to track which zone generated the channel
- Creates `ChannelZone` records with sequential positions
- With `regenerate: true`: Destroys existing channels first

```ruby
generator = ChannelGenerator.new(codeplug)
result = generator.generate_channels(regenerate: false)
# => { channels_created: 5, zones_processed: 2, skipped: false }
```

### Public vs Private Zones
- Private zones: Only owner can view/edit/use
- Public zones: Any user can view and add to their codeplugs
- Use `Zone.available_to_user(user)` scope to get zones a user can see

### Polymorphic Mode Details
Systems have different attributes based on mode:
- **DMR**: color_code (0-15)
Expand All @@ -229,6 +265,7 @@ Use polymorphic association: `System belongs_to :mode_detail, polymorphic: true`
- Channel references a **System** (gets frequencies, tones)
- For digital systems, Channel references **SystemTalkGroup** (includes timeslot)
- Channel adds user preferences (power, bandwidth override, tone_mode)
- Channel has `source_zone_id` if it was generated from a zone

### Tone Handling
- System has `tx_tone_value` and `rx_tone_value` (CTCSS/DCS codes)
Expand Down Expand Up @@ -572,4 +609,4 @@ When helping with this project:

---

**Last Updated**: 2025-11-01
**Last Updated**: 2025-12-17
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,22 @@ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for detailed architectural deci
The application manages several key entities:

- **Codeplugs**: User's complete radio configuration
- **Channels**: Individual channel configurations referencing systems
- **Zones**: Logical groupings of channels (unlimited in app, split on export)
- **Systems**: Repeater/simplex frequencies with technical specs
- **Zones**: Standalone templates defining systems and talkgroups (public/private)
- **Channels**: Generated from zones or manually created
- **Systems**: Repeater/simplex frequencies with technical specs (shared resource)
- **TalkGroups**: Digital radio talkgroup definitions organized by networks
- **Radio Models**: Radio hardware specifications and capabilities
- **Codeplug Layouts**: CSV export format definitions for specific radios

### Zone Architecture

Zones use a template-based approach:
- Zones are **standalone entities** owned by users (not embedded in codeplugs)
- Zones can be **public** (shareable) or **private**
- Zones define which **systems** and **talkgroups** to include
- Channels are **generated** from zones when the user is ready
- Generated channels can be **customized** (changes persist until regeneration)

See [docs/MODELS.md](docs/MODELS.md) for complete data model documentation.

## Requirements
Expand Down Expand Up @@ -87,6 +96,11 @@ The seed data creates:
- 1 development user account
- 10 radio manufacturers
- 10 realistic radio models with specifications
- Sample networks (Brandmeister, TGIF, P25 Network)
- Sample systems (analog and DMR repeaters)
- Sample talkgroups
- Sample zones with systems and talkgroups
- Sample codeplug with generated channels

### 5. Start Development Server

Expand Down Expand Up @@ -253,15 +267,33 @@ rails db:rollback

## User Workflows

### Creating a Codeplug
### Creating Zones (Templates)

1. User registers/logs in
2. Creates a new Codeplug
3. Adds Systems (repeaters) with location and technical specs
4. Creates Channels referencing Systems
5. Organizes Channels into Zones
2. Navigates to "Zones" in the navigation menu
3. Creates a new Zone (name, optional long/short names)
4. Adds Systems to the zone (analog repeaters, DMR repeaters, etc.)
5. For digital systems, adds Talkgroups (with timeslot info)
6. Optionally marks the zone as "Public" to share with other users

### Creating a Codeplug

1. User creates a new Codeplug
2. Adds Zones to the codeplug (own zones or public zones from other users)
3. Reorders zones as desired using drag-and-drop
4. Clicks "Generate Channels" to create channels from the zone templates
5. Optionally customizes generated channels (name, power level, etc.)
6. Exports Codeplug for specific Radio Model

### Regenerating Channels

If you modify zones (add systems/talkgroups) after generating channels:
1. Navigate to the codeplug
2. Click "Regenerate Channels"
3. Confirm the regeneration (existing channels will be replaced)
4. New channels are generated from the updated zone templates
5. Any previous customizations will be lost

### Exporting to Radio Format

1. User selects Codeplug to export
Expand Down Expand Up @@ -430,4 +462,4 @@ Built with:

**Version**: 0.1.0 (Initial Development)

**Last Updated**: 2025-11-01
**Last Updated**: 2025-12-17
3 changes: 2 additions & 1 deletion app/views/codeplugs/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="card-title mb-0">Standalone Zones</h5>
<h5 class="card-title mb-0">Zones</h5>
<small class="text-muted">Templates that define what channels to generate</small>
</div>

<%# Add zone form %>
Expand Down
13 changes: 12 additions & 1 deletion app/views/zones/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
<%= form_with model: zone do |f| %>
<div class="alert alert-info mb-4">
<strong>What is a Zone?</strong>
<p class="mb-0 mt-1">
Zones are templates that define which systems (repeaters) and talkgroups you want on your radio.
After creating a zone, you'll add systems to it, then add the zone to your codeplug to generate channels.
</p>
</div>

<% if zone.errors.any? %>
<div class="alert alert-danger">
<h5><%= pluralize(zone.errors.count, "error") %> prohibited this zone from being saved:</h5>
Expand Down Expand Up @@ -32,7 +40,10 @@
<div class="form-check">
<%= f.check_box :public, class: "form-check-input" %>
<%= f.label :public, "Make this zone public", class: "form-check-label" %>
<div class="form-text">Public zones can be viewed by all users. Private zones are only visible to you.</div>
<div class="form-text">
Public zones can be viewed and added to codeplugs by any user.
This is useful for sharing commonly used repeater groups with the community.
</div>
</div>
</div>

Expand Down
Loading