docs: add #34 user-scoped viewer tokens, remove SUGGESTIONS.md
- CLAUDE.md: document planned user-scoped token scope (account_id filter) - TODO.md: add #34 spec, drop stale SUGGESTIONS.md reference - SUGGESTIONS.md: deleted — fully superseded by TODO.md + CLAUDE.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4dfbae49a4
commit
d542357855
@ -51,6 +51,7 @@ Read-only access for DPOs and reviewers. Key invariants:
|
||||
- **`app.secret_key`** — derived from `machine_id` bytes so Flask sessions survive restarts. Set once at startup in `gdpr_scanner.py`; do not override it.
|
||||
- **`GET /api/db/flagged`** — returns `get_session_items()` (last completed scan session, joined with dispositions), filtered by `session["viewer_scope"].role` when set. Used exclusively by `_loadViewerResults()` in `results.js`. Do not confuse with `get_flagged_items()` (single scan_id, no disposition join).
|
||||
- **Rate-limit state** (`_pin_attempts` dict in `routes/viewer.py`) — in-memory only, resets on server restart. Intentional — a restart clears lockouts without a persistent store.
|
||||
- **User-scoped tokens (planned #34)** — scope `{"user": "alice@school.dk"}` will filter `GET /api/db/flagged` by `account_id` (indexed column, already populated: M365 → UPN, Google → email). File-scan items have `account_id = ""` and won't appear. Server enforcement mirrors the role filter: `user = session.get("viewer_scope", {}).get("user"); if user: add WHERE account_id = user`. Do not combine `user` + `role` in a single scope — they are orthogonal use cases.
|
||||
- **Token onclick attributes** — Copy/Revoke buttons in `_renderTokenList()` pass the token as a single-quoted JS string literal (`'\'' + tok.token + '\''`), never via `JSON.stringify`. `JSON.stringify` produces double-quoted strings that break the surrounding `onclick="…"` HTML attribute.
|
||||
- **Settings Security pane** — Admin PIN and Viewer PIN groups live in `stPaneSecurity`, not `stPaneGeneral`. `switchSettingsTab('security')` in `sources.js` triggers both `stLoadPinStatus()` and `stLoadViewerPinStatus()`. The Share modal Configure button opens `openSettings('security')`.
|
||||
- **`stClearViewerPin` guard** — validates that the current-PIN field is non-empty client-side before sending the DELETE request; shows an inline error and focuses the field if empty.
|
||||
|
||||
1537
SUGGESTIONS.md
1537
SUGGESTIONS.md
File diff suppressed because it is too large
Load Diff
16
TODO.md
16
TODO.md
@ -1,6 +1,6 @@
|
||||
# TODO — Pending features and sustainability
|
||||
|
||||
Quick overview of what's still to be done. Full details in [SUGGESTIONS.md](SUGGESTIONS.md).
|
||||
Quick overview of what's still to be done.
|
||||
|
||||
---
|
||||
|
||||
@ -48,6 +48,20 @@ Fixed by adding `M365DriveNotFound(M365Error)` exception, raising it from `_get(
|
||||
|
||||
---
|
||||
|
||||
### #34 — User-scoped viewer tokens
|
||||
Extend viewer token scope from `{"role": "student"|"staff"}` to also support `{"user": "alice@school.dk"}`, filtering `flagged_items` by `account_id`. Lets a single employee see only their own flagged files.
|
||||
|
||||
**Infrastructure already in place:** `account_id` is an indexed column on `flagged_items`, populated for M365 (UPN) and Google (email). File-scan items have `account_id = ""` and won't appear in user-scoped views — document this in the token-creation UI.
|
||||
|
||||
**Changes needed:**
|
||||
1. Token creation UI — add a "specific user" option (email input) alongside the role dropdown
|
||||
2. `GET /api/db/flagged` — filter by `account_id` when `session["viewer_scope"].get("user")` is set (same pattern as existing role filter)
|
||||
3. Viewer header — show locked identity (similar to locked `#filterRole` for role-scoped tokens)
|
||||
|
||||
**Size:** Small · **Priority:** Medium
|
||||
|
||||
---
|
||||
|
||||
### #32 — Windowed mode for Profiles, Sources, and Settings ✗ Won't do
|
||||
The workflow is sequential (configure → scan → review), not parallel — there is no realistic scenario where a modal and the results grid need to be open simultaneously. The Sources panel is already visible in the sidebar. Option A (the least-work path) still loads the full 3800-line JS stack twice. Closed.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user