How akumascoffin/rdio-scanner works
1. This repository is a three-part product: a Go backend in server/, an Angular web client in client/, and a native Android client in android/. The backend is the central runtime; the web client is compiled into static assets and embedded into the Go binary at build time.
2. The core server is a long-running HTTP application that exposes the browser UI, admin UI, public REST API, WebSocket/live updates, and recorder ingestion endpoints. It is the architectural hub connecting incoming call data, persisted metadata, transcripts, and downstream consumers.
3. Call ingestion is driven by recorder integrations. The server can accept API-based uploads from supported recorders and also monitor directories for “one audio file per call” workflows. This ingest path feeds metadata parsing, persistence, optional transcription, and live broadcast to connected clients.
4. Persistence is abstracted behind the server’s database layer and supports SQLite by default, with PostgreSQL, MySQL, and MariaDB as options. The README emphasizes PostgreSQL as the preferred deployment for large installs because search and stats rely on database indexes and concurrent ingest/search workloads.
5. Search and browsing are first-class server features. The backend stores call records, transcripts, systems, talkgroups, units, tags, and stats-related aggregates, then serves filtered search results and deep links to the web UI. Transcript search is optimized at the database level, which is important for diagramming the data flow from ingest to indexed query.
6. Transcription is a separate backend subsystem. The server can send audio to Groq Whisper, manage multiple API keys, retry on failures, and conditionally hold call visibility until transcript text is available. This makes transcription an asynchronous enrichment stage after ingestion rather than part of the initial upload path.
7. Real-time behavior is handled through WebSockets and livefeed-style server push. The backend broadcasts current call activity, listener counts, and LCD-style status updates to web and mobile clients. The README’s “early-WS opener” and buffered sends indicate that realtime transport is a core performance boundary, not just a UI detail.
8. The web client in client/ is an Angular single-page application with two major user surfaces: the main scanner UI and the admin console. It includes components for search, stats, live feed, selection, and configuration management, plus a service layer that talks to the Go backend’s HTTP and WebSocket endpoints.
9. The admin area is a substantial subsystem rather than a small settings page. It manages systems, talkgroups, units, groups, API keys, access controls, downstreams, directory watch configuration, logs, statistics, and import/export tooling. In the architecture diagram, this is the control plane for server configuration and operational data.
10. The main web UI focuses on operator and listener experience: live transcript display, search, stats dashboard, and shareable deep links. The frontend is designed to consume the backend’s public data model and realtime updates, while the server remains responsible for authorization, filtering, and persistence.
11. The Android app in android/ is a separate native client built with Kotlin and Compose. It mirrors the live scanner experience, supports multiple connection profiles, background audio playback, and reconnect logic, and talks directly to the same backend rather than embedding the web app.
12. Supporting subsystems in the backend include audio playback/decode, downloader/repository logic, settings persistence, protocol/message modeling, network monitoring, and scheduler/background tasks. These are internal boundaries inside the Go service that connect file/audio handling, database operations, and client-facing APIs.
13. Deployment-wise, the architecture is usually a single Go executable plus a database, with optional external recorder processes supplying audio files. The embedded web app means there is no separate frontend server in production, and the Android app is optional as an additional client, not part of the backend runtime.
14. Overall data flow: recorder or uploader → Go ingest/parsing → database persistence and optional transcription → indexed search/stats/livefeed updates → Angular web UI or Android app consumption. That is the main end-to-end path an architecture diagram should emphasize.
Main entry points: main.go HTTP server · call.go Call ingest · livefeed.go Live updates · public_api.go Public API
Components 20
Go backend
Central long-running server runtime and embedded web asset host
- HTTP server · Main long-running Go process serving UI, API, admin, and realtime endpoints
server/main.go - Embedded webapp · Built Angular assets embedded into the Go binary at build time
server/webapp.go - Public API · Browser, mobile, and external API surface for call data and queries
server/public_api.go - Admin plane · Configuration and operational endpoints for systems, keys, access, logs, and tools
server/admin.go - Live updates · WebSocket and livefeed broadcasting for current calls, listeners, and status
server/livefeed.go - Call ingest · Recorder upload and directory-watch intake path that parses and stages incoming calls
server/call.go - Dir watch · Watches audio directories for one-file-per-call workflows
server/dirwatch.go - Transcription · Sends audio to external transcription services, retries failures, and gates visibility when needed
server/transcription.go - Database layer · Abstracted storage supporting SQLite, PostgreSQL, MySQL, and MariaDB
server/database.go - Search & stats · Filtered search, deep links, and aggregated stats over calls, transcripts, systems, talkgroups, units, and tags
server/stats.go - Background jobs · Deferred work and periodic tasks coordinating ingest, cleanup, and enrichment flows
server/scheduler.go - Data model · Shared call, system, talkgroup, unit, tag, message, and protocol structures
server/message.go
Angular web client
Browser SPA plus admin control plane
- Web app · Browser application shell for operator and listener experience
client/src/app/app.component.ts - Main scanner · Live feed, transcript display, search, stats, and selection workflows
client/src/app/components/rdio-scanner/main/main.component.ts - Admin console · Substantial admin surface for configuration, access, imports, logs, stats, and tools
client/src/app/components/rdio-scanner/admin/admin.component.ts - API services · Angular service layer that talks to HTTP and WebSocket backend endpoints
client/src/app/components/rdio-scanner/rdio-scanner.service.ts - Public stats · Listener-facing stats and deep-link browsing view
client/src/app/components/rdio-scanner/stats/public-stats.component.ts
Android client
Native Kotlin/Compose mobile client
- Android app · Kotlin/Compose mobile app mirroring the live scanner experience
android/app/src/main/kotlin/solutions/saubeo/rdioscanner/MainActivity.kt - Client repo · Repository and downloader logic for backend communication and playback orchestration
android/app/src/main/kotlin/solutions/saubeo/rdioscanner/data/repository/RdioRepository.kt - Audio playback · Background audio service and call playback handling
android/app/src/main/kotlin/solutions/saubeo/rdioscanner/audio/AudioService.kt
Connections 27
- HTTP server → Embedded webapp: serves embedded UI · The Go binary exposes the built Angular assets as the browser application
- HTTP server → Public API: exposes · Publishes the public REST API for search, browsing, and call data
- HTTP server → Admin plane: exposes · Publishes operational/admin endpoints for configuration and maintenance
- HTTP server → Live updates: pushes · Maintains realtime client connections and buffered broadcast streams
- HTTP server → Call ingest: accepts uploads · Receives recorder uploads and call submissions into the ingest pipeline
- HTTP server → Dir watch: monitors files · Supports directory-based recorder workflows through file watching
- Call ingest → Data model: parses metadata · Converts incoming call artifacts into the server domain model
- Call ingest → Database layer: persists · Stores call metadata, transcript status, and related entities
- Call ingest → Transcription: enriches · Hands off eligible calls for asynchronous transcription
- Transcription → Database layer: writes transcript · Stores transcript text and transcript availability state
- Transcription → Live updates: announces · Notifies connected clients when transcripts or visibility state change
- Database layer → Search & stats: supports · Indexed persistence backs search, browsing, and stats queries
- Search & stats → Public API: serves queries · Search and stats results are returned through the API surface
- Live updates → Public API: streams updates · Realtime activity complements the request/response API
- Background jobs → Call ingest: coordinates · Background tasks can defer or orchestrate ingest-related work
- Background jobs → Transcription: retries · Retries and delayed processing are managed as background work
- Web app → Main scanner: contains · The main SPA routes into the operator/listener interface
- Web app → Admin console: contains · The SPA also exposes the admin console as a major surface
- Main scanner → API services: uses · Main UI components consume backend data through shared services
- Admin console → API services: uses · Admin screens use the same service layer for configuration and operations
- API services → Public API: calls · Angular service layer talks to backend HTTP endpoints
- API services → Live updates: subscribes · Web client receives live updates over WebSockets or similar push channels
- Public stats → Search & stats: queries · Stats and browse views depend on server-side indexed search and aggregates
- Android app → Client repo: uses · Compose UI drives the mobile repository and connection layer
- Client repo → Public API: calls · Android connects directly to the same backend data surface
- Client repo → Live updates: subscribes · Mobile client consumes realtime updates from the server
- Client repo → Audio playback: plays · Repository and UI coordinate media playback through the audio subsystem