Commit Graph

10 Commits

Author SHA1 Message Date
b05047d8e5 vrek: retire icons goal, add icon principle
Retires gol-m8je1wc (icons done for now) and records principle
pri-8ev5m89, derived from dec-1vnz5fw. Icons come from lucide-react,
always accompany text, are aria-hidden, use standard Tailwind sizes,
map one concept to one icon, and are tested by lucide-<name> class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 12:35:54 -05:00
190191df92 Add Lucide icons: camera status badge, actions and warnings
Adds lucide-react (vrek dec-1vnz5fw, chosen over Heroicons and React
Icons) for the icons goal gol-m8je1wc.

- Camera status badge on each card (iss-scj42jq): Live, Connecting,
  Needs login, Not activated, Offline, Session ended. Each is an icon
  plus a visible label, derived from existing query state with no
  extra device calls. Logic in src/app/camera-status.tsx.
- Action icons (iss-chrdd0v): scan (radar, then spinner), refresh
  rate, change or forget login, retry, the camera web page link
  (replaces ↗), save, sign in and sign out.
- Warning and error icons (iss-egy082x): unsecured banner, setup
  panel, inline errors, session-ended notice, login and setup
  headings.

Icons are decorative (aria-hidden), spinners respect reduced motion,
and every accessible name is unchanged (all 403 prior tests pass
untouched). 416 tests, 99.9% line coverage. The vitest threshold
comment now points to principle pri-be2smzk. Refreshes the vrek
export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 12:33:16 -05:00
5d181f3b3b Enforce admin login: login, first-run setup, proxy and access checks
Completes securing the web front end (vrek gol-wqf95dq, iss-r5vrjx7).

- /login: Server Action with a generic error, same-site-only redirect
  back to ?next=, and throttling of failed logins (10 per address and
  100 overall per 15 min). The header shows "Signed in as" with
  Sign out (iss-nj9wmwp).
- First run with no admin: instrumentation prints a one-time setup
  code, shared with the app through globalThis. /setup requires it,
  and 5 wrong codes rotate it. "Skip for now" runs unsecured for the
  browser session behind a red warning banner on every page
  (iss-9nxdndr).
- src/proxy.ts: optimistic redirects to /login or /setup, 401 for
  the API, and the 12 h sliding session refresh. requirePageAccess()
  and apiAccessDenied() re-check in the page and all 6 route handlers
  (iss-76d5wrb).
- An expired session now shows "Your session has ended" instead of
  the camera-login form.
- README documents in-app setup, skipping and signing in.

Verified with unit tests (383, 99.9% line coverage), end to end
against `next start`, and manually in a browser by the user.
Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 11:58:20 -05:00
462141aa35 Add admin login foundations: scrypt admin file, CLI, sessions
Groundwork for securing the web front end (vrek gol-wqf95dq). The app
does not enforce login yet.

- src/lib/admin-file.ts: the admin file at ADMIN_AUTH_FILE (default
  .data/admin.json). scrypt hashing (N=2^16, random salt, bounded
  parameters, constant-time compare), zod-validated reads where a
  malformed file is an error, and atomic 0600 writes that won't
  replace an existing admin without overwrite. Plain Node, so the
  CLI can share it (iss-mffqscg).
- src/lib/admin-auth.ts: server-only app layer; failed logins always
  cost one hash.
- scripts/create-admin.mts + `npm run admin:create`: create or reset
  the admin outside the app, interactive (hidden, confirmed) or piped
  (iss-7xmka20). The README documents it, a no-npm Node one-liner,
  the file format, and password reset.
- src/lib/session-token.ts and session.ts: stateless HMAC-signed
  session cookie, keyed from the password hash so a password change
  ends every session, with a 12 h sliding window (iss-e27nb70,
  dec-f0xar8r).

281 tests, 99.8% line coverage. Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 09:46:40 -05:00
a174d7a2d6 Keep runtime data out of Next's output file tracing
next build warned that the env-dependent registry and credential-store
paths made Turbopack trace the whole project (vrek iss-jvxcd1n).
Marking only the readFile calls cleared the warning, but it still
traced .data/cameras.json and the encrypted .data/credentials.json,
which a standalone deployment would copy from the build machine.

A /* turbopackIgnore: true */ on each default path.join(process.cwd(),
".data", ...) fixes both. The traced files for every route now include
nothing from src/, public/ or .data/. The env-var overrides the tests
use still work. Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 09:23:34 -05:00
4931c3af83 Reach 99.8% test coverage and enforce a 95% floor
- Route tests for camera info, snapshot and credentials (vrek
  iss-nc2tj7c): input validation, store-only-after-verify, reconnects
  after login changes, and fixed error messages with no upstream text.
- Providers and layout tests (iss-nc5w0j8).
- Discovery tests for onvif.ts (iss-3bg4r6e): multicast parsing,
  unicast sweep batching and subnet limits, de-duplication and
  merging. They run on a fake network, replacing onvif Discovery,
  node:dgram and node:os, per new vrek principle pri-e14bahk
  (replaceable transport; tests never touch the real network).
- coverage.thresholds.lines = 95, so `npm run coverage` fails below
  the goal (iss-zjpc22k).

200 tests, 99.77% line coverage. Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 09:17:55 -05:00
31026559b7 Test camera.ts: connection handling, errors and snapshot auth
Adds 47 tests for camera.ts (vrek iss-qak2mz8), bringing it to 100%
line coverage. A scripted stand-in for the onvif Cam class drives the
connect outcomes: profiles, warnings, inactive devices, and login
errors. Snapshots run over real HTTP against a local server with real
Digest and Basic 401 challenges. Also covers isAllowedHost edge cases.

Overall line coverage is 72.4% (143 tests). Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 09:07:53 -05:00
33c12ea70c Stop camera routes echoing raw error messages
cameraErrorResponse now returns fixed text for each error class and
logs the original server-side. Upstream ONVIF/SOAP responses, socket
errors and credential-file paths no longer reach the browser (vrek
iss-tz5s098). CameraAuthError gains a missingLogin flag so the UI can
still tell "no login saved" apart from "login rejected".

Tests throw errors carrying a fake password and file path, and check
neither appears in any response. Closes the dashboard migration (vrek
iss-qbh3541). Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 09:03:46 -05:00
870b4cd2af Move dashboard client onto React Query hooks
Adds src/app/camera-queries.ts: React Query hooks over our own routes,
with each camera's queries keyed ['camera', id]. The camera card,
snapshot polling, login form and network scan use these hooks instead
of hand-rolled fetch/useEffect state (vrek iss-2fm6x2y, iss-ksxmctm,
iss-m032zwq, iss-8hfq2y2).

- Snapshot polling pauses in hidden tabs, never overlaps a slow
  frame, and stops after a failure until Retry. Each frame's object
  URL is created and revoked in one effect, so none leak under Strict
  Mode.
- Saving or forgetting a login resets only that camera's queries.
- New "Forget saved login" action, shown for stored logins.
- Fix: a scan timeout typed below 1 s now clamps to 1 s instead of
  falling back to 5 s.

Adds jsdom component tests (test/dom.tsx helpers): 93 tests, line
coverage 54.3%. Refreshes the vrek export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 09:01:34 -05:00
97a6b59cfe Track vrek export, MCP config and IDE VCS mapping
Commits .vrek/log.ndjson, the vrek export of goals, principles,
decisions, issues and evidence (restore with vrek_import), plus
.mcp.json, which wires the vrek MCP server, and .idea/vcs.xml. The
SQLite database and its -wal/-shm files are local state and are
gitignored; the export is refreshed and committed periodically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 08:52:49 -05:00