Agency Admin View

Feature Owner: scorevi (Sean Patrick Caintic)
Module: Dashboards
Priority: P0
Sprint #12: Fully Implemented & Deployed
Date: 2026-06-29


EXECUTIVE SUMMARY

What is this feature?
Agency-level administration dashboard for managing team members, token limits, branding, and reviewing analytics. Protected by authenticateAgencyMember() in app/agency/layout.tsx. Agency layout renders AgencyLayoutClient.tsx with UnifiedSidebar(userRole="agency"). Owner vs member split: only agency owners (verified via agencies.owner_clerk_id — TEXT, Clerk string ID) can manage team, set token limits, and update branding. The ADMIN agency member role was deprecated June 2026 (migration 202606050001 removed ADMIN, added previous_platform_role VARCHAR(50)). Agency member roles: CHECK (IN ('CREATOR','REVIEWER')).

Why does it matter?
Agencies are the B2B unit. Agency admins need to manage their team, control token costs per member, and configure their own branding (logo, SMTP). Without this, every agency action requires a platform admin.

What's the MVP scope?
Fully deployed. Team management (invite, remove, edit roles). Token limit per member. Agency branding (SMTP, logo, themes). Member usage tracking. Owner/member split enforced server-side. AgencyStatusContext with 1-min in-memory cache.


1. USER PAIN POINT & SOLUTION

Current State (Without Feature)

Agencies have no self-service. They must email platform admins to add team members, set limits, or change branding.

Pain Point

Emotional: "I run a training agency but I can't even add my own team members."
Functional: No agency-level administration.
Business Impact: Support burden on platform admins; agencies feel limited.

Future State (With Feature)

Agency owner logs in → sees their agency dashboard → invites team members → sets per-member token limits → configures branding. Fully self-service.

Marketing Hook

"Your agency, your rules. Manage your team, control your costs, own your branding."


2. 4D FRAMEWORK MAPPING

Diagnose

Agency status endpoint (GET /api/agency/status) returns { isMember, isOwner, platformRole, effectiveRole, isViewingAsOther, agency?, membership? } for dashboard orchestration.

Design

Not directly applicable.

Develop

Token limit controls per member shape content production budgets.

Deliver

Reviewer analytics visible on agency dashboard.


3. USER FLOWS

Entry Point

Agency owner/member signs in → auto-routed to /agency. Layout guard authenticateAgencyMember() verifies membership.

Success Criteria

Owner manages team/tokens/branding. Member sees personal usage and team directory.

Main Flow (Happy Path)

Owner — Team Management:

  1. Owner navigates to agency team page

  2. Clicks "Invite Member" → InviteModal.tsx opens

  3. 8-rule invitation validation in lib/agency/member-invitation.service.ts:

    • No self-invite, cannot invite platform ADMINS, cannot invite AGENCY owners, cannot invite LEARNERs

    • Role compatibility check, single-agency constraint, active-only check, owner-only for admin-level invites

  4. Invite sent via POST /api/agency/team/invite/

  5. Member accepts → status becomes ACTIVE

Owner — Token Limits:

  1. Owner navigates to agency admin

  2. Sees per-member token usage (enriched via GET /api/agency/admin/members)

  3. Adjusts member limit → PATCH /api/agency/admin/members/[memberId]/token-limit

Owner — Branding:

  1. PUT/GET /api/agency/branding, POST/DELETE /api/agency/branding/logo, POST /api/agency/branding/smtp-test — all owner-only

Member — Personal:

  1. GET /api/agency/member/usage — personal token consumption

  2. GET /api/agency/member/team — team directory

Edge Cases

  • No data: No members → "Invite your first team member" prompt.

  • API error: Invite fails → error toast with reason (e.g., user already in another agency).

  • Permission denied: Member accessing owner-only pages → redirected.


4. INFORMATION ARCHITECTURE

Primary Information (Always visible)

  • Dashboard: Members, token budget, top usage, review analytics.

  • Team: Member list with roles and statuses.

  • Status: Agency membership context via AgencyStatusContext (1-min cache).

Secondary Information

  • Token usage per member.

  • Agency branding preview.

  • AgencyLegacyWarning.tsx — warning for AGENCY-role users without an agency.

Actions

Primary CTA (Owner): "Invite Member", "Save Limits", "Update Branding".
Secondary Actions: "Remove Member", "Edit Role", "Resend Invite" (POST /api/agency/team/invite/resend/).


5. WIREFRAMES

Excluded — UI is fully developed (AgencyLayoutClient.tsx + sub-pages, InviteModal.tsx, AgencyBanners.tsx, AgencyLegacyWarning.tsx).

6. WIREFLOWS

Excluded.

7. PROTOTYPE

Excluded — production deployed.


8. BACKEND SCHEMA

Database Tables

agencies:
id UUID PK, owner_clerk_id TEXT NOT NULL -- Clerk string ID
name, plan, monthly_token_budget, status
 
agency_members:
id UUID PK, agency_id FK→agencies
user_clerk_id TEXT -- Clerk string ID
role TEXT CHECK (role IN ('CREATOR','REVIEWER')) -- ADMIN deprecated Jun 2026
status TEXT CHECK (status IN ('PENDING','ACTIVE','REVOKED'))
monthly_token_limit INTEGER
previous_platform_role VARCHAR(50) -- For rollback tracking (migration 202606050001)

Invitation Validation (8-Rule Chain)

Located in lib/agency/member-invitation.service.ts:

  1. No self-invite

  2. Cannot invite platform ADMINS

  3. Cannot invite AGENCY owners

  4. Cannot invite LEARNERs

  5. Role compatibility check

  6. Single-agency constraint (user must not be in another agency)

  7. Active-only (cannot invite suspended users)

  8. Owner-only for admin-level invites


9. API ENDPOINTS

Status & Team

GET /api/agency/status (returns: isMember, isOwner, platformRole, effectiveRole, isViewingAsOther, agency?, membership?)
GET /api/agency/team/list/ (agency admin — note: NOT team-directory)
POST /api/agency/team/invite/ (agency admin)
POST /api/agency/team/invite/resend/ (agency admin)
PATCH /api/agency/team/members/[memberId]/ (edit role)
DELETE /api/agency/team/members/[memberId]/ (remove member)
POST /api/agency/team/claim/ (auto-claim pending invite)
GET /api/agency/team/eligible-users/ (agency admin)
GET /api/agency/team/lookup/ (agency admin)

Member Usage

GET /api/agency/member/usage (personal token consumption)
GET /api/agency/member/team-directory (agency member)

Admin (Owner Only)

GET /api/agency/admin/members (enriched with token usage)
PATCH /api/agency/admin/members/[memberId]/token-limit (owner only)

Branding (Owner Only)

GET /api/agency/branding (owner)
PUT /api/agency/branding (owner)
POST /api/agency/branding/logo (owner)
DELETE /api/agency/branding/logo (owner)
POST /api/agency/branding/smtp-test (owner)

Self-Service

POST /api/agency/create (self-service agency creation)
GET /api/agency/list (PUBLIC)

10. DATA REQUIREMENTS

Frontend Needs

  • AgencyStatusContext provides agency membership status with 1-min in-memory cache.

  • Team member list with roles, statuses, and token usage.

  • Token limit sliders for per-member adjustments.

Caching Strategy

  • AgencyStatusContext caches for 1 minute (in-memory).


11. PERFORMANCE CONSIDERATIONS

Database Optimization

  • Index on agency_members.user_clerk_id for lookup.

  • Index on agency_members.agency_id for member lists.


12. SECURITY & AUTHORIZATION

Who can access this feature?

  • Agency owners: full access (verified via agencies.owner_clerk_id TEXT field).

  • Agency members (CREATOR/REVIEWER): limited access (personal usage, team directory).

  • Non-members: redirected.

Authorization Logic

authenticateAgencyMember() for layout guard. Owner verification for sensitive routes via owner_clerk_id comparison.


13. ERROR HANDLING

Error

How Handled

Non-member accessing /agency

Redirected to actual role dashboard

Invite validation failure

Error toast with specific rule violated

User already in another agency

Blocked (single-agency constraint)

Owner-only access by member

Permission denied


14. TESTING CHECKLIST

Happy Path
□ Owner invites member → member claims → active
□ Owner sets token limit → member sees cap
□ Member views personal usage dashboard
□ Owner uploads/removes logo

Edge Cases
□ Non-member accessing /agency → redirected
□ Inviting user already in another agency → blocked
□ Revoking invite → status becomes REVOKED
AgencyStatusContext cache invalidation after 1 min


15. OPEN QUESTIONS

  • The AgencyLegacyWarning component for AGENCY-role users without an agency is a stopgap — should we remove the AGENCY platform role entirely?

  • ADMIN agency member role fully deprecated June 2026 — any remaining rows with ADMIN role should be migrated.


16. OUT OF SCOPE (v1.1+)

  • Multi-agency membership.

  • Agency sub-admins with limited permissions.

  • Agency billing/invoicing.


17. SUCCESS METRICS

  • Agency owners manage team without platform admin intervention.

  • Token limit enforcement prevents cost overruns.


18. DEPENDENCIES

This feature depends on:

  • [0.1] Secure Login + [6.1.1] RBAC.

  • [10.1] Gemini Configuration — token tracking feeds agency budgets.

  • [5.1] Super Admin View — admin can also manage agencies.

These features depend on this:

  • Agency-level reviewer analytics.

  • Token enforcement (3-tier: sitewide → agency → member).


19. TIMELINE & OWNERSHIP

Sprint #12: Already deployed.
Backend: scorevi
Frontend: scorevi
Estimated Completion: Complete.


Document Version

1.0 - Initial version - 2026-06-29 08:20 UTC

1.1 - Added Document Version section and update author to have full name - 2026-06-29 08:46 UTC


Was this article helpful?