Files
PubScript/CHUNK#10.md
T

4.8 KiB
Raw Blame History

CHUNK #10 — Multi-User Admin & Sharing

Duration: ~2 days · Prereqs: CHUNK #2 (auth skeleton, ServerAdapter) · Follows: CHUNK #9 · Unblocks: CHUNK #11 (parity: admin works in web + desktop identically)

Purpose: Complete the multi-user product: full admin user management (create, disable, change role), project sharing with read/edit permissions, an audit log, and hard multi-tenant isolation — all reachable from both the web app and the desktop app identically.


Steps

1. Admin API (server/src/routes/admin.ts)

  1. GET /api/admin/users — list all users (name, email, role, status, lastActive).
  2. POST /api/admin/users — create a user (email + role; server generates a one-time password or sends an invite link).
  3. PATCH /api/admin/users/:id — change role (admin/author) or disable/enable.
  4. GET /api/admin/activity — audit log tail (filtered by user/action/date).
  5. GET /api/admin/stats — instance-wide: user count, project count, storage used.
  6. All routes behind requireAdmin middleware.

2. Sharing API (server/src/routes/projects.ts — extend Chunk 2)

  1. POST /api/projects/:id/shares — invite by email, grant read/edit.
  2. PATCH /api/projects/:id/shares/:userId — change permission.
  3. DELETE /api/projects/:id/shares/:userId — revoke.
  4. POST /api/projects/:id/transfer — transfer ownership (owner only).
  5. GET /api/projects — return owned ∪ shared (with perm on each).

3. Access control (server/src/auth.ts — extend Chunk 2)

  1. canAccessProject(projectId, perm) — enforces owner OR shared-with (correct perm). Middleware on every content route.
  2. Multi-tenant isolation: every query filters by project_id the user can access. A user can never read another's project — enforced at the SQL layer, not just the app layer.
  3. Session revocation: disabling a user → their session token is invalidated within one event round-trip (Chunk 2 acceptance criterion).

4. Audit log (server/src/db.ts — extend Chunk 2)

  1. audit(id, at, user_id, action, detail JSON) — log: user create/disable, role change, share grant/revoke, ownership transfer, project delete.
  2. GET /api/admin/activity returns the tail; retention: 1 year (v1, no purge).

5. Admin UI — web (apps/web/src/features/admin/AdminView.tsx)

  1. Users tab: table (name, email, role, status, lastActive); "Create user" modal; inline role toggle; disable/enable switch.
  2. Sharing tab (per project): list shared users with permission dropdown; transfer ownership; revoke.
  3. Activity tab: filterable audit log table.
  4. Stats tab: instance-wide counters.

6. Admin UI — desktop parity

  1. The desktop app renders the same AdminView (it's part of the shared React app). No desktop-specific admin code — parity is structural.
  2. Desktop uses bearer token for auth (Chunk 2); web uses cookie. Both hit the same API.

7. Invite flow

  1. POST /api/admin/users with sendInvite: true → generates an invite token, stores a pending invite, (v1) logs the invite link to the audit log; the invitee clicks → /invite/:token → sets password → becomes an author.

8. Tests

  1. Unit: canAccessProject — owner can edit; shared-read can read not edit; unrelated user gets 403.
  2. Integration: admin creates user → user logs in → sees only shared projects; admin disables user → user's next API call gets 401.
  3. Integration: project isolation — user A's adapter never returns user B's project (contract suite extension).
  4. E2E: admin creates a user, shares a project (edit) → user sees it; revoke → it disappears.

Acceptance criteria (all must pass)

  • Admin creates/disables/changes-role of users from the web app.
  • Admin manages sharing (grant/revoke/transfer) from the web app.
  • Admin sees activity log + instance stats.
  • The same admin UI works identically in the desktop app.
  • A shared-with-read user cannot edit; a shared-with-edit user can.
  • Multi-tenant isolation: user A can never read user B's project (enforced at SQL layer).
  • Disabling a user revokes their session within one event round-trip.
  • Audit log records all admin actions.
  • Contract suite still green on both adapters.

Definition of done

PubScript is a real multi-user product: admins manage users and sharing from both web and desktop, projects are shared with granular permissions, and isolation is guaranteed at the database layer.

Risks & fallbacks

  • Permission bugs → data leaks → enforce isolation at the SQL layer (WHERE project_id in accessible); contract suite tests cross-user access.
  • Session revocation latency → check token validity on every request (small cost) rather than caching; cap the auth lookup.
  • Invite email delivery → v1 logs the invite link (no SMTP); document SMTP as a later addition.