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
26 changes: 11 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ jobs:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
# macOS matrix deferred until Phase 0 bootstrap is stable (see docs/PLAN.md)

defaults:
run:
working-directory: video-feed
# macOS matrix deferred (see docs/PLAN.md)

steps:
- uses: actions/checkout@v4
Expand All @@ -27,30 +23,30 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install web-test + dev dependencies
- name: Install package (web-test + dev extras)
run: |
python -m pip install --upgrade pip
pip install -r requirements-web-test.txt -r requirements-dev.txt
pip install -e ".[web-test,dev]"

- name: Ruff (Phase 0 paths — correctness rules)
- name: Ruff (Phase 1 paths — correctness rules)
run: |
# Full style cleanup deferred (repo predates ruff); gate on bugs only
ruff check --select E,F,B \
videofeed/auth_gate.py \
videofeed/credentials.py \
videofeed/routes/auth.py \
src/spectrax/auth_gate.py \
src/spectrax/credentials.py \
src/spectrax/paths.py \
src/spectrax/routes/auth.py \
tests/test_api_characterization.py \
tests/test_auth.py \
tests/test_config_security.py \
tests/test_package_layout.py \
tests/conftest.py

- name: Pytest (API / unit, no torch, no MediaMTX)
env:
PYTHONPATH: .
run: |
# Only Phase 0 API tests: test_db*.py import recorder → cv2 (full stack)
pytest \
tests/test_api_characterization.py \
tests/test_auth.py \
tests/test_config_security.py \
-m "not slow and not requires_mediamtx"
tests/test_package_layout.py \
-m "not slow and not requires_mediamtx"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ server.key
mediamtx.yml

# YOLO Models (large files)
video-feed/models/*.pt
models/*.pt
*.pt
# Distribution / packaging
.Python
Expand Down
106 changes: 106 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Layout

The installable package lives under **`src/spectrax/`** (import name `spectrax`).
Install from the repo root with an editable install — do **not** set `PYTHONPATH`.

```
src/spectrax/ # Python package
config/spectrax.yml # example config (no secrets)
models/ # YOLO weights (gitignored *.pt)
tests/ # pytest suite
dashboard/ # orphaned static HTML until Phase 4
```

## Environment

A `venv/` (or `.venv/`) at the repo root is the expected environment; activate it
before running anything. `scripts/surveillance.sh` auto-activates it.

```bash
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]" # full stack (torch, etc.)
# or, for API tests only (no torch):
pip install -e ".[web-test,dev]"
```

MediaMTX must be on `PATH` (`brew install mediamtx`); the launcher hard-fails without it.
There are no env vars to configure — all config lives in `config/spectrax.yml`.
Credentials are generated at runtime into the OS keychain (service
`video-feed-mediamtx` — name kept for Phase 0 compatibility), never into files;
`spectrax reset` wipes them.

## Running

From the repo root after editable install:

```bash
./scripts/surveillance.sh config # start from config/spectrax.yml
./scripts/surveillance.sh quick # one camera, defaults
spectrax config # same as above via console script
surveillance config # temporary alias (kept until Phase 2)
```

The CLI is Typer (`src/spectrax/surveillance.py`): `config`, `start`, `quick`,
`run`, `detect`, `reset`, `admin`, `apikey`, `credentials`.

## Testing

Run pytest from the **repo root** (not a nested package dir):

```bash
pytest
pytest tests/test_auth.py::test_name # single test
pytest -m unit # by marker
```

`pyproject.toml` sets `--strict-markers`, so any new marker must be added to
`[tool.pytest.ini_options].markers`
(`unit, integration, db, recording, detection, slow, requires_mediamtx, api`).
CI uses the slim web-test extra (no torch) and runs characterization/auth/layout tests only.

Coverage is sparse and concentrated on DB/recording/storage/auth; many modules
still lack tests. Characterization tests in `tests/test_api_characterization.py`
are the regression net for routes.

## Style

Ruff config lives in `pyproject.toml` (`ruff check .`, `ruff format .`).
The existing code predates it and is not clean — lint the files you touch;
do not mass-reformat the repo as a side effect of another change.

Otherwise follow the conventions of the file you are editing: 4-space indent,
docstrings on public modules and functions, `typing` annotations, `@dataclass`
for config objects, relative or absolute package imports (`from spectrax…`
or `from .constants import …`).

## Git

Branch off `main` with a type prefix (`docs/`, `feat/`, `fix/`) and merge via PR.
Never commit directly to `main`.

## Gotchas

- **No `sys.path` / `PYTHONPATH` hacks** — use `pip install -e .`.
- **Routes use module-level global state, not DI.** `visualizer.py` wires them at
startup via setters (`video_routes.set_detector_manager`,
`files_routes.set_recordings_directory`,
`recordings_routes.set_recordings_api`). Miss one and the route 500s. See
`src/spectrax/routes/README.md`. New endpoints belong in `routes/`, not
`visualizer.py`. (DI is Phase 2.)
- **Two class filters that look alike**: `detection.filters.classes` controls
what is *detected*, `recording.record_objects` controls what is *recorded*.
Empty list means "all" for both.
- **`recording.codec` must be `avc1`** — `mp4v` produces clips the browser
player cannot play. Re-verify playback after any OpenCV bump.
- **RTSPS uses a self-signed cert** generated at runtime (`server.crt` /
`server.key` / `mediamtx.yml` are gitignored); clients will show security
warnings. API auth is session cookie or bearer API key (Phase 0).
- **Path helpers** for config/models/TLS live in `spectrax.paths` — do not
reintroduce `Path(__file__).parent.parent / "config"`.
- **Docs are known-stale — trust the code.** Full rewrite is Phase 4.
`docs/ARCHITECTURE.md` and some README paths still mention the old
`video-feed/` layout.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,16 @@ Access the web interface at the URL shown when starting the system (e.g., `http:
./scripts/surveillance.sh quick

# Start streaming server only (no detection)
python -m videofeed.surveillance run --path video/front-door
python -m spectrax.surveillance run --path video/front-door

# Start detection only (existing stream)
python -m videofeed.surveillance detect --rtsp-url "rtsps://viewer:pass@host:8322/video/cam"
python -m spectrax.surveillance detect --rtsp-url "rtsps://viewer:pass@host:8322/video/cam"

# Query recordings by tracker ID
python scripts/query_recordings.py tracker 42

# Reset stored credentials
python -m videofeed.surveillance reset
python -m spectrax.surveillance reset
```

### REST API
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions video-feed/ui/README.md → dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This directory contains a standalone HTML dashboard for quick access to surveillance feeds.

## Status (Phase 0)
## Status (Phase 0/1)

**Unsupported for production use.** The unauthenticated `/paths` discovery server
(`localhost:3333`) was removed in Phase 0. Opening `dashboard.html` via `file://` or
Expand All @@ -11,7 +11,7 @@ cross-origin auto-discovery no longer works.
Use the **integrated dashboard** served by the FastAPI app (same origin, session cookie):

```bash
# After: surveillance admin set-password
# After: spectrax admin set-password
./scripts/surveillance.sh config
# Open http://127.0.0.1:8080/login
```
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ Currently, there are no rate limits on API endpoints. For production deployments

## CORS

Cross-Origin Resource Sharing (CORS) is enabled by default for all origins. To restrict access, modify the FastAPI CORS middleware configuration in `videofeed/visualizer.py`.
Cross-Origin Resource Sharing (CORS) is enabled by default for all origins. To restrict access, modify the FastAPI CORS middleware configuration in `spectrax/visualizer.py`.

---

Expand Down
10 changes: 5 additions & 5 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This document provides a comprehensive overview of the SpectraX codebase archite
```
root/
├── video-feed/ # 📦 Main Python package
│ ├── videofeed/ # Core modules
│ ├── spectrax/ # Core modules
│ │ ├── surveillance.py # 🎯 MAIN ENTRY POINT - Unified CLI
│ │ ├── config.py # 🔧 Configuration management
│ │ ├── detector.py # 🎯 YOLO object detection
Expand Down Expand Up @@ -105,7 +105,7 @@ class SurveillanceConfig:

**Usage:**
```python
from videofeed.config import SurveillanceConfig
from spectrax.config import SurveillanceConfig

config = SurveillanceConfig.load_from_yaml('config/surveillance.yml')
cameras = config.get_camera_paths()
Expand Down Expand Up @@ -588,7 +588,7 @@ pytest tests/

```bash
# Start with config file
python -m videofeed.surveillance config
python -m spectrax.surveillance config

# Or use the shell script
./scripts/surveillance.sh config
Expand Down Expand Up @@ -621,7 +621,7 @@ pytest
pytest tests/test_detector.py

# Run with coverage
pytest --cov=videofeed tests/
pytest --cov=spectrax tests/

# Run with verbose output
pytest -v
Expand All @@ -631,7 +631,7 @@ pytest -v

```python
import pytest
from videofeed.detector import ObjectDetector
from spectrax.detector import ObjectDetector

def test_detector_initialization():
detector = ObjectDetector(model_path="yolov8n.pt", confidence=0.4)
Expand Down
33 changes: 19 additions & 14 deletions docs/PLAN.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SpectraX Modernization & Re-architecture Plan

> Status: **Phase 0 implemented on `feat/phase-0-security`** · Written 2026-08-09 ·
> Phase 0 detail confirmed 2026-08-10 · Supersedes nothing (first plan doc)
> Status: **Phase 0 on `main`** · **Phase 1 on `feat/phase-1-repackage` (merge pending)** ·
> Written 2026-08-09 · Phase 0 confirmed 2026-08-10 · Phase 1 implemented 2026-08-10
>
> Sources: full-codebase survey, security audit, and architecture design produced 2026-08-09;
> Phase 0 PR DAG refined by `plan-next-phase` workflow 2026-08-10.
Expand Down Expand Up @@ -201,7 +201,7 @@ spectrax/

### Phase 0 — Stop the bleeding (security, on the CURRENT layout) — 4–7 days

**Status: implemented on branch `feat/phase-0-security` (merge pending).**
**Status: merged to `main` (PR #9).**

Fixes both CRITICALs and the HIGHs before any restructuring, so security never waits on
architecture. Work stays on `video-feed/videofeed/` — **no** `create_app`, `src/spectrax/`,
Expand Down Expand Up @@ -252,13 +252,18 @@ Checklist (maps to original items):
### Phase 1 — Repackage — days
Mechanical only, no logic changes.

1. `pyproject.toml` (setuptools backend, `requires-python >= 3.11`, both console scripts);
delete `setup.py`, `cli.py` shim, and the `sys.path` hack.
2. `git mv` to `src/spectrax/` layout; fix imports; ruff config moves into pyproject.
3. Dependency refresh in tiers (web stack → CV stack → utilities), tests between tiers;
compiled lockfile (`uv pip compile`). **Re-verify `avc1` clip playback in-browser after
the OpenCV bump.**
4. `@app.on_event` → lifespan context; clear pydantic v2 deprecation warnings.
**Status: implemented on branch `feat/phase-1-repackage` (merge pending).**

1. `pyproject.toml` (setuptools backend, `requires-python >= 3.11`, console scripts
`spectrax` + `surveillance` alias); delete `setup.py`, `cli.py` shim, and the
`sys.path` hack. Core deps exclude torch; full stack is `pip install -e ".[cv]"`. — **done**
2. `git mv` to `src/spectrax/` layout; package rename `videofeed` → `spectrax`; path
helpers in `spectrax.paths`; ruff/pytest config in pyproject; config at
`config/spectrax.yml`; keychain service string kept as `video-feed-mediamtx`. — **done**
3. Compiled lockfiles via `uv pip compile` (`requirements.lock.txt`,
`requirements-web-test.lock.txt`). Direct pin bumps (OpenCV/`avc1` gate) deferred to a
follow-up so this PR stays mechanical. — **done (structure); version bumps deferred**
4. `@app.on_event` → lifespan context. — **done**

*Ships: identical behavior, proper installable package, current deps.*

Expand Down Expand Up @@ -342,10 +347,10 @@ URLs, Phase 0 tests as the regression net.
1. ~~**Dashboard TLS**~~ — **Decided (Phase 0):** plain HTTP on trusted LAN;
`Secure=False` by default; `HttpOnly` + `SameSite=Strict` always. Self-signed dashboard
HTTPS deferred.
2. **Rename**: package becomes `spectrax` (from `videofeed`) in Phase 1 — confirm the name
before the `git mv`.
3. **`.enc` extension** in the file-serving allowlist looks like an abandoned encryption
feature — confirm dead and remove in Phase 1.
2. ~~**Rename**~~ — **Decided (Phase 1):** package is `spectrax`; console scripts
`spectrax` + temporary `surveillance` alias. Keychain service stays
`video-feed-mediamtx`.
3. ~~**`.enc` extension**~~ — **Decided (Phase 1):** removed from files allowlist (dead).
4. **MediaMTX ownership**: keep spawning it as a child of the core (simplest, current
behavior) vs separate systemd unit on Linux (survives core restarts)? Plan assumes
child-process in dev, separate unit in production — confirm in Phase 2.
Expand Down
4 changes: 2 additions & 2 deletions video-feed/models/README.md → models/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ The system automatically uses models from this directory when you specify a mode

Models are automatically loaded from this directory when you specify them in:

1. **Configuration file** (`video-feed/config/surveillance.yml`):
1. **Configuration file** (`config/spectrax.yml`):
```yaml
detection:
model: "yolov8l.pt"
```

2. **Command line**:
```bash
python -m videofeed.surveillance start --model yolov8n.pt
spectrax start --model yolov8n.pt
```

## Automatic Download
Expand Down
Loading
Loading