Skip to content

Development

Requirements

  • Python 3.13
  • uv package manager
  • Node.js 22+ and npm (for the frontend)
  • Docker (for integration testing)
  • A reachable Redis instance

Setup

# Clone the repo
git clone <repo-url>
cd dive_detector

# Install backend dependencies
uv sync

# Install frontend dependencies
cd frontend && npm install && cd -

Running backend services locally

Start Redis, then run the collector and detector against it:

# Start Redis (in Docker for simplicity)
docker run -d --name redis -p 6379:6379 redis:latest

# Collect navigation data for R/V Rachel Carson
uv run backend/navproc_collector.py \
  --ship rcsn --domain rc --redis-host localhost --poll-interval 5

# In another terminal: run the dive detector
OBS_PASSWORD="" \
uv run backend/divedetector.py \
  --ship rcsn --redis-host localhost \
  --obs-host <your-obs-host> --poll-interval 10

Running the frontend locally

cd frontend
cp .env.example .env       # point REDIS_HOST/PORT at a reachable Redis
npm run dev                # http://localhost:3000

The dev server hot-reloads Svelte components. The SvelteKit server-side routes (src/routes/api/.../+server.ts) restart on save automatically.

Inspecting cached data

# Static snapshot
uv run backend/redis_dump.py rcsn

# Live auto-refreshing TUI
uv run backend/redis_dump_textual.py rcsn --refresh-interval 2

See Redis Tools for full options.

Project layout

dive_detector/
├── backend/                    # Python services
│   ├── collector_keys.toml     # NATS keys the collector mirrors
│   ├── divedetector.py         # Detection loop + main entrypoint
│   ├── navproc_collector.py
│   ├── obs_control.py
│   ├── redis_dump.py
│   └── redis_dump_textual.py
├── frontend/                   # SvelteKit + Tailwind dashboard
│   ├── src/
│   │   ├── lib/
│   │   │   ├── components/     # ShipCard, MapWidget, StatusPill, ...
│   │   │   ├── server/redis.ts # ioredis singleton + accessors
│   │   │   └── types.ts        # Shared TS types
│   │   └── routes/             # Pages + +server.ts API endpoints
│   ├── static/favicon.svg
│   └── package.json
├── docker/                     # Dockerfiles
│   ├── dive_detector.dockerfile
│   ├── frontend.dockerfile
│   └── navproc_collector.dockerfile
├── docs/                       # This documentation (MkDocs)
├── compose.yaml                # Docker Compose stack
├── pyproject.toml
├── mkdocs.yml
└── uv.lock

Dependencies

Backend (pyproject.toml)

Package Purpose
nats-py Async NATS JetStream client
redis Redis client
obs-websocket-py OBS WebSocket v5 client
rich Terminal table formatting (redis_dump)
textual / textual-serve Interactive TUI + web serving (redis_dump_textual)
fastapi / uvicorn ASGI web framework (available for future use)

tomllib (stdlib in Python 3.11+) is used to parse collector_keys.toml — no extra dependency required.

Frontend (frontend/package.json)

Package Purpose
@sveltejs/kit SvelteKit framework
@sveltejs/adapter-node Node server adapter
svelte Svelte 5
tailwindcss + @tailwindcss/vite Tailwind v4
ioredis Redis client used in server-side routes
leaflet + @types/leaflet Map widget

Common changes

Adding a new NATS-sourced metric

  1. Append the NATS key (UPPERCASE dotted form) to backend/collector_keys.toml and update the comment block listing consumers.
  2. If a Python service should read it, add the read directly with the normalised Redis key name.
  3. If the dashboard should display it, add the key helper to frontend/src/lib/server/redis.ts, extend the pipeline + the ShipState type, then surface it in ShipCard.svelte.
  4. Rebuild the affected containers.

Adding a new ship

  1. Add a NATS-accessible ship to the system.
  2. Add two new services to compose.yaml — one navproc-collector and one dive-detector — using the new ship's SHIP_NAME, SHIP_DOMAIN, and OBS_HOST.
  3. Add the ship to the SHIPS array in frontend/src/lib/types.ts and to the ShipId union.
  4. Verify the new OBS instance has the MainOnly and FeedOffline scenes.

Serving the docs locally

uv run --with mkdocs --with mkdocs-material mkdocs serve

Then open http://127.0.0.1:8000.

To build static HTML:

uv run --with mkdocs --with mkdocs-material mkdocs build

Output is written to site/.