Unified frontend architect for Next.js 16 + React 19 + TypeScript 5 + Tailwind 4 + Zustand 5 + TanStack Query 5 + TanStack Table + Better Auth. Transforms feature requirements into production-grade, multi-tenant, component-driven frontend implementations with mock/real API adapter pattern. Trigger when building any frontend feature, page, component, form, wizard, table, dashboard, or UI module. Also for state management decisions, API integration, data table config, form validation, wizard patterns, mock data setup, or any React/Next.js architecture question.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Unified frontend architect for Next.js 16 + React 19 + TypeScript 5 + Tailwind 4 + Zustand 5 + TanStack Query 5 + TanStack Table + Better Auth. Transforms feature requirements into production-grade, multi-tenant, component-driven frontend implementations with mock/real API adapter pattern. Trigger when building any frontend feature, page, component, form, wizard, table, dashboard, or UI module. Also for state management decisions, API integration, data table config, form validation, wizard patterns, mock data setup, or any React/Next.js architecture question.
// fetchApi auto-detects mode from env/localStorage// NEXT_PUBLIC_API_MODE=mock → routes to handleMockRequest()// NEXT_PUBLIC_API_MODE=real → routes to fetch() with auth headers// Mock handler: src/lib/api/mock/handler.ts// Add your feature's routes to the router
Rules:
API service is a plain object with async methods (NOT a class)
Every method returns typed promises
Mock data must be realistic (use real-world Indian names, departments, etc.)
Keyboard accessible (tab navigation, enter to submit)
No console errors/warnings
State Management Decision Tree
Is this data from an API?
├── YES → TanStack Query (useQuery/useMutation)
│ Never put API data in Zustand.
│
└── NO → Is it shared across many components?
├── YES → Zustand store (with persist if needed)
│ Examples: sidebar state, user preferences, active workspace
│
└── NO → Is it form state?
├── YES → react-hook-form (useForm)
│
└── NO → React useState/useReducer
Examples: modal open, local filter, wizard step
Every frontend feature must work for three customer types. Use progressive complexity — UC1 users see a simple UI, UC3 users see the full feature set.
Workspace Context (Required for UC3)
// Zustand store — persists active workspaceinterfaceWorkspaceState {
activeWorkspaceId: string | nullactiveCompanyId: string | nullworkspaces: Workspace[]
setActiveWorkspace: (id: string) =>void
}
// Every fetchApi() call includes workspace header automaticallyheaders: { 'x-workspace-id': useWorkspaceStore.getState().activeWorkspaceId }
Rules:
Workspace selector in top nav (HIDDEN when company has only 1 workspace)
"All Workspaces" option for Company Admins (read-only aggregated view)
Switching workspace refreshes ALL React Query caches: queryClient.invalidateQueries()
Domain Tabs (Required for UC2+)
// Domain tabs above data table — NOT a cosmetic filter
<DomainTabs
domains={workspaceDomains} // Fetched from /api/domains
activeDomainId={activeDomainId} // null = "All Domains"
onSelect={(domainId) =>setActiveDomainId(domainId)}
/>
// Passes domainId to API: /api/recipients?domainId=xxx
Rules:
HIDDEN when workspace has only 1 domain (UC1)
Shows recipient count per domain
"All Domains" tab shows combined (with Person de-dup count)
Person Column (Required for UC2+)
// In column definitions
{
id: 'person',
header: 'Person',
cell: ({ row }) => {
const linkCount = row.original.personLinkCountreturn linkCount > 1
? <Badgevariant="outline">{linkCount} identities</Badge>
: <spanclassName="text-muted-foreground">Single</span>
},
// HIDDEN when workspace has only 1 domain (UC1)
}
Bulk Operations Domain Breakdown (Required for UC2+)
// When selecting across domains, show breakdown in toolbar
<BulkActionsToolbar>
<span>5 from tatasteel.com, 3 from tatasteel.co.in selected</span>
{hasSyncProtectedFields && (
<Alertvariant="warning">
3 recipients have sync-protected fields. Changes may revert on next sync.
</Alert>
)}
</BulkActionsToolbar>
Settings Inheritance UI (Required for UC3)
// Each settings field shows its source
<SettingsField
label="Track Email Opens"
value={settings.trackOpens}
source={fieldSources.trackOpens} // 'company' | 'workspace' | 'override'
onOverride={() =>/* unlock field for workspace-level edit */}
onReset={() =>/* reset to company default */}
/>
// Badges: COMPANY (green, locked) | WORKSPACE (blue) | OVERRIDE (yellow, unlockable)
Progressive Complexity Rule
// In any component that has UC3-specific features:const { workspaces } = useWorkspaceStore()
const { domains } = useDomainsForWorkspace(activeWorkspaceId)
const showWorkspaceSelector = workspaces.length > 1const showDomainTabs = domains.length > 1const showPersonColumn = domains.length > 1 || workspaces.length > 1const showCompanyLibrary = workspaces.length > 1const showBlueprintFeatures = workspaces.length > 1const showSettingsInheritance = workspaces.length > 1// UC1 user sees NONE of these. UC3 sees ALL.