Complete implementation of the admin authentication and authorization plan using a separate Clerk instance (App B) for cryptographic isolation from the storefront. Convex backend changes: - auth.config.ts: dual JWT provider (storefront + admin Clerk issuers) - http.ts: add /clerk-admin-webhook route with separate signing secret - users.ts: role-aware upsertFromClerk (optional role arg), store reads publicMetadata.role from JWT, assertSuperAdmin internal query - model/users.ts: add requireSuperAdmin helper - adminInvitations.ts: inviteAdmin action (super_admin gated, Clerk Backend SDK) Admin app (apps/admin): - Route groups: (auth) for sign-in, (dashboard) for gated pages - AdminUserSync, AdminAuthGate, AccessDenied, LoadingSkeleton components - useAdminAuth hook with loading/authorized/denied state machine - RequireRole component for super_admin-only UI sections - useStoreUserEffect hook for Clerk→Convex user sync - Sidebar shell with nav-main, nav-user, app-sidebar - clerkMiddleware with /sign-in excluded from auth.protect - ShadCN UI components (sidebar, dropdown, avatar, etc.) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
54 lines
1.4 KiB
JSON
54 lines
1.4 KiB
JSON
{
|
|
"name": "ecommerce",
|
|
"version": "0.0.1",
|
|
"private": true,
|
|
"packageManager": "npm@11.6.2",
|
|
"workspaces": [
|
|
"apps/*",
|
|
"packages/*"
|
|
],
|
|
"scripts": {
|
|
"dev": "turbo dev",
|
|
"build": "turbo build",
|
|
"lint": "turbo lint",
|
|
"type-check": "turbo type-check",
|
|
"dev:storefront": "turbo dev --filter=storefront",
|
|
"dev:admin": "turbo dev --filter=admin",
|
|
"build:storefront": "turbo build --filter=storefront",
|
|
"build:admin": "turbo build --filter=admin",
|
|
"test": "vitest",
|
|
"test:once": "vitest run",
|
|
"test:coverage": "vitest run --coverage --coverage.reporter=text"
|
|
},
|
|
"dependencies": {
|
|
"@clerk/backend": "^2.32.1",
|
|
"@tailwindcss/postcss": "^4.2.0",
|
|
"convex": "^1.32.0",
|
|
"next": "^15.3.2",
|
|
"react": "^19.2.4",
|
|
"react-dom": "^19.2.4",
|
|
"stripe": "^20.4.0",
|
|
"svix": "^1.86.0",
|
|
"tailwindcss": "^4.2.0"
|
|
},
|
|
"devDependencies": {
|
|
"@edge-runtime/vm": "^5.0.0",
|
|
"@testing-library/react": "^16.3.2",
|
|
"@types/node": "^20.0.0",
|
|
"@types/react": "^19.2.14",
|
|
"@types/react-dom": "^19.2.3",
|
|
"autoprefixer": "^10.4.0",
|
|
"convex-test": "^0.0.41",
|
|
"eslint": "^9.0.0",
|
|
"eslint-config-next": "^15.3.2",
|
|
"happy-dom": "^20.7.0",
|
|
"postcss": "^8.4.0",
|
|
"turbo": "^2.0.0",
|
|
"typescript": "^5.4.0",
|
|
"vitest": "^4.0.18"
|
|
},
|
|
"engines": {
|
|
"node": ">=18.0.0"
|
|
}
|
|
}
|