A private intelligence aggregation platform built around Automatic License Plate Recognition (ALPR) data. Sightline ingests Flock-style ALPR exports, normalizes and deduplicates them, maps camera networks, correlates vehicle sightings into investigation timelines, reconstructs...
A private intelligence aggregation platform built around Automatic License Plate Recognition (ALPR) data. Sightline ingests Flock-style ALPR exports, normalizes and deduplicates them, maps camera networks, correlates vehicle sightings into investigation timelines, reconstructs movement and detects anomalies, manages watchlists and alerts, generates analyst reports, and enriches investigations with passive OSINT.
ALPR is the core product. OSINT enrichment is a supporting module.
Responsible-use note: ALPR data is privacy-sensitive. Sightline assumes the operator holds the data lawfully and is accountable for its use. Access control, full audit logging, source attribution, and configurable retention are first-class features so that use is traceable.
| Capability | Status |
|---|---|
| JWT auth + role-based access control (admin/analyst/viewer) | ✅ verified |
| API-key auth (X-API-Key) for machine-to-machine, with revoke | ✅ verified |
| OIDC / SSO login (config-gated, standard auth-code flow) | ✅ implemented |
| CSV + JSON + PDF Flock-style ingest with column auto-mapping | ✅ verified |
| Normalization (plate/timestamp/direction/confidence/geo) | ✅ unit-tested |
| Deterministic dedup (idempotent re-import, sub-second burst collapse) | ✅ verified |
| Async ingest via Celery worker (+ synchronous path) | ✅ verified |
| Real-time stream ingest (push reads, no file) | ✅ verified |
| API connectors (generic JSON-REST poller, webhook) | ✅ verified |
| Plate / partial-plate / unified search | ✅ verified |
| Movement intelligence: route reconstruction, haversine speed, impossible-travel anomaly detection, dwell, frequency, co-travel, camera transitions | ✅ unit-tested + live |
| Watchlists + inline hit generation + history backfill | ✅ verified |
| Investigation timeline + entity graph | ✅ verified |
| Evidence with SHA-256 chain-of-custody + integrity-checked download | ✅ verified |
| Report generation (Markdown/JSON/CSV/PDF) with auto key-findings | ✅ verified |
| OSINT enrichment plugins (DNS, RDAP, crt.sh, IP/ASN, security.txt, robots, GitHub, TLS) | ✅ verified |
| Pluggable storage (local filesystem / S3-compatible) | ✅ verified |
| Retention enforcement (admin trigger + scheduled Celery beat, cascade-safe) | ✅ verified |
| Immutable audit log on every mutation (entity-linked) | ✅ verified |
| In-process rate limiting | ✅ |
Frontend is a complete Next.js app (17 routes) wired to the live API: dashboard, investigations list/detail with evidence + report export, plate search, camera map + detail, vehicle profile, entity graph, watchlist manager, alerts, ALPR import, OSINT panel, audit log, and an admin console (settings, retention, API keys, connectors, users, sources).
cp .env.example .env
docker compose up --build
# API → http://localhost:8000/docs (seeded automatically)
# UI → http://localhost:3000
# login → admin@sightline.app / changeme123
cd backend
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
# point at a Postgres instance
export SIGHTLINE_DATABASE_URL="postgresql+psycopg2://sightline:sightline@localhost:5432/sightline"
alembic upgrade head
python seed.py # admin@sightline.app / changeme123 + sample data
uvicorn app.main:app --reload # http://localhost:8000/docs
pytest # 16 tests: pipeline + analytics, no DB required
Next.js (TS) ──REST+JWT──▶ FastAPI ──▶ PostgreSQL (pg_trgm partial-plate search, FTS-ready)
│ └──▶ Redis + Celery (ingest, enrichment, retention jobs)
└──────────▶ Object store (evidence + raw import blobs)
Parser pipeline: CSV/JSON/PDF → normalize → dedup → persist → watchlist eval → analytics → audit
Full design - schema, API routes, parser pipeline, analytics, frontend plan, file tree - is in
docs/DESIGN.md.
The seeded data includes a plate (GHI5566) observed at two cameras 13.6 km apart only
60 seconds apart. The movement engine computes the implied speed (818 km/h) and flags it:
GET /api/v1/vehicles/GHI5566/movement
→ "anomalies": [{ "reason": "impossible_travel_speed", "speed_kmh": 817.8, ... }]
This surfaces likely plate misreads or cloned plates - a core ALPR analytic.
Sightline/
├── docker-compose.yml # postgres, redis, api, worker, beat, frontend
├── docs/DESIGN.md # full architecture & schema
├── backend/ # FastAPI + SQLAlchemy + Alembic + Celery
│ ├── app/
│ │ ├── core/ # config, security, storage, rate limit, permissions
│ │ ├── api/routes/ # auth, oidc, investigations, imports, live, evidence,
│ │ │ # search, cameras, watchlists, enrichment, api-keys,
│ │ │ # reports, admin
│ │ ├── services/ # normalize, dedup, ingest, parsers (csv/json/pdf),
│ │ │ # analytics, watchlist, reporting, report_pdf,
│ │ │ # connectors, retention, enrichment plugins
│ │ └── workers/ # celery app + tasks (ingest, enrichment, retention)
│ ├── alembic/ # migrations
│ ├── seed.py # idempotent sample-data loader
│ ├── sample_data/ # Flock-style CSV + JSON + PDF exports
│ └── tests/ # pytest: pipeline + analytics (17 tests)
└── frontend/ # Next.js App Router (TypeScript) - 17 routes
audit_logs row (actor, action, entity, metadata).X-API-Key header.daily-retention Celery beat task.SIGHTLINE_STORAGE_BACKEND - evidence and raw import blobs both flow through it.FastAPI · SQLAlchemy 2.0 · Alembic · PostgreSQL · Redis · Celery · Pydantic · python-jose · bcrypt · pdfminer.six · reportlab · boto3 · Authlib · Next.js 14 · React 18 · TypeScript · Leaflet.