Files

109 lines
4.3 KiB
Markdown

# BEACON Web
[![CodeQL](https://github.com/MeshCore-Beacon/beacon-web/actions/workflows/codeql.yml/badge.svg)](https://github.com/MeshCore-Beacon/beacon-web/actions/workflows/codeql.yml)
[![CI](https://github.com/MeshCore-Beacon/beacon-web/actions/workflows/ci.yml/badge.svg)](https://github.com/MeshCore-Beacon/beacon-web/actions/workflows/ci.yml)
[![Docker](https://github.com/MeshCore-Beacon/beacon-web/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/MeshCore-Beacon/beacon-web/actions/workflows/docker-publish.yml)
Real-time LoRa mesh packet analyzer. Desktop-first, dark-mode-primary, dense information display for radio hobbyists.
Built with React 19, TypeScript, Tailwind CSS 4, TanStack Query, and TanStack Virtual.
## Deployment
### 1. Copy the `docker/` folder to your server
```bash
scp -r docker/ user@your-server:/opt/docker/beacon-web
```
### 2. Create a `.env` file
```bash
cd /opt/docker/beacon-web
cat > .env << 'EOF'
DOMAIN=dev.meshcore.ca
VITE_API_BASE=https://dev.meshcore.ca/api/v1
VITE_WS_URL=wss://dev.meshcore.ca/ws
EOF
```
| Variable | Description |
|---|---|
| `DOMAIN` | Domain for HTTPS (Caddy auto-provisions Let's Encrypt certs) |
| `VITE_API_BASE` | Backend REST API base URL |
| `VITE_WS_URL` | Backend WebSocket URL |
### 3. Start the services
```bash
docker compose up -d
```
The images are public on GitHub Container Registry — no `docker login` required.
If a pull fails with `403 Forbidden`, the package visibility has regressed to
Private; a maintainer needs to set it back to Public (see the troubleshooting note
in [beacon-docs](https://github.com/MeshCore-Beacon/beacon-docs)).
Caddy will automatically obtain a TLS certificate for your domain. Ensure DNS is pointed at your server before starting.
## Local Development
```bash
npm install
cp .env.example .env # edit with your backend URLs
npm run dev # starts Vite dev server at http://localhost:5173
```
### Commands
| Command | Description |
|---|---|
| `npm run dev` | Start dev server |
| `npm run build` | Type-check and build for production |
| `npm run preview` | Preview production build locally |
| `npm run lint` | Run ESLint |
| `npx vitest run` | Run tests |
| `npx tsc --noEmit` | Type-check without emitting |
## Project Structure
```
docker/
docker-compose.yml # production deployment compose file
Caddyfile # internal Caddy config (static file serving)
Caddyfile.proxy # reverse proxy config (HTTPS termination)
docker-entrypoint.sh # runtime env var injection
Dockerfile # multi-stage build (Node + Caddy)
src/
api/
client.ts # typed REST client (fetch wrapper)
ws-manager.ts # WebSocket connection, reconnect, subscription management
components/ # shared UI components
features/ # feature modules (packets, nodes, channels, map, stats)
hooks/ # React hooks (region, theme, WebSocket)
lib/ # constants, formatters, theme utilities
types/ # TypeScript types and enums
App.tsx # providers + routing + WS init
main.tsx # entry point
index.css # Tailwind setup, theme tokens, animations
```
## Architecture
- **Region-driven**: All data queries and WS subscriptions are scoped to an IATA region code. Changing region resets the cache and resubscribes.
- **Live + historical merge**: WebSocket pushes live packets into a `LivePacketStore` buffer (capped at 500). Historical data comes from cursor-paginated REST via `useInfiniteQuery` (max 20 pages). Both are merged and deduped at render time.
- **Client-side filtering**: Filters are not part of the query key. The cache holds all packets for the current region; filters are applied via `useMemo`. Toggling a filter is instant with no refetch.
- **Reconnect with jitter**: Exponential backoff with +/-25% random jitter prevents thundering herd on server bounce.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). All contributors are welcome — please
also read the [Code of Conduct](CODE_OF_CONDUCT.md). To report a security issue,
see [SECURITY.md](SECURITY.md).
## License
Licensed under the GNU Affero General Public License v3.0 or later
(AGPL-3.0-or-later). See [LICENSE](LICENSE) for the full text and
[CONTRIBUTORS.md](CONTRIBUTORS.md) for acknowledgements.