This file is read automatically by Codex at session start.
Read these before doing anything else on any task:
package.json— check existing deps before suggesting new onesdocs/ai/sessions/ACTIVE.md— check active workstreams; do not touch in-progress areassql/migrations/README.md— current migration statedocs/DATABASE_CONNECTION.md— DB access rules;npm testrequires Docker; use unit-only flags locallydocs/SSM_ACCESS.md— EC2/SSM access; read before any DB or production operationdocs/schema/observations-sources.md— before any query touching observation/wigle datadocs/ai/decisions/— scan ADRs before any architectural decision
ShadowCheck is a SIGINT forensics platform for wireless network threat detection. It analyzes WiFi, Bluetooth, and cellular observations to identify surveillance devices.
Stack: Node.js 22 + Express (CommonJS), React 19 + Vite (ES modules), PostgreSQL 18 + PostGIS 3.6, Redis, Docker, AWS EC2/SSM, TypeScript throughout.
Network types: W (WiFi), E (BLE), B (Bluetooth), L (LTE), N (5G NR), G (GSM)
client/— React 19/Vite frontend (ES modules, TypeScript)server/— Express API backend (CommonJS, TypeScript)src/api/routes/v1/— Route definitions; sub-routers underadmin/,wigle/, etc.src/services/— Business logicsrc/repositories/— Data access layer (SQL here only)
etl/— Import, transform, enrichment pipelinesql/migrations/— Live runner path — DO NOT touch without explicit instructiontests/— Jest unit and integration testsdocs/ai/decisions/— Architecture Decision Recordsdocs/schema/— Table/column reference docs (read before writing queries)
npm run build # Frontend + server → dist/
npm run dev # Nodemon backend (port 3001)
npm run dev:frontend # Vite dev server (port 5173)
npm test # Jest suite
npm run test:cov # With coverage (70% threshold)
npm run lint # ESLint
npm run lint:fix # Auto-fix
npm run lint:boundaries # Verify no client→server importsBackend three-tier: Routes validate → Services hold logic → Repositories hold SQL. SQL never appears in route handlers.
CRITICAL — module systems:
- Backend: CommonJS (
require/module.exports) - Frontend: ES modules (
import/export) - Never mix them
Database user separation:
// Read (default)
const { query } = require('../config/database');
// Write (admin only)
const adminDb = require('../services/adminDbService');Admin route prefix: All import sub-routes live under /admin/ prefix (e.g., /api/admin/import-history). The adminRoutes router is mounted at app.use('/api', adminRoutes) — sub-route paths must include /admin/.
No sed on EC2: Use proper file editors, not sed/awk/echo pipelines. Patches to running files on EC2 have caused data loss.
No dist patches: Never edit files in dist/ directly. Always rebuild from source via scs_rebuild.sh.
EC2 access: SSM only — instance i-06380d0c9c99f6124, profile shadowcheck. Secrets from shadowcheck/config in Secrets Manager. Never open port 22.
CRITICAL — EC2 rebuild/deploy rule (non-negotiable):
- ALWAYS use
scs_rebuild.shfor any rebuild, redeploy, or container restart on EC2. - NEVER run:
docker build,docker compose build,docker compose up,docker restart, or any raw docker deploy command on EC2. scs_rebuild.shprotects SSL certs, EBS volumes, and permissions. Raw docker commands bypass all of this.- If a fix requires a rebuild: commit, push to master, then run
scs_rebuild.shon EC2. - Permitted docker commands on EC2 (read-only):
docker logs,docker execfor psql/redis queries,docker ps,docker inspect. - These rules apply to ALL agents without exception.
Approved shell patterns:
# DB access via SSM — never write password to disk
DB_PASS=$(aws secretsmanager get-secret-value --secret-id shadowcheck/config \
--region us-east-1 --query SecretString --output text | \
python3 -c "import sys,json; print(json.load(sys.stdin)['db_admin_password'])")
docker exec -e PGPASSWORD=$DB_PASS shadowcheck_postgres psql \
-U shadowcheck_admin -d shadowcheck_db -c "<SQL>"
# Rebuild EC2 stack (the ONLY approved rebuild method)
export HOME=/home/ssm-user && cd /home/ssm-user/shadowcheck && bash deploy/aws/scripts/scs_rebuild.sh| Role | Purpose |
|---|---|
shadowcheck_admin |
DDL owner — use for all psql operations via SSM |
shadowcheck_user |
App runtime — read-only, limited access |
postgres |
Does NOT exist in this container setup |
Always use -v ON_ERROR_STOP=1 on every psql execution.
- NEVER write secrets to disk
- NEVER commit
.envcontents — only.env.example - No raw SQL string concatenation — parameterized queries only
- Validate all inputs with Joi or Zod
NEVER without explicit approval in the current prompt:
git commit— show exact diff and message firstgit push— requires explicit "yes"git stash pop/git stash drop— list contents first--forceon any git operation — never
For every change, in this exact order:
- Make the change
npm run lintornpx eslint <filepath>npx tsc --noEmit- Run relevant tests
- Report PASS or the exact failure output
- Stop for approval before committing
Before any git commit, ALL of these must pass (in order):
- Lint:
npm run lint→ zero errors - Type Check:
npx tsc --noEmit→ no TypeScript errors - Test Suite:
npm test→ all tests pass (70% coverage threshold enforced)
Test Coverage Standards:
- Behavior changes require regression tests
- New features require full test coverage (70% threshold)
- SQL queries require JSDoc + schema documentation
- New endpoints require entry in
client/src/config/apiTestEndpoints.ts
Test Structure:
- Unit tests:
tests/unit/— isolated function tests, mock all dependencies - Integration tests:
tests/integration/— endpoint tests with mocked database - Setup utilities: Import from
tests/setup.ts
Running Tests:
npm test # All tests
npm run test:watch # Watch mode
npm run test:cov # With coverage report
npx jest tests/unit/file.test.ts # Single file
npx jest -t "test name pattern" # Tests matching patternSee docs/workflow/TESTING_STANDARDS.md for complete testing guidelines.
- Secrets shall never be written to disk.
- AWS Secrets Manager shall remain the source of truth for secrets.
- Core tables shall remain canonical.
- Enrichment data shall live in separate source-owned tables.
- Cross-source merging shall happen in views or materialized views, not core tables.
- Source precision shall be preserved end-to-end.
- Rounding, truncation, and shortening shall remain presentation concerns only.
- Refactors shall not leave cruft, duplicate paths, or half-migrated code behind.
- Behavior changes require regression tests; new features require test coverage.
- Bootstrap, restore, import, and upgrade are separate contracts and must be validated separately.
- Entry in
client/src/config/apiTestEndpoints.ts - JSDoc comment on the route handler
- If it touches DB schema: a note in the relevant
docs/schema/file
- JSDoc on the query builder function
- If schema changes: update
docs/schema/before the PR
These are non-negotiable. Do not commit a new route without all three.