Skip to content

Conversation

@b3p3k0
Copy link

@b3p3k0 b3p3k0 commented Nov 25, 2025

What does this PR do?

following up on your reddit thread and our discussions, creates a basic webui (local only, no auth or TLS support etc) using the exposed API endpoints.

I've done minimal testing in ubuntu 24.04 LTS and using a nooelec dongle with a short hwip antenna.

Issue link

https://www.reddit.com/r/vibecoding/comments/1p33nbo/interested_in_vibecoding_a_frontend/

Checklist before merging

  • My commit history follows the conventional commits specification
  • Each commit represents a single, coherent unit of work
  • [x ] My changes are covered by unit tests
  • [ x] Unit tests successfully run locally
  • I have formatted Python code with black
  • I have checked static type hinting with mypy
  • [x ] I have added/updated necessary documentation, if required
  • I have checked for and resolved any merge conflicts
  • [x ] I have performed a self-review of my code

Additional notes

based off a quick weekend "vibecode" request; submitted with missing ticks per our convo

b3p3k0 and others added 29 commits November 22, 2025 17:19
Implement browser-based interface for recording spectrograms and viewing
saved PNG captures with enhanced gallery features.

**Frontend (React + Vite):**
- RecordingForm component with real-time status updates
- SavedSpectrograms gallery with thumbnail grid and lightbox
- Metadata parsing (timestamp, tag) from filenames
- Download buttons for individual PNG files
- Refresh functionality to reload recordings list
- Responsive design for mobile and desktop

**Backend fixes:**
- Return relative URLs instead of absolute in Flask routes
- Prevents Docker internal hostname issues in browser
- Applied to batches.py, logs.py, and configs.py

**Infrastructure:**
- Production nginx config with priority prefix matching (^~)
- Fixes static file caching interference with API proxying
- Docker Compose entrypoint override for proper bash execution
- Documentation in DOCKER_TROUBLESHOOTING.md for debugging

**Key improvements:**
- Images load correctly through nginx proxy
- Download functionality with event propagation handling
- High-contrast lightbox for spectrogram viewing
- JSend-compliant API error handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add localStorage persistence to the profile dropdown in RecordingForm so the user's selected configuration tag is remembered between page reloads and browser sessions. Includes validation to clear invalid persisted values if the config no longer exists.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Remove the inline PNG preview that appeared after recording completion. Users can now view recordings exclusively through the gallery, providing a cleaner interface and avoiding duplication.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Enhances the web UI with two key improvements:

1. **Extended timeout support for long recordings**
   - Add 15-minute timeout to nginx proxy for /recordings endpoint
   - Implement AbortController-based timeout in frontend API client
   - Set 900s timeout on recordSignal() and recordSpectrogram() methods
   - Enables recordings up to 14+ minutes without timeout errors

2. **Sort toggle for saved spectrograms gallery**
   - Add sort button to toggle between newest/oldest first
   - Sort by filename (contains sortable YYYYMMDD_HHMMSS format)
   - No parsing needed - uses simple string comparison
   - Responsive design with mobile support

Technical details:
- nginx.conf: Add proxy_read_timeout, proxy_connect_timeout, proxy_send_timeout
- apiClient.js: Implement timeout parameter with AbortController
- SavedSpectrograms.jsx: Add sortOrder state and getSortedRecordings()
- main.css: Add .gallery-controls and .sort-button styles

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implements a complete dark mode theme with toggle button and persistence.

Features:
- CSS variables-based theming system for easy maintenance
- Dark mode toggle button in header (☀️ Light / 🌙 Dark)
- localStorage persistence - preference survives browser sessions
- Smooth 0.3s transitions between themes
- All components adapted: sections, cards, forms, gallery, lightbox

Color scheme:
- Light: White backgrounds (#fff, #f5f5f5), dark text (#333)
- Dark: Dark backgrounds (#1a1a1a, #2d2d2d), light text (#e0e0e0)
- Purple gradient slightly muted in dark mode for eye comfort

Technical implementation:
- CSS custom properties (:root and body.dark-mode)
- React state with localStorage initialization
- useEffect to apply/remove dark-mode class on body
- Toggle button positioned absolutely in header

Resolves eye strain from prolonged use of light theme.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Enables users to view, create, edit, and delete receiver configurations via the Web UI.

- Add ConfigManager React component with list, view, edit, create, and delete modes
- Extend apiClient.js with config management and receiver API methods
- Add comprehensive styling with dark mode support and responsive design
- Integrate ConfigManager into main app layout between recording form and gallery

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Tightens spacing throughout the UI and combines recording form with config manager for better workflow.

- Reduce padding across all sections for more professional appearance
- Combine recording form and config manager into single 2-column section (desktop)
- Add responsive stacking for mobile devices (1-column layout)
- Add /receivers endpoint proxy to Nginx configuration
- Fix config dropdown synchronization via callback mechanism
- Create, edit, and delete operations now update recording form dropdown automatically

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replace infinitely expanding card grid with fixed-height scrollable table
to prevent page layout shifts as configurations are added.

Changes:
- Replace card grid with HTML table structure (Tag | Receiver | Mode | Actions)
- Add fixed max-height (400px desktop, 300px mobile) with vertical scroll
- Implement sticky table header for better navigation
- Add row striping and hover effects for improved readability
- Reduce action button size to fit table cells

This provides a cleaner, more scalable UI that maintains consistent
page layout regardless of the number of configurations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implements automatic seeding of default configuration profiles to improve
first-run UX. Fresh installations now have three ready-to-use profiles:
- demo-sine: No-hardware virtual signal generator for testing
- rtlsdr-fm-wide: FM broadcast monitoring for RTL-SDR hardware
- rtlsdr-solar-20MHz: Solar/Jovian radio monitoring at 20.1 MHz

Key features:
- Profiles bundled in Docker image at /app/default_profiles/
- Automatic idempotent seeding on container startup
- Never overwrites existing user configurations
- Deleted default profiles auto-restore on next restart
- Includes metadata manifest for future tooling

Technical changes:
- Modified entrypoint.sh to add seeding logic before privilege drop
- Updated Dockerfile to copy default_profiles into image
- Updated docker-compose.yml to build backend locally with runtime target
- Added comprehensive README documentation with profile table

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The profiles_manifest.json metadata file was being copied to the configs
directory and listed in the UI alongside actual receiver configs. When
clicked, it caused a parser error because it lacks the required
receiver_name, receiver_mode, and parameters fields.

Changes:
- entrypoint.sh: Skip manifest during seeding (not a receiver config)
- configs.py: Filter manifest from get_configs() list

The manifest still exists in /app/default_profiles/ for reference but
won't appear in the UI or get copied to user configs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Create docs/notes/ directory for tracking development notes and lessons
that can be shared with new developers.

- Add PINLIST.md: Tracks future feature ideas with detailed descriptions
  and rationale for deferral (e-Callisto integration, real-time waterfall,
  storage indicators, tag management, advanced plot customization)

- Add data-management-features.md: Implementation guide skeleton for
  delete, filtering, and log viewer features. Structured as teaching
  material for mid-level developers with architecture decisions,
  implementation details, common pitfalls, and lessons learned sections.

This establishes a pattern for documentation-driven development that
helps onboard future contributors while maintaining institutional
knowledge.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implement deletion of individual recordings directly from the Web UI
with confirmation dialog to prevent accidental data loss.

Frontend Changes:
- Add delete button to each recording card with trash icon
- Implement confirmation modal with filename display and warning
- Pessimistic update strategy: wait for API success before UI update
- Handle edge cases: close lightbox if deleted file was open
- Disable buttons during deletion to prevent double-submit
- Full dark mode support for new UI elements

UI/UX:
- Side-by-side Download and Delete buttons on each card
- Modal overlay with cancel and confirm options
- Click outside modal to cancel
- Loading state shows "Deleting..." during operation
- Error messages display at section level with retry option

CSS:
- New .recording-actions flex container for button layout
- .delete-button styling matching app's danger color scheme
- .modal-overlay and .modal-content for confirmation dialog
- Responsive mobile layout: buttons stack vertically
- Theme-aware colors using CSS variables

Documentation:
- Complete implementation guide in data-management-features.md
- Architecture decisions explained (confirmation pattern, pessimistic updates)
- Common pitfalls documented with solutions
- Manual testing checklist for user verification

Backend:
- Uses existing deleteBatchFile API method (no backend changes needed)
- DELETE /spectre-data/batches/<file_name> endpoint

This addresses the first priority feature for data management workflow,
enabling users to clean up unwanted recordings without CLI access.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implement collapsible filter panel allowing users to search recordings
by date (year/month/day) and tags, improving navigation as collections
grow.

Frontend Changes:
- Add collapsible filter panel with toggle button and active badge
- Year, month, day number inputs with HTML5 validation
- Multi-select dropdown for tags with Ctrl/Cmd support
- Active filter pills showing current selections
- Apply and Clear buttons for filter management
- Automatic tag list population from backend

UI/UX:
- Filter toggle button in gallery controls with pulsing badge when active
- Collapsible panel keeps UI clean when not in use
- Explicit "Apply" button prevents excessive API calls
- "Clear Filters" button (disabled when no filters active)
- Visual feedback with filter pill badges
- Hint text for multi-select interaction

CSS:
- New .filters-section with grid layout for inputs
- .filter-toggle-button with badge animation
- .filter-pill badges for active filters display
- .apply-filters-button and .clear-filters-button styling
- Responsive mobile layout: single column, stacked buttons
- Full dark mode support with theme variables

Backend Integration:
- Uses existing getBatchFiles API with query parameters
- Fetches available tags via getTags endpoint
- Supports partial date filtering (year only, year+month, full date)
- Multiple tag selection (OR logic)
- Empty string inputs treated as no filter

Architecture Decisions:
- Collapsible panel reduces visual clutter
- Explicit apply prevents API spam during input
- Separate date inputs enable partial date queries
- Pessimistic loading (wait for API before showing results)

Documentation:
- Complete implementation guide in data-management-features.md
- Three architecture decisions explained with rationale
- Five common pitfalls documented with solutions
- Manual testing checklist and user test cases

This addresses the second priority feature for data management,
enabling efficient navigation of growing recording libraries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implement dedicated log viewer component enabling users to access
system logs for debugging without terminal access, particularly useful
for educational settings.

Frontend Changes:
- Create new LogViewer component with list + modal pattern
- Process type filter dropdown (All/Worker/User)
- Click-to-view log content in modal overlay
- Download log file functionality
- Refresh button for log list updates

Component Structure:
- List view shows all log filenames
- Modal viewer displays full log content
- Monospace font for proper formatting
- Scrollable content area for large logs
- Loading states for list and content

API Client:
- Add getLogs() method with process type filtering
- Add getLogContent() method for raw text retrieval
- Support for date filtering (not yet exposed in UI)

UI/UX:
- View button (👁) on each log item
- Modal with filename header and close button
- Download button saves log as text file
- Click overlay to close modal
- Process type filter in header controls

CSS:
- New .logs-section, .logs-header, .logs-controls
- .log-item styling with hover effects
- .log-modal-overlay and .log-modal-content
- .log-content with monospace font and wrapping
- Responsive mobile layout: stacked controls
- Full dark mode support

Backend Integration:
- GET /spectre-data/logs/ with process_type filter
- GET /spectre-data/logs/<file_name>/raw for content
- Returns plain text log files for viewing

Architecture Decisions:
- Separate component for different data type (text vs images)
- List-then-view pattern prevents loading large files upfront
- On-demand content loading for performance
- Modal viewer handles scrolling and large content

Educational Use Case:
- Worker logs: Recording failures, hardware issues, processing errors
- User logs: API errors, configuration problems, validation issues
- No terminal access required for troubleshooting
- Download capability for sharing with instructors

Documentation:
- Complete implementation guide in data-management-features.md
- Architecture decisions with rationale
- Log type explanations (worker vs user)
- Four common pitfalls documented with solutions
- Manual testing checklist

This completes the third priority feature for data management,
enabling self-service debugging and troubleshooting capabilities.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Capture recording start time before API call
- Calculate end time forward from start (not backward from completion)
- Fixes timing mismatch that broke both 5s and 30s recordings
- 30s recordings now work again
- 5s recordings still under investigation (separate issue)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implements Phase 1 of long recording support by replacing blocking API calls
with async job-based architecture. Users can now:
- Start recordings up to 8 hours (increased from 1 hour limit)
- Close browser and return later to check progress
- View progress percentage and time estimates
- Cancel in-progress recordings

## Backend Changes

- Add job management service (jobs.py) with file-based state storage
- Create async recording endpoints:
  - POST /recordings/spectrogram/async - Returns job_id immediately
  - GET /recordings/jobs/<job_id> - Get job status and progress
  - GET /recordings/jobs - List all jobs
  - DELETE /recordings/jobs/<job_id> - Cancel job
- Spawn recording as subprocess using multiprocessing.Process
- Store job state in /app/.spectre-data/jobs/{job_id}.json
- Track job status: pending → running → completed/failed/cancelled

## Frontend Changes

- Add async API methods (recordSpectrogramAsync, getJobStatus, etc.)
- Implement 5-second polling for job status updates
- Add progress bar with percentage display
- Add cancel button during recording
- Persist active job_id to localStorage for page refresh recovery
- Increase duration limit to 28,800 seconds (8 hours)

## Technical Details

- Progress calculated based on elapsed time vs duration
- Job metadata includes: job_id, tag, duration, start_time, status, progress, pid
- Background process updates job state via file writes
- Frontend reconnects to in-progress jobs on mount
- Backward compatible - original sync endpoints unchanged

## Testing

- Verified 30-second recording completes successfully
- Job state persisted to disk correctly
- Progress updates from 0% → 100%
- Batch files created during recording
- Job listing endpoint returns completed jobs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link

@Schousboe Schousboe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so first of all, what in the AI vibe coding is this supposed to mean...

Screenshot 2025-11-27 22 28 40

I mean it's not a NASA space shuttle you should "program". Oh yeah also, not legal advice, but adding a license for every single folder is a bad idea...

Oh yeah ALSO why in the world did you remake the entire README file just for this? You litterally No joke deleted everything and replaced with your own. Just hear how this sounds

Spectre WebUI is a local-first interface for the Spectre SDR capture pipeline, prototyped 100% by Codex (GPT-5) and Claude after vibing on the [“Interested in vibecoding a frontend?” thread](https://www.reddit.com/r/vibecoding/comments/1p33nbo/interested_in_vibecoding_a_frontend/). We stand on the shoulders of [jcfitzpatrick12/spectre](https://github.com/jcfitzpatrick12/spectre); check the [upstream README](https://github.com/jcfitzpatrick12/spectre/blob/main/README.md) whenever you need deeper backend details, device specifics, or CLI flag references.

I will now list all the meaningful things you deleted:

  1. The whole "Getting started" section including; link to wiki, installation, tutorials, contributing and ''track our progress"
  2. The whole "About us section" which got prelaced by "prerequisites" and "5 minute install". This is for example the text
_Spectre_ is a free and open source receiver-agnostic program for recording and visualising radio spectrograms. It's geared for hobbyists, citizen scientists, and academics who want to achieve scientifically interesting results at low cost. 

Which you just switched with

- Docker Desktop (Windows/macOS) or Docker Engine + Docker Compose plugin (Linux)
- Command-line basics: `curl`, `jq`, `tar`, and `docker` available (PowerShell, macOS Terminal, WSL, etc.)
- Optional but fun: an SDR such as RTL-SDR, HackRF, SDRplay, or USRP. The `demo-sine` profile works without hardware.

You also deleted the credits to GNU radio and FFTW

You know what, i'm too tired for for this right now, just want you to hear that you should atleast not make this AI make all the code (1365 files) and atleast check it trough before commiting - and i nearly only saw the README which was bad enough. My laptop also crashed multiple times writing this review because of all these files.

Here is a review from Copilot as i can legit not write more without my whole computer crashing more. And you think it's a genius web UI...

@Schousboe
Copy link

Schousboe commented Nov 27, 2025

Yeah, i tried to get review from Copilot but computer crashed again in doing so


@b3p3k0, please, just... Don't accept this pr. It will break all your work 💀

@b3p3k0 b3p3k0 changed the base branch from main to gui-poc November 28, 2025 00:26
@b3p3k0
Copy link
Author

b3p3k0 commented Nov 28, 2025

@Schousboe thx that's my bad, it was supposed to go under the gui-poc. have a good one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants