diff --git a/CHECKLIST.md b/CHECKLIST.md index 747d867..e0120df 100644 --- a/CHECKLIST.md +++ b/CHECKLIST.md @@ -110,6 +110,19 @@ Isolation audit (run after any change to desktop CSS/JS to confirm no mobile reg - [ ] `sudo -u fenja node /opt/fenja/bin/joins.js stats` totals match what you see in `list` - [ ] Logged out: `curl -X POST https://project-bifrost.fenja.ai/api/bifrost-join` → 401 (auth gate holds) +## H1b. After changes to engagement event tracking (events) + +- [ ] [browser, logged out] Log in fresh via the entrance form → entrance advances to the welcome step +- [ ] `sudo -u fenja node /opt/fenja/bin/events.js list --type login --limit 5` shows a new row with your email, current timestamp, populated device/os/browser, and a session-ID prefix +- [ ] [browser, logged in] Visit `/timeline` → page loads +- [ ] `sudo -u fenja node /opt/fenja/bin/events.js list --type timeline_view --limit 5` shows a new row with `view=desktop forced=false` (or `view=mobile forced=false` if you tested on a phone UA) +- [ ] [browser] Visit `/timeline?view=mobile` from a desktop UA → mobile page renders +- [ ] `sudo -u fenja node /opt/fenja/bin/events.js list --type timeline_view --limit 5` shows the most recent row with `view=mobile forced=true` +- [ ] `sudo -u fenja node /opt/fenja/bin/events.js summary` includes your email with correct `LOGINS` and `TIMELINE` counts +- [ ] `sudo -u fenja node /opt/fenja/bin/events.js stats` totals match what `list` shows; device breakdown reflects the views you generated +- [ ] `sudo -u fenja node /opt/fenja/bin/events.js for ` shows full per-user history +- [ ] No 500s in `journalctl -u fenja -n 100` from the test traffic + ## H2. After changes to the hidden admin page (`/fenjaops`) Covers `admin/`, the `/api/fenjaops/*` endpoints, and `requireAdmin`. diff --git a/CLAUDE.md b/CLAUDE.md index 9ba8051..2e7cc23 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,6 +18,8 @@ npm start # production start node bin/invite.js add # invite (also: remove, list) node bin/joins.js list # read join-CTA click log # (also: summary, for , stats) +node bin/events.js list # read engagement event log + # (also: summary, for , stats) ``` There is no test suite, linter, or build step. Verification is the checklist in `CHECKLIST.md`, primarily by walking the entrance → code → timeline flow in a browser. @@ -67,4 +69,4 @@ These are from `PROJECT.md`. A change that breaks any of them is a security regr - ESM imports only, Node 20+. - File headers use the `// ─── ... ───` comment banner style. Match it when editing existing files. -- `bin/invite.js` and `bin/joins.js` are the admin CLIs — there is no web UI for either by design. `invite.js` manages the invite list; `joins.js` reads the CTA click log. +- `bin/invite.js`, `bin/joins.js`, and `bin/events.js` are the admin CLIs — there is no web UI for them by design. `invite.js` manages the invite list; `joins.js` reads the final-CTA click log; `events.js` reads the engagement event log (logins, timeline views). diff --git a/OPERATIONS.md b/OPERATIONS.md index 02a2804..a1cd2b9 100644 --- a/OPERATIONS.md +++ b/OPERATIONS.md @@ -87,6 +87,37 @@ sudo -u fenja sqlite3 /opt/fenja/data/fenja.sqlite \ "SELECT email, datetime(clicked_at/1000,'unixepoch') FROM bifrost_joins ORDER BY clicked_at DESC;" ``` +## Reading engagement events + +Logins and timeline page views are logged to the `events` table. Each row carries the user's email, a timestamp, the session ID, and device fields parsed from the User-Agent (`device_type`, `os`, `browser`). Use `bin/events.js` to read it: + +```bash +# Every event, newest first (filter with --type, page with --limit) +sudo -u fenja node /opt/fenja/bin/events.js list +sudo -u fenja node /opt/fenja/bin/events.js list --type login --limit 50 + +# One row per user — login count, timeline-view count, last seen +sudo -u fenja node /opt/fenja/bin/events.js summary + +# Full event history for a single user +sudo -u fenja node /opt/fenja/bin/events.js for someone@example.com + +# Totals per event type + device-type breakdown +sudo -u fenja node /opt/fenja/bin/events.js stats +``` + +Events recorded: + +- `login` — written on `POST /auth/login` success. One row per fresh login (cookie-loss re-logins included). The `meta` column is empty. +- `timeline_view` — written on every `GET /timeline`. `meta` is `{view: "mobile"|"desktop", forced: true|false}`; `forced=true` means the user passed `?view=mobile` or `?view=desktop` to override the UA guess. + +For ad-hoc SQL: + +```bash +sudo -u fenja sqlite3 /opt/fenja/data/fenja.sqlite \ + "SELECT event_type, email, datetime(occurred_at/1000,'unixepoch'), device_type, os, browser FROM events ORDER BY occurred_at DESC LIMIT 50;" +``` + ## Service control ```bash