βββββββββββββ ββββββ βββ ββββββ βββββββββ ββββββββββ βββ
ββββββββββββββ ββββββ βββββββββββββββββββββββββββββββ βββ
βββ βββββββ βββββββ ββ βββββββββββ βββ βββ ββββββββ
βββ βββ βββββββ ββββββββββββββββββ βββ βββ ββββββββ
βββββββββββ βββββ βββββββββββββ βββ βββ βββββββββββ βββ
ββββββββββ βββ ββββββββ βββ βββ βββ ββββββββββ βββ
Turn fragmented public records into legible, queryable intelligence.
π Live Status Β· π£οΈ Roadmap Β· π Architecture Β· π Security Β· π Issues
CIVWATCH is a full-stack civic intelligence platform that transforms fragmented public records β agendas, minutes, budgets, contracts, votes β into normalized, anomaly-aware timelines. Designed for residents, journalists, and civic analysts who need more than PDFs.
Current state (April 11, 2026): Phase 1 Foundation is complete. Phase 2 Feature Completeness is active (window: Apr 4β20). The ML service runs live DBSCAN anomaly detection on :5000. The backend serves /api/status and /api/health on :3000. PostgreSQL is wired and storing data. JWT auth middleware is live. The React frontend nav route for the AnomalyDashboard is wired. Three critical Phase 2 gaps remain:
- Feature extraction type errors in
dataAnalyzer.tsblocking verified vector output (#3) - DBSCAN execution path β no scheduler/trigger wired from
anomaly_scores(manual-call only) - ML
/predictendpoint β missing schema + return β‘ System Status
Last verified: April 11, 2026 β 3:56 AM CDT
| Component | Status |
π’ Backend β /api/status |
LIVE β GET :3000/api/status β {"status":"ok"} |
π’ Backend β /api/health |
LIVE β GET :3000/api/health β uptime + version |
π’ Backend β /api/alerts |
LIVE β POST/GET with PostgreSQL queries |
π’ Backend β /api/analytics |
LIVE β routes wired, DB queries active |
| π’ Backend β Auth middleware | DONE β requireAuth JWT validation live |
| π’ Backend β Error handling | DONE β AppError middleware + structured responses |
| π’ ML Service (FastAPI) | LIVE β Server on :5000, CORS enabled |
| π’ ML β Health / Readiness | LIVE β /health + /ready probes confirmed |
π’ ML β DBSCAN /detect |
LIVE β Fully functional, StandardScaler applied |
| π’ ML β Sentiment (single) | LIVE β /analyze/sentiment with TextBlob MVP |
| π’ ML β Batch scoring | LIVE β /analyze/batch 1:1 input/output |
| π’ ML β Anomaly scoring v2 | LIVE β /score/anomaly with z-score + flags |
| π’ PostgreSQL | WIRED β Pool initialized, tables created, routes querying |
| π’ Docker Compose | DONE β All services start; healthchecks fixed (bd55128) |
| π’ CI/CD Pipeline | LIVE β Real tests running (Jest/pytest), 6 security workflows |
| π‘ Anomaly route | PARTIAL β GET /api/anomalies registered, returns empty array |
| π‘ Ingest route | PARTIAL β POST /api/ingest accepts, no storage/forwarding |
| π‘ Feature extraction | BOTTLENECK β dataAnalyzer.ts type errors block real vectors (#3) |
| π‘ Frontend nav | PARTIAL β AnomalyDashboard route wired; data source empty |
| π‘ Dashboard layout | PARTIAL β Components exist; no charts/graphs; no live data (#10) |
| π‘ Redis cache | PLANNED β Client declared; not wired into routes (#5) |
| π‘ GraphQL resolvers | STUB β Schema defined; no resolvers (#6) |
| π‘ Unit tests | PARTIAL β Jest/pytest configured; coverage ~15% (#15) |
| π‘ NLP preprocessing | MVP β TextBlob only; transformers swap planned (#8) |
| π΄ DBSCAN execution path | GAP β No scheduler/trigger wired from anomaly_scores |
π΄ ML /predict endpoint |
NOT STARTED β No schema; returns static JSON; no return binding (#9) |
| π΄ Integration tests | NOT STARTED β No cross-service tests (#15) |
| π΄ WebSocket / Real-Time | NOT STARTED β Streaming layer not built (#12) |
| π΄ Rate limiting | NOT STARTED β No middleware (#7) |
| π΄ E2E tests | NOT STARTED β No user flow tests (#15) |
| π΄ Dark mode | NOT STARTED β No theme support (#13) |
Legend: π’ Done & verified | π‘ Partial / needs work | π΄ Not started / blocked
Prerequisites: Docker & Docker Compose Β· Node.js 20+ Β· Python 3.10+
git clone https://github.com/POWDER-RANGER/CIVWATCH.git cd CIVWATCH
cp .env.example .env
docker-compose up
npm run docker:up
curl http://localhost:3000/api/status
curl http://localhost:5000/health
npm run setup
npm run dev
npm run dev:backend # Node.js API β :3000 npm run dev:frontend # React UI β :4000 npm run dev:ml # FastAPI ML β :5000
The anomaly detection engine is live and fully independent. It runs on :5000 and is the most production-ready component in the stack.
curl -X POST http://localhost:5000/detect
-H "Content-Type: application/json"
-d '{
"data": [
[1.2, 0.5, 200000],
[1.0, 0.4, 195000],
[8.9, 7.1, 4500000]
]
}'
Response: DBSCAN cluster labels β outliers flagged as -1. StandardScaler normalization is applied before every clustering pass.
| Step | Status |
Data ingestion (POST /detect) |
β Live |
Normalization (StandardScaler) |
β Live |
| Clustering (DBSCAN / scikit-learn) | β Live |
Outlier flagging (Label -1) |
β Live |
Sentiment analysis (/analyze/sentiment) |
β Live |
Batch scoring (/analyze/batch) |
β Live |
Anomaly scoring v2 (/score/anomaly) |
β Live |
| Model persistence | π΄ Planned |
| Transformers swap (M2 NLP) | π΄ Planned |
| GPU optimization | π΄ Planned |
CIVWATCH/
βββ π backend/ Node.js/Express API
β βββ /api/status β
LIVE
β βββ /api/health β
LIVE
β βββ /api/alerts β
LIVE
β βββ /api/analytics β
LIVE
β βββ /api/anomalies β οΈ PARTIAL (empty array)
β βββ /api/ingest β οΈ PARTIAL (accepts, no processing)
β
βββ π frontend/ React scaffold (nav route wired)
β βββ AnomalyDashboard β οΈ PARTIAL (no data binding)
β
βββ π ml/ Python FastAPI β ML engine
β βββ POST /detect β
DBSCAN live
β βββ GET /health β
LIVE
β βββ GET /ready β
LIVE
β βββ POST /analyze/sentiment β
LIVE
β βββ POST /analyze/batch β
LIVE
β βββ POST /score/anomaly β
LIVE (z-score + flags)
β
βββ π src/analytics/ dataAnalyzer.ts (mean/median/stddev) β οΈ Type errors (#3)
βββ π tests/ Jest + pytest configured, coverage ~15%
βββ π docs/ Architecture, API spec, testing strategy
βββ π demo/ Demo scenarios and scripts
βββ π civwatch-desktop/ Electron wrapper (Phase 1 complete)
βββ π .github/ GitHub Actions: 6 security workflows
βββ π³ docker-compose.yml Multi-service orchestration (fixed)
βββ βοΈ .env.example Environment config template
βββ π package.json Monorepo root (workspaces)
βββ π requirements.txt Python dependencies
| β | Backend /api/health + /api/status live |
| β | PostgreSQL pool initialized + wired in routes |
| β | ML FastAPI server live on :5000 |
| β | DBSCAN /detect endpoint fully functional |
| β | StandardScaler normalization applied |
| β | JWT auth middleware (requireAuth) live |
| β | Docker Compose healthchecks fixed (bd55128) |
| β | CI/CD pipeline β real tests running |
| β | 6 security scanning workflows (bandit, CodeQL, Semgrep, etc.) |
| β | Electron shell + IPC bridge (PR #102) |
| β | AnomalyDashboard nav route wired (commit 15b1c41) |
π΄ [CRITICAL] Feature extraction β Fix dataAnalyzer.ts type errors; verify real vectors (#3) |
|
π΄ [CRITICAL] DBSCAN trigger β Wire scheduler/trigger from anomaly_scores table |
|
π΄ [CRITICAL] ML /predict β Add feature vector schema + return binding to /anomalies (#9) |
|
π‘ Complete ingest pipeline β POST /api/ingest must store/queue/forward |
|
| π‘ Build React UI components (charts, tables, anomaly visualizations) (#10, #11) | |
| π‘ Implement WebSocket real-time layer (#12) | |
| π‘ Wire Redis caching into alert routes (#5) | |
| π‘ Add GraphQL resolvers (#6) | |
| π‘ Write integration tests (backend-to-ML, frontend-to-backend) (#15) | |
| π‘ Swap TextBlob for transformers (M2 NLP upgrade) (#8) | |
| π‘ Model serialization + persistence (#9) | |
| π‘ Performance profiling |
| π‘ Security audit + penetration testing (OWASP A01βA05) (#17) | |
| π‘ Rate limiting + request throttling (#7) | |
| π‘ Performance optimization β query tuning, load testing | |
| π‘ 80%+ code coverage gate in CI (#16) | |
| π‘ Packaged releases (.exe, .dmg, .AppImage) | |
| π‘ Documentation review + ops runbook (#18) |
Current coverage: ~15% across Jest (Node/TS) + pytest (Python). Target for Phase 2: 50%+. MVP target: 80%+.
npm test
pytest tests/ -v
npm run test --workspaces && pytest tests/ -v
See docs/testing.md for the full testing strategy.
Good first issues β each is fully tracked:
| Task | Issue |
|---|---|
Fix TypeScript type errors in dataAnalyzer.ts |
#3 |
| Wire Redis client into alert routes | #5 |
| Add GraphQL resolvers (Query/Mutation/Subscription) | #6 |
| Build React anomaly visualization components (charts) | #10 |
| Implement WebSocket real-time layer | #12 |
| Write integration tests (backend-to-ML) | #15 |
| Rate limiting middleware | #7 |
| Dark mode theme support | #13 |
See CONTRIBUTING.md for full guidelines. Keep PRs small and focused. Every PR needs a short why in the description.
| File | Purpose |
|---|---|
| STATUS.md | Live per-component implementation matrix (updated Apr 11) |
| IMPLEMENTATION_ROADMAP.md | Phased PR plan (PR0 β PR19) |
| NEXT_PHASE.md | This-week tasks + debugging guide |
| docs/architecture.md | System design, port map, data flow |
| CHANGELOG.md | Version history (Keep a Changelog) |
| SETUP.md | Detailed local environment setup |
| SECURITY.md | Security practices + threat model |
| RESPONSIBLE_DISCLOSURE.md | Vulnerability reporting procedures |
| CREDIBILITY_CHECKLIST.md | Repo health + credibility audit |
| GIT-CRYPT-SETUP.md | Encrypted secrets via git-crypt |
Do not open public GitHub issues for security vulnerabilities. Report via GitHub Security Advisories only.
Full policy β SECURITY.md Β· RESPONSIBLE_DISCLOSURE.md
MIT β see LICENSE.
Built by Curtis Farrar Independent Systems Engineer Β· AI Security Architect Β· Civic Monitoring Keokuk, Iowa, USA
"Make civic data as actionable as a security feed."
This README reflects actual current state β not aspirations. Full truth table β STATUS.md