workflow-agent-cli 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,492 @@
1
+ # Single Source of Truth
2
+
3
+ > **Purpose**: This document defines the canonical locations for all imperative services, utilities, and architectural patterns in the codebase. When making changes, always reference the correct source files to maintain consistency.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Supabase Clients](#supabase-clients)
10
+ 2. [Authorization](#authorization)
11
+ 3. [Types & Schemas](#types--schemas)
12
+ 4. [Context Providers](#context-providers)
13
+ 5. [Server Actions](#server-actions)
14
+ 6. [Hooks](#hooks)
15
+ 7. [Components](#components)
16
+ 8. [Testing Infrastructure](#testing-infrastructure)
17
+ 9. [Configuration](#configuration)
18
+
19
+ ---
20
+
21
+ ## Supabase Clients
22
+
23
+ All Supabase client creation MUST go through these files. Never create clients directly.
24
+
25
+ | File | Purpose | Usage Context |
26
+ | ---------------------------- | ----------------------------- | -------------------------------------- |
27
+ | `lib/supabase/client.ts` | Browser client (singleton) | Client components, hooks |
28
+ | `lib/supabase/server.ts` | Server client (async cookies) | Server components, server actions |
29
+ | `lib/supabase/admin.ts` | Admin client (bypasses RLS) | Server actions needing elevated access |
30
+ | `lib/supabase/middleware.ts` | Session refresh | `middleware.ts` only |
31
+
32
+ ### Usage Patterns
33
+
34
+ ```typescript
35
+ // ❌ WRONG - Never create clients directly
36
+ import { createClient } from '@supabase/supabase-js';
37
+ const supabase = createClient(url, key);
38
+
39
+ // ✅ CORRECT - Use the appropriate helper
40
+ // In client components:
41
+ import { getSupabaseClient } from '@/lib/supabase/client';
42
+ const supabase = getSupabaseClient();
43
+
44
+ // In server actions/components:
45
+ import { createServerClient } from '@/lib/supabase/server';
46
+ const supabase = await createServerClient();
47
+
48
+ // For admin operations (bypasses RLS):
49
+ import { createAdminClient } from '@/lib/supabase/admin';
50
+ const supabase = createAdminClient();
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Authorization
56
+
57
+ Authorization logic is centralized in these files. Never implement permission checks inline.
58
+
59
+ | File | Purpose | Usage Context |
60
+ | ------------------------------- | ----------------------------------------- | ----------------- |
61
+ | `utils/authorization.ts` | Role constants, hierarchy, client helpers | Client components |
62
+ | `utils/authorization.server.ts` | Server-side verification functions | Server actions |
63
+ | `hooks/useAuthorization.tsx` | React hook for permission checks | Client components |
64
+
65
+ ### Role Constants (from `utils/authorization.ts`)
66
+
67
+ ```typescript
68
+ // Role types
69
+ export type OrgRole = 'super_admin' | 'owner' | 'admin' | 'manager' | 'developer' | 'viewer';
70
+
71
+ // Role hierarchy (higher index = more permissions)
72
+ export const ROLE_HIERARCHY: OrgRole[] = [
73
+ 'viewer',
74
+ 'developer',
75
+ 'manager',
76
+ 'admin',
77
+ 'owner',
78
+ 'super_admin',
79
+ ];
80
+
81
+ // Role groups for permission checks
82
+ export const ADMIN_ROLES: OrgRole[] = ['super_admin', 'owner', 'admin'];
83
+ export const PRIVILEGED_ROLES: OrgRole[] = ['super_admin', 'owner', 'admin', 'manager'];
84
+ export const CONTRIBUTOR_ROLES: OrgRole[] = [
85
+ 'super_admin',
86
+ 'owner',
87
+ 'admin',
88
+ 'manager',
89
+ 'developer',
90
+ ];
91
+ ```
92
+
93
+ ### Server-Side Authorization (from `utils/authorization.server.ts`)
94
+
95
+ ```typescript
96
+ import {
97
+ verifyBoardAccess,
98
+ verifyTaskAccess,
99
+ verifyWorkspaceAccess,
100
+ requireAdminAccess,
101
+ requirePrivilegedAccess,
102
+ requireContributorAccess,
103
+ } from '@/utils/authorization.server';
104
+
105
+ // In server actions - always verify access FIRST
106
+ export async function getTask(taskId: string) {
107
+ const access = await verifyTaskAccess(taskId);
108
+ if (!access.hasAccess) {
109
+ return { data: null, error: access.error || 'Access denied' };
110
+ }
111
+ // ... proceed with data access
112
+ }
113
+
114
+ // For role-restricted operations
115
+ export async function deleteBoard(boardId: string) {
116
+ const { profile } = await requireAdminAccess(); // Throws if not admin
117
+ // ... proceed with deletion
118
+ }
119
+ ```
120
+
121
+ ### Client-Side Authorization (using `useAuthorization` hook)
122
+
123
+ ```typescript
124
+ import { useAuthorization } from "@/hooks/useAuthorization";
125
+
126
+ function TaskActions({ task }) {
127
+ const { can, currentUserRole, isRestricted } = useAuthorization();
128
+
129
+ return (
130
+ <>
131
+ {can.editTask() && <Button onClick={handleEdit}>Edit</Button>}
132
+ {can.deleteTask() && <Button onClick={handleDelete}>Delete</Button>}
133
+ {can.manageUsers() && <Button onClick={handleManage}>Manage</Button>}
134
+ </>
135
+ );
136
+ }
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Types & Schemas
142
+
143
+ ### Type Definitions
144
+
145
+ | File | Contents | When to Update |
146
+ | ------------------- | ------------------------------- | ----------------------------------------- |
147
+ | `types/index.ts` | Application types (camelCase) | Adding new entities, changing data shapes |
148
+ | `types/supabase.ts` | Database types (auto-generated) | After running `pnpm supabase:gen` |
149
+
150
+ ### Key Types in `types/index.ts`
151
+
152
+ ```typescript
153
+ // Entity types
154
+ export interface Task { id: string; title: string; ticketId: string; ... }
155
+ export interface Board { id: string; name: string; columns: Column[]; ... }
156
+ export interface Sprint { id: string; name: string; startDate: string; ... }
157
+ export interface Epic { id: string; title: string; color: string; ... }
158
+ export interface Organization { id: string; name: string; slug: string; ... }
159
+ export interface Team { id: string; name: string; members?: TeamMember[]; ... }
160
+ export interface Project { id: string; name: string; prefix: string; ... }
161
+
162
+ // Role types
163
+ export type UserRole = "super_admin" | "owner" | "admin" | "manager" | "developer" | "viewer";
164
+ export type OrgRole = UserRole;
165
+ export type TeamRole = "admin" | "member" | "viewer";
166
+
167
+ // Status/Priority enums
168
+ export type TaskStatus = "backlog" | "todo" | "in_progress" | "in_review" | "done" | "blocked" | "cancelled";
169
+ export type Priority = "low" | "medium" | "high" | "critical";
170
+ export type TaskType = "story" | "task" | "bug" | "epic";
171
+ ```
172
+
173
+ ### Zod Schemas
174
+
175
+ | Location | Purpose |
176
+ | ----------------------------- | -------------------------------------- |
177
+ | `lib/validations/*.schema.ts` | Validation schemas with type inference |
178
+ | `lib/validations/index.ts` | Central export of all schemas |
179
+
180
+ ```typescript
181
+ // lib/validations/task.schema.ts
182
+ import { z } from 'zod';
183
+
184
+ export const TaskSchema = z.object({
185
+ id: z.string().uuid(),
186
+ ticketId: z.string().regex(/^[A-Z]{1,6}-\d{4}$/),
187
+ title: z.string().min(1).max(255),
188
+ priority: z.enum(['low', 'medium', 'high', 'critical']),
189
+ });
190
+
191
+ export type Task = z.infer<typeof TaskSchema>;
192
+
193
+ // lib/validations/index.ts
194
+ export { TaskSchema, type Task } from './task.schema';
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Context Providers
200
+
201
+ ### Current Structure (Monolithic)
202
+
203
+ Currently, all providers are in `app/providers.tsx` (2500+ lines). This file exports:
204
+
205
+ | Context | Hook | Purpose |
206
+ | ---------------------- | -------------------- | --------------------------------- |
207
+ | `AuthContext` | `useAuth()` | User authentication state |
208
+ | `OrganizationContext` | `useOrganization()` | Current org, members, permissions |
209
+ | `NotificationsContext` | `useNotifications()` | Notification state and actions |
210
+ | `TeamsContext` | `useTeams()` | Team membership and management |
211
+ | `PreferencesContext` | `usePreferences()` | User preferences |
212
+ | `ImpersonationContext` | `useImpersonation()` | Super admin impersonation |
213
+ | `ProjectsContext` | `useProjects()` | Project management |
214
+
215
+ ### Target Structure (Modular)
216
+
217
+ The providers should be refactored into `app/providers/`:
218
+
219
+ ```
220
+ app/providers/
221
+ ├── index.tsx # Composite provider (exports Providers)
222
+ ├── AuthProvider.tsx # Authentication context
223
+ ├── OrganizationProvider.tsx # Organization context
224
+ ├── NotificationProvider.tsx # Notifications context
225
+ ├── PreferencesProvider.tsx # User preferences context
226
+ ├── TeamsProvider.tsx # Teams context
227
+ ├── ImpersonationProvider.tsx # Impersonation context
228
+ ├── ProjectsProvider.tsx # Projects context
229
+ └── types.ts # Shared provider types
230
+ ```
231
+
232
+ ### Usage Pattern
233
+
234
+ ```typescript
235
+ // Always import hooks from the providers module
236
+ import { useAuth, useOrganization, useNotifications } from '@/app/providers';
237
+
238
+ function MyComponent() {
239
+ const { user, loading } = useAuth();
240
+ const { organization, canManageUsers } = useOrganization();
241
+ const { notifications, markAsRead } = useNotifications();
242
+ // ...
243
+ }
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Server Actions
249
+
250
+ All server actions live in `app/actions/` with a central export.
251
+
252
+ | File | Purpose |
253
+ | ------------------------------- | ----------------------------- |
254
+ | `app/actions/index.ts` | Central export of all actions |
255
+ | `app/actions/tasks.ts` | Task CRUD operations |
256
+ | `app/actions/boards.ts` | Board management |
257
+ | `app/actions/sprints.ts` | Sprint management |
258
+ | `app/actions/epics.ts` | Epic management |
259
+ | `app/actions/comments.ts` | Comment operations |
260
+ | `app/actions/organizations.ts` | Organization management |
261
+ | `app/actions/teams.ts` | Team operations |
262
+ | `app/actions/projects.ts` | Project management |
263
+ | `app/actions/projectMembers.ts` | Project membership |
264
+ | `app/actions/notifications.ts` | Notification operations |
265
+ | `app/actions/invites.ts` | Invite system |
266
+ | `app/actions/profile.ts` | User profile operations |
267
+ | `app/actions/impersonation.ts` | Super admin impersonation |
268
+ | `app/actions/userManagement.ts` | User administration |
269
+
270
+ ### Action Pattern
271
+
272
+ Every action file MUST:
273
+
274
+ 1. Start with `'use server'` directive
275
+ 2. Verify authorization before data access
276
+ 3. Return `{ data, error }` or `{ success, error }` pattern
277
+ 4. Transform snake_case DB fields to camelCase
278
+
279
+ ```typescript
280
+ 'use server';
281
+
282
+ import { createServerClient } from '@/lib/supabase/server';
283
+ import { verifyBoardAccess } from '@/utils/authorization.server';
284
+ import { revalidatePath } from 'next/cache';
285
+
286
+ export async function getTasks(boardId: string) {
287
+ const access = await verifyBoardAccess(boardId);
288
+ if (!access.hasAccess) {
289
+ return { data: null, error: access.error };
290
+ }
291
+
292
+ const supabase = await createServerClient();
293
+ const { data, error } = await supabase.from('tasks').select('*').eq('board_id', boardId);
294
+
295
+ if (error) return { data: null, error: error.message };
296
+
297
+ return { data: data.map(transformTask), error: null };
298
+ }
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Hooks
304
+
305
+ Custom React hooks live in `hooks/`.
306
+
307
+ | Hook | Purpose | File |
308
+ | ------------------ | -------------------------------- | ---------------------------- |
309
+ | `useAuthorization` | Permission checking | `hooks/useAuthorization.tsx` |
310
+ | `useTheme` | Color theme management | `hooks/useTheme.tsx` |
311
+ | `useRealtime` | Supabase real-time subscriptions | `hooks/useRealtime.tsx` |
312
+ | `useMediaQuery` | Responsive breakpoints | `hooks/useMediaQuery.tsx` |
313
+ | `useMobile` | Mobile device detection | `hooks/useMobile.tsx` |
314
+ | `useDebounce` | Debounced values | `hooks/useDebounce.tsx` |
315
+ | `useLocalStorage` | Persistent local state | `hooks/useLocalStorage.tsx` |
316
+
317
+ ### Hook Pattern
318
+
319
+ ```typescript
320
+ import { useState, useEffect, useCallback } from 'react';
321
+
322
+ export function useHookName(param: string) {
323
+ const [data, setData] = useState<DataType | null>(null);
324
+ const [loading, setLoading] = useState(true);
325
+ const [error, setError] = useState<string | null>(null);
326
+
327
+ useEffect(() => {
328
+ // Effect logic
329
+ }, [param]);
330
+
331
+ const action = useCallback(() => {
332
+ // Action logic
333
+ }, []);
334
+
335
+ return { data, loading, error, action };
336
+ }
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Components
342
+
343
+ > **📚 Canonical Reference**: See `guidelines/COMPONENT_LIBRARY.md` for complete component documentation, usage patterns, and decision tree.
344
+
345
+ ### Component Library Resources
346
+
347
+ | Resource | Location | Purpose |
348
+ | ----------------------- | --------------------------------- | --------------------------------------------------------- |
349
+ | Component Library Guide | `guidelines/COMPONENT_LIBRARY.md` | Full component inventory, usage patterns, audit checklist |
350
+ | Design Tokens | `lib/design-tokens.ts` | Centralized colors, sizes, gradients |
351
+ | Feature Flags | `lib/feature-flags.ts` | Component rollout control |
352
+ | Storybook | `pnpm storybook` (localhost:6006) | Visual component documentation |
353
+
354
+ ### Directory Structure
355
+
356
+ | Directory | Purpose |
357
+ | ------------------------- | --------------------------------- |
358
+ | `components/` | Feature components |
359
+ | `components/ui/` | Base UI components (shadcn) |
360
+ | `components/auth/` | Authentication-related components |
361
+ | `components/settings/` | Settings page components |
362
+ | `components/super-admin/` | Super admin panel components |
363
+ | `components/skeletons/` | Loading skeleton components |
364
+ | `.storybook/` | Storybook configuration |
365
+
366
+ ### Component Testing
367
+
368
+ | Pattern | Location |
369
+ | --------------- | --------------------------------- |
370
+ | Component tests | `components/*.test.tsx` |
371
+ | Snapshot tests | `components/__snapshots__/*.snap` |
372
+ | Stories | `components/*.stories.tsx` |
373
+
374
+ ### Key Components
375
+
376
+ | Component | Purpose |
377
+ | ----------------------- | ------------------------------------- |
378
+ | `Dashboard.tsx` | Main dashboard layout |
379
+ | `DashboardApp.tsx` | Dashboard application wrapper |
380
+ | `Header.tsx` | Top navigation header |
381
+ | `Sidebar.tsx` | Navigation sidebar |
382
+ | `KanbanBoardView.tsx` | Kanban board display |
383
+ | `TableView.tsx` | Table view for tasks |
384
+ | `TaskCard.tsx` | Task card component |
385
+ | `TaskDialog.tsx` | Task creation/editing dialog |
386
+ | `TaskDetailPanel.tsx` | Task detail side panel |
387
+ | `SprintDialog.tsx` | Sprint management dialog |
388
+ | `BoardDialog.tsx` | Board configuration |
389
+ | `CommentsSection.tsx` | Task comments |
390
+ | `NotificationPanel.tsx` | Notifications dropdown |
391
+ | `ErrorBoundary.tsx` | Error boundary wrapper |
392
+ | `PriorityBadge.tsx` | Priority indicator badge |
393
+ | `StatusBadge.tsx` | Status indicator badge (feature flag) |
394
+
395
+ ---
396
+
397
+ ## Testing Infrastructure
398
+
399
+ ### Unit Testing
400
+
401
+ | File/Directory | Purpose |
402
+ | -------------------------- | -------------------------------------------- |
403
+ | `vitest.config.ts` | Vitest configuration (bail: 1 for fail-fast) |
404
+ | `test/setup.ts` | Test setup (mocks, MSW) |
405
+ | `test/fixtures.tsx` | Mock data factories |
406
+ | `lib/test-utils/` | Test utilities |
407
+ | `lib/test-utils/handlers/` | MSW API handlers |
408
+ | `lib/test-utils/db.ts` | Mock database |
409
+
410
+ ### Component Testing
411
+
412
+ | File/Directory | Purpose |
413
+ | --------------------------- | -------------------------------------------- |
414
+ | `components/*.test.tsx` | Component unit tests |
415
+ | `components/__snapshots__/` | Snapshot test files |
416
+ | `lib/*.test.ts` | Utility tests (design tokens, feature flags) |
417
+
418
+ ### E2E Testing
419
+
420
+ | File/Directory | Purpose |
421
+ | ---------------------------- | ------------------------ |
422
+ | `playwright.config.ts` | Playwright configuration |
423
+ | `e2e/` | E2E test files |
424
+ | `e2e/critical-tests.spec.ts` | Critical path tests |
425
+ | `e2e/impersonation.spec.ts` | Impersonation flow tests |
426
+
427
+ ---
428
+
429
+ ## Configuration
430
+
431
+ ### Application Config
432
+
433
+ | File | Purpose |
434
+ | ---------------- | --------------------------------- |
435
+ | `next.config.ts` | Next.js configuration |
436
+ | `middleware.ts` | Route middleware (auth redirects) |
437
+ | `tsconfig.json` | TypeScript configuration |
438
+ | `vercel.json` | Vercel deployment config |
439
+
440
+ ### Styling Config
441
+
442
+ | File | Purpose |
443
+ | -------------------- | ------------------------------- |
444
+ | `postcss.config.mjs` | PostCSS/Tailwind config |
445
+ | `app/globals.css` | Global CSS variables and styles |
446
+
447
+ ### Database
448
+
449
+ | Directory | Purpose |
450
+ | ---------------------- | --------------------- |
451
+ | `supabase/migrations/` | SQL migration files |
452
+ | `supabase/config.toml` | Supabase local config |
453
+
454
+ ---
455
+
456
+ ## Quick Reference: Import Paths
457
+
458
+ ```typescript
459
+ // Supabase clients
460
+ import { getSupabaseClient } from '@/lib/supabase/client';
461
+ import { createServerClient } from '@/lib/supabase/server';
462
+ import { createAdminClient } from '@/lib/supabase/admin';
463
+
464
+ // Authorization
465
+ import { ROLE_HIERARCHY, ADMIN_ROLES } from '@/utils/authorization';
466
+ import { verifyBoardAccess, requireAdminAccess } from '@/utils/authorization.server';
467
+ import { useAuthorization } from '@/hooks/useAuthorization';
468
+
469
+ // Types
470
+ import type { Task, Board, Sprint, Organization } from '@/types';
471
+ import type { Database } from '@/types/supabase';
472
+
473
+ // Providers/Context
474
+ import { useAuth, useOrganization, useTeams } from '@/app/providers';
475
+
476
+ // UI Components
477
+ import { Button, Input, Dialog } from '@/components/ui';
478
+
479
+ // Schemas
480
+ import { TaskSchema, CreateTaskSchema } from '@/lib/validations';
481
+
482
+ // Test utilities
483
+ import { mockTasks, createMockTask, seedTasks } from '@test/fixtures';
484
+ ```
485
+
486
+ ---
487
+
488
+ ## Related Documents
489
+
490
+ - [AGENT_EDITING_INSTRUCTIONS.md](AGENT_EDITING_INSTRUCTIONS.md) - Editing rules and patterns
491
+ - [LIBRARY_INVENTORY.md](LIBRARY_INVENTORY.md) - Approved dependencies
492
+ - [TESTING_STRATEGY.md](TESTING_STRATEGY.md) - Testing patterns