Skip to content

feat: RBAC+web, scoped RBAC (org/event) with invitations + member management + admin web UI - #2

Open
cbot918 wants to merge 7 commits into
devfrontierhq:mainfrom
cbot918:feature/roleAuthtication
Open

feat: RBAC+web, scoped RBAC (org/event) with invitations + member management + admin web UI#2
cbot918 wants to merge 7 commits into
devfrontierhq:mainfrom
cbot918:feature/roleAuthtication

Conversation

@cbot918

@cbot918 cbot918 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

中文快速:

  1. RBAC
  2. 一個內含的 web 測試介面

Summary

Builds out the scoped RBAC system (modeled after KKTIX's org/event permission
model) and adds an admin web UI to manage it. Extends the existing
JwtAuthGuard/PermissionGuard foundation with a two-layer scope, an email
invitation flow, a member-management module, and a React admin front end.

What's included

Backend

  • Scoped RBAC — three scopes (PLATFORM / ORG / EVENT); org permissions
    cascade to events under that org (resolved at request time). JWT stays minimal
    ({ sub, v }); permissions resolved server-side and cached, with a
    tokenVersion bump to revoke instantly.
  • Email invitation flow — org- and activity-scoped invitations with a
    pending → accepted/rejected state machine (7-day expiry), resend included.
  • Member management module — CRUD API for platform members.
  • e2e safety guardjest-e2e.setup aborts unless TEST_DATABASE_URL is
    set and local, so the destructive e2e suite can never touch a remote DB.

Frontend (web/, Vite + React + shadcn/ui)

  • Admin UI for members, roles, permission codes, and organization-member role
    assignment. Talks to the API via a relative base + dev proxy (no hard-coded
    origin), so it runs against the backend on any port.

Status / scope

Honest about what's done vs. pending, so review expectations are clear:

  • ✅ Backend: both org & event scopes + the full invitation state machine.
  • ✅ Frontend: organization-scope role assignment (verified end-to-end).
  • ⏳ Not yet in the frontend: event-scope member management UI and the
    invitation UI (backend endpoints for both already exist). Tracked in
    HANDOFF-permission-admin.md.

Testing

  • Existing unit suite green (TokenVersion + permissions cache RBAC).
  • e2e DB guard verified negatively: aborts when TEST_DATABASE_URL is unset or
    points at a remote host.
  • Web flows manually verified against a live backend: dev-login, members list,
    roles + permission-code tabs, and org-member role assignment (assignment
    persisted to the DB).

Happy to walk through anything or adjust scope. "Allow edits by maintainers"
is enabled
— feel free to push test commits or tweaks directly to this branch.

cbot918 and others added 7 commits June 7, 2026 22:43
Replace JWT-embedded permissions with TokenVersion + Cache strategy:
- Add tokenVersion (Int, default 1) to Member model
- Minimize JWT payload to { sub, v } only
- Cache permissions & tokenVersion via @nestjs/cache-manager on login
- JwtStrategy.validate() verifies tokenVersion and loads permissions from cache (DB fallback on miss)
- Add AuthService.bumpTokenVersion() to revoke tokens immediately
- Add PermissionsCacheService for centralized cache operations

Benefits:
- Tokens can be revoked instantly without waiting for JWT expiry
- JWT payload stays small regardless of permission count
- Zero DB queries on requests when cache is warm

Verified with manual E2E test: old token returns 401 after bump, new login restores access.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add comprehensive unit tests for the new auth architecture:
- PermissionsCacheService: set/get/invalidate for permissions & tokenVersion
- JwtStrategy: cache hit/miss, tokenVersion mismatch, revoked token, deleted user
- PermissionGuard: unauthenticated, missing permissions, all permissions granted
- AuthService: getUserPermissions, devLogin, bumpTokenVersion, invalidateUserCache

Also update jest config:
- transformIgnorePatterns: allow ESM packages (arctic, passport-jwt)
- moduleNameMapper: map src/ paths & strip .js extensions for Prisma 7

26 tests passing, 0 failing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
…yle)

Reworks the flat global RBAC into a two-layer scoped model and adds an
email invitation flow, modelled on KKTIX's organization/activity permissions.

- schema: add Organization, Membership (replaces global MemberRole, carries
  scopeType + org/activity FK), Invitation; Role.scope, Activity.organizationId.
  Migration carries existing member_roles over as PLATFORM-scoped.
- auth: getScopedPermissions returns { platform, org, event } buckets, cached;
  JWT still only carries { sub, v } (reuses tokenVersion revocation).
- guard: @RequirePermissions({ scope, param, perms }); PLATFORM grants apply
  everywhere; ORG permissions cascade down to that org's events.
- api: Organization CRUD (creator auto-becomes Owner), scoped membership
  management, full invitation flow (invite/accept/reject/resend/revoke,
  7-day expiry, email-match, MailService log stub).
- seed: scoped permission catalogue + KKTIX default roles per scope.
- dev: GET /roles/catalog (dev-only) + extended /ui mock for manual testing.
- docs: KKTIX research note + HANDOFF.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds MemberModule (controller/service/dto) for listing and managing
platform members, registered in AppModule. Minor activity dto/service
tweaks + specs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vite + React + shadcn/ui admin for the scoped RBAC: members, roles,
permission codes, and organization-member role assignment. Talks to the
backend via a relative /api base + vite proxy (no hard-coded origin).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jest-e2e.setup aborts unless TEST_DATABASE_URL is set and points at
localhost, so the destructive e2e suite can never wipe a remote DB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…kups

Adds HANDOFF-permission-admin.md (frontend progress + TODO), refreshes
.env.example / docs, and ignores *.env.bak so local secret backups can
never be committed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant