Appearance
Epic 11 — Admin Panel
BE-ADMIN-001 — Full admin user management API
- [x] Implemented
Files:
- Edit:
src/graphql/schema/index.ts— add admin queries/mutations - Create:
src/graphql/resolvers/admin.ts - Create:
src/services/admin/userManagement.ts
Queries: adminUsers(page, filter): UserPage!, adminUser(id): User!, adminStats: PlatformStats!
Mutations: suspendUser(id, reason), banUser(id, reason), restoreUser(id), verifyUser(id), resetUserPassword(id)
Note: the originally-planned
impersonateUsermutation has moved to its own epic — see Epic 24 — Admin Impersonation. The earlier shape (impersonateUser(id): AuthPayload!) was insufficient because it returned a normal access token that would collide with the admin's own session and left no audit trail.
Add to User model: status UserStatus @default(ACTIVE) (enum: ACTIVE SUSPENDED BANNED), verifiedAt DateTime?, suspendedAt DateTime?, banReason String?
FE-ADMIN-001 — Admin user management page
- [x] Implemented
Files:
- Edit:
apps/app/src/pages/admin/AdminPage.tsx— add tabs for Users, Jobs, Reports - Create:
apps/app/src/pages/admin/AdminUsersPage.tsx - Create:
apps/app/src/pages/admin/AdminUserDetailPage.tsx - Create:
apps/app/src/hooks/useAdminUsers.ts
Description: Admin-only (role: ADMIN). User list with search and filter by role/status. Each row: avatar, email, role, status, created date, action menu (Suspend / Ban / Verify / Reset Password). User detail shows full profile data, activity log, and moderation history. Uses DS components. Matches "ADMIN-Desktop" frames in Figma.
BE-ADMIN-003 — Admin missing spec features (merge, logs, analytics, config, concierge)
- [x] Implemented
Files:
- Edit:
prisma/schema.prisma— addUserActivityLog,SystemConfigmodels - Run:
pnpm db:migrate - Edit:
src/graphql/schema/index.ts— extend admin queries/mutations - Edit:
src/graphql/resolvers/admin.ts - Create:
src/services/admin/activityLog.ts - Create:
src/services/admin/systemConfig.ts
1. Merge duplicate accounts:
graphql
mergeUserAccounts(primaryId: ID!, duplicateId: ID!): User!Migrates all profile data, applications, messages, and CasTars from duplicateId to primaryId, then deletes the duplicate. Requires confirmation step — admin must type the duplicate email to confirm.
2. User activity & login logs:
prisma
model UserActivityLog {
id String @id @default(cuid())
userId String
action String // "LOGIN" | "PASSWORD_CHANGE" | "ROLE_CHANGE" | "SUSPENSION" | "BAN" | "PROFILE_UPDATE"
detail String?
ip String?
userAgent String?
createdAt DateTime @default(now())
@@map("user_activity_logs")
}Write a log entry on: login, password reset, role change, suspend/ban/restore. Query: userActivityLog(userId, first, after): ActivityLogConnection!
3. Platform analytics:
graphql
platformAnalytics(range: DateRange!): PlatformAnalytics!
type PlatformAnalytics {
newUsers: Int!
activeUsers: Int!
jobsPosted: Int!
applicationsSubmitted: Int!
hiresCompleted: Int!
casTarsPurchased: Int! # revenue proxy
topCategories: [CategoryStat!]!
}4. System configuration:
prisma
model SystemConfig {
key String @id // "MAINTENANCE_MODE" | "MAX_APPLICATIONS_PER_JOB" | "CASTARS_EARN_MULTIPLIER" etc.
value String
updatedBy String
updatedAt DateTime @updatedAt
@@map("system_config")
}getSystemConfig(key) / setSystemConfig(key, value) — admin only.
5. Concierge tab — surfaced in the FE admin panel; resolvers already defined in Epic 23 (updateConciergeStatus, fulfillConciergeRequest).
BE-ADMIN-002 — Reporting & appeals
- [x] Implemented
Files:
- Edit:
prisma/schema.prisma— addReportmodel - Edit:
src/graphql/schema/index.ts - Create:
src/graphql/resolvers/reports.ts
Schema:
prisma
model Report {
id String @id @default(cuid())
reporterId String
targetType String // USER | JOB | GROUP
targetId String
reason String
description String?
status ReportStatus @default(PENDING)
resolvedBy String?
resolvedAt DateTime?
createdAt DateTime @default(now())
@@map("reports")
}
enum ReportStatus { PENDING REVIEWED RESOLVED DISMISSED }Mutations: reportContent(targetType, targetId, reason, description?), resolveReport(id, action) (admin)
FE-ADMIN-002 — Admin extended UI (logs, analytics, merge, config, concierge)
- [x] Implemented
Files:
- Edit:
apps/app/src/pages/admin/AdminPage.tsx— add tabs: Analytics, Config, Concierge - Edit:
apps/app/src/pages/admin/AdminUserDetailPage.tsx— add activity log timeline, merge account action - Create:
apps/app/src/pages/admin/AdminAnalyticsPage.tsx - Create:
apps/app/src/pages/admin/AdminConfigPage.tsx - Create:
apps/app/src/pages/admin/AdminConciergePage.tsx - Create:
apps/app/src/hooks/useAdminAnalytics.ts
New tabs/pages:
- User detail — Activity Log: chronological timeline of login, role change, suspension events per user. IP and user agent shown. Used for fraud investigation.
- User detail — Merge Accounts: "Merge with…" button opens a search modal to pick the duplicate account. Shows a diff of both profiles before confirming. Requires typing the duplicate email.
- Analytics tab: date-range picker + stat cards (new users, active users, jobs posted, applications, hires, CasTars revenue). Bar chart for top talent categories (use
recharts). - Config tab: key-value table of
SystemConfigentries. Each row has an inline edit field. Save triggerssetSystemConfig. Sensitive keys (e.g.MAINTENANCE_MODE) have a confirmation dialog. - Concierge tab: table of all
ConciergeRequestentries with status filter. Detail drawer shows description, requester, cost, admin notes field, and result submission form. "Fulfil" action opens a form to add candidate links and notes.