Skip to content

Commit 9da3780

Browse files
tofikwestclaude
andcommitted
Merge main into feat/pentest-credits
Resolves modify/delete conflict on packages/db/prisma/schema/organization-billing.prisma by keeping the delete from this branch — the legacy `OrganizationBilling` model was empty in production and its only code consumer (apps/app/src/app/api/webhooks/stripe-pentest/route.ts) was already removed in db0e7e7. Schema state remains consistent: no orphan relations from Organization or elsewhere. All other overlapping files auto-merged cleanly: - apps/api/package.json (jest transformIgnorePatterns + main's new deps) - apps/api/src/admin-organizations/admin-organizations.module.ts (AdminPentestCreditsController + main's PurgeOrganization* services) - apps/app/src/app/(app)/[orgId]/admin/organizations/[adminOrgId]/components/AdminOrgTabs.tsx (Pentest credits tab + main's "Delete Permanently" action) - bun.lock - packages/db/prisma/schema/organization.prisma - packages/db/prisma/schema/security-penetration-test-run.prisma Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 parents f494299 + 60de920 commit 9da3780

391 files changed

Lines changed: 31022 additions & 2792 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
name: audit-design-system
3+
description: Audit & fix design system usage — migrate @trycompai/ui and lucide-react to @trycompai/design-system
4+
---
5+
6+
Audit the specified files for design system compliance. **Fix every issue found immediately.**
7+
8+
## Rules
9+
10+
1. **`@trycompai/design-system`** is the primary component library. `@trycompai/ui` is legacy — only use as last resort when no DS equivalent exists.
11+
2. **Always check DS exports first** before reaching for `@trycompai/ui`. Run `node -e "console.log(Object.keys(require('@trycompai/design-system')))"` to check.
12+
3. **Icons**: Use `@trycompai/design-system/icons` (Carbon icons), NOT `lucide-react`. Check with `node -e "const i = require('@trycompai/design-system/icons'); console.log(Object.keys(i).filter(k => k.match(/YourSearch/i)))"`.
13+
4. **DS components that do NOT accept `className`**: `Text`, `Stack`, `HStack`, `Badge`, `Button` — wrap in `<div>` for custom styling.
14+
5. **Button**: Use DS `Button` with `loading`, `iconLeft`, `iconRight` props instead of manually rendering spinners/icons.
15+
6. **Layout**: Use `PageLayout`, `PageHeader`, `Stack`, `HStack`, `Section`, `SettingGroup`.
16+
7. **Patterns**: Sheet (`Sheet > SheetContent > SheetHeader + SheetBody`), Drawer, Collapsible.
17+
18+
## Process
19+
1. Read files specified in `$ARGUMENTS`
20+
2. Find `@trycompai/ui` imports — check if DS equivalent exists
21+
3. Find `lucide-react` imports — find matching Carbon icons
22+
4. Migrate components and icons
23+
5. Run build to verify: `bunx turbo run typecheck --filter=@trycompai/app`
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
name: audit-hooks
3+
description: Audit & fix hooks and API usage patterns — eliminate server actions, raw fetch, and stale patterns
4+
---
5+
6+
Audit the specified files for hook and API usage compliance. **Fix every issue found immediately.**
7+
8+
## Forbidden Patterns (fix immediately)
9+
10+
1. **`useAction` from `next-safe-action`** → replace with SWR hook or custom mutation hook
11+
2. **Server actions mutating via `@db`** → delete and use API hook instead
12+
3. **Direct `@db` in client components** → replace with `apiClient` via hook
13+
4. **Direct `@db` in Next.js pages for mutations** → replace with `serverApi`
14+
5. **Raw `fetch()` without `credentials: 'include'`** → use `apiClient`
15+
6. **`window.location.reload()` after mutations** → use SWR `mutate()`
16+
7. **`router.refresh()` after mutations** → use SWR `mutate()`
17+
8. **`useEffect` + `apiClient.get` for data fetching** → replace with `useSWR`
18+
9. **Callback props for data refresh** (`onXxxAdded`, `onSuccess`) → remove, rely on SWR cache sharing
19+
20+
## Required Patterns
21+
22+
- **Client data fetching**: `useSWR` with `apiClient` or custom hook
23+
- **Client mutations**: custom hooks wrapping `apiClient` with `mutate()` for cache invalidation
24+
- **Server components**: `serverApi` from `apps/app/src/lib/api-server.ts`
25+
- **SWR**: `fallbackData` for SSR data, `revalidateOnMount: !initialData`
26+
- **API response**: lists = `response.data.data`, single = `response.data`
27+
- **`mutate()` safety**: guard against `undefined` in optimistic update functions
28+
- **`Array.isArray()` checks**: when consuming SWR data that could be stale
29+
30+
## Process
31+
1. Read files specified in `$ARGUMENTS`
32+
2. Find forbidden patterns and fix them
33+
3. Ensure all data fetching uses SWR hooks
34+
4. Run typecheck to verify: `bunx turbo run typecheck --filter=@trycompai/app`

.agents/skills/audit-rbac/SKILL.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
name: audit-rbac
3+
description: Audit & fix RBAC and audit log compliance in API endpoints and frontend components
4+
---
5+
6+
Audit the specified files or directories for RBAC and audit log compliance. **Fix every issue found immediately.**
7+
8+
## Rules
9+
10+
### API Endpoints (NestJS — `apps/api/src/`)
11+
1. **Every mutation endpoint** (POST, PATCH, PUT, DELETE) MUST have `@RequirePermission('resource', 'action')`. If missing, **add it**.
12+
2. **Read endpoints** (GET) should have `@RequirePermission('resource', 'read')`. If missing, **add it**.
13+
3. **Self-endpoints** (e.g., `/me/preferences`) may skip `@RequirePermission` — authentication via `HybridAuthGuard` is sufficient.
14+
4. **Controller format**: Must use `@Controller({ path: 'name', version: '1' })`, NOT `@Controller('v1/name')`. If wrong, **fix it**.
15+
5. **Guards**: Use `@UseGuards(HybridAuthGuard, PermissionGuard)` at controller or endpoint level. Never skip PermissionGuard.
16+
6. **Webhooks**: External webhook endpoints use `@Public()` — no auth required.
17+
18+
### Frontend Components (`apps/app/src/`)
19+
1. **Every mutation element** (button, form submit, toggle, switch, file upload) MUST be gated with `usePermissions` from `@/hooks/use-permissions`. If not:
20+
- **Create/Add buttons**: Wrap with `{hasPermission('resource', 'create') && <Button>...`
21+
- **Edit/Delete in dropdown menus**: Wrap the menu item
22+
- **Inline form fields on detail pages**: Add `disabled={!canUpdate}`
23+
- **Status/property selectors**: Add `disabled={!canUpdate}`
24+
2. **Actions columns** in tables: hide entire column when user lacks write permission.
25+
3. **No manual role string parsing** (`role.includes('admin')`) — use `hasPermission()`.
26+
4. **Nav items**: gate with `canAccessRoute(permissions, 'routeSegment')`.
27+
5. **Page-level**: call `requireRoutePermission('segment', orgId)` server-side.
28+
29+
### Permission Resources
30+
`organization`, `member`, `control`, `evidence`, `policy`, `risk`, `vendor`, `task`, `framework`, `audit`, `finding`, `questionnaire`, `integration`, `apiKey`, `trust`, `pentest`, `app`, `compliance`
31+
32+
### Multi-Product RBAC
33+
- Products (compliance, pen testing) are org-level feature flags — NOT RBAC
34+
- `app:read` gates compliance dashboard; `pentest:read` gates security product
35+
- Custom roles can grant access to any combination of resources
36+
- Portal-only resources (`policy`, `compliance`) do NOT grant app access
37+
38+
## Process
39+
1. Read files specified in `$ARGUMENTS` (or scan the directory)
40+
2. Check each rule above
41+
3. **Fix every violation immediately** — don't just report
42+
4. Run typecheck to verify: `bunx turbo run typecheck --filter=@trycompai/api --filter=@trycompai/app`
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
name: audit-tests
3+
description: Audit & fix unit tests for permission-gated components
4+
---
5+
6+
Check that unit tests exist and pass for permission-gated components. **Write missing tests immediately.**
7+
8+
## Infrastructure
9+
- **Framework**: Vitest with jsdom
10+
- **Component testing**: `@testing-library/react` + `@testing-library/jest-dom`
11+
- **Setup**: `apps/app/src/test-utils/setup.ts`
12+
- **Permission mocks**: `apps/app/src/test-utils/mocks/permissions.ts`
13+
- **Run**: `cd apps/app && bunx vitest run`
14+
15+
## Required Test Pattern
16+
17+
Every component importing `usePermissions` MUST have tests covering:
18+
19+
1. **Admin (write) user**: mutation elements visible/enabled
20+
2. **Auditor (read-only)**: mutation elements hidden/disabled
21+
3. **Data always visible**: read-only content renders regardless of permissions
22+
23+
Use `setMockPermissions`, `ADMIN_PERMISSIONS`, `AUDITOR_PERMISSIONS` from test utils.
24+
25+
## Process
26+
1. Find components with `usePermissions` in `$ARGUMENTS`
27+
2. Check for corresponding `.test.tsx` files
28+
3. Write missing tests following the pattern above
29+
4. Fix any failing tests
30+
5. Run: `cd apps/app && bunx vitest run`

.agents/skills/better-auth-best-practices/SKILL.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ description: Configure Better Auth server and client, set up database adapters,
1111

1212
## Setup Workflow
1313

14-
1. Install: `npm install better-auth`
14+
1. Install: `bun add better-auth`
1515
2. Set env vars: `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL`
1616
3. Create `auth.ts` with database + config
1717
4. Create route handler for your framework
18-
5. Run `npx @better-auth/cli@latest migrate`
18+
5. Run `bunx @better-auth/cli@latest migrate`
1919
6. Verify: call `GET /api/auth/ok` — should return `{ status: "ok" }`
2020

2121
---
@@ -32,9 +32,9 @@ Only define `baseURL`/`secret` in config if env vars are NOT set.
3232
CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--config` for custom path.
3333

3434
### CLI Commands
35-
- `npx @better-auth/cli@latest migrate` - Apply schema (built-in adapter)
36-
- `npx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle
37-
- `npx @better-auth/cli mcp --cursor` - Add MCP to AI tools
35+
- `bunx @better-auth/cli@latest migrate` - Apply schema (built-in adapter)
36+
- `bunx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle
37+
- `bunx @better-auth/cli@latest mcp --cursor` - Add MCP to AI tools
3838

3939
**Re-run after adding/changing plugins.**
4040

@@ -172,4 +172,4 @@ For separate client/server projects: `createAuthClient<typeof auth>()`.
172172
- [Options Reference](https://better-auth.com/docs/reference/options)
173173
- [LLMs.txt](https://better-auth.com/llms.txt)
174174
- [GitHub](https://github.com/better-auth/better-auth)
175-
- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts)
175+
- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts)

.agents/skills/code/SKILL.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
---
2+
name: code
3+
description: "Use when writing TypeScript/React code - covers type safety, component patterns, and file organization"
4+
---
5+
6+
Source Cursor rule: `.cursor/rules/code.mdc`.
7+
Original Cursor alwaysApply: `false`.
8+
9+
# Code Standards
10+
11+
## TypeScript
12+
13+
### No `any`, No Unsafe Casts
14+
15+
```tsx
16+
// ✅ Validate with zod
17+
const TaskSchema = z.object({ id: z.string(), title: z.string() });
18+
const task = TaskSchema.parse(response.data);
19+
20+
// ✅ Use unknown and narrow
21+
const parseResponse = (data: unknown): Task => {
22+
if (!isTask(data)) throw new Error('Invalid');
23+
return data;
24+
};
25+
26+
// ❌ Never
27+
const data: any = fetchData();
28+
const task = response as Task;
29+
const name = user!.name;
30+
// @ts-ignore
31+
```
32+
33+
### Generics Over Any
34+
35+
```tsx
36+
// ✅ Generic
37+
const first = <T>(items: T[]): T | undefined => items[0];
38+
39+
// ❌ Any
40+
const first = (items: any[]): any => items[0];
41+
```
42+
43+
## React Patterns
44+
45+
### Named Exports, PascalCase
46+
47+
```tsx
48+
// ✅ Named export, PascalCase file
49+
// TaskCard.tsx
50+
export function TaskCard({ task }: TaskCardProps) { ... }
51+
52+
// ❌ Default export, lowercase
53+
export default function taskCard() { ... }
54+
```
55+
56+
### Derive State, Avoid useEffect
57+
58+
```tsx
59+
// ✅ Derived
60+
const completedCount = tasks.filter(t => t.completed).length;
61+
62+
// ❌ Synced state
63+
const [count, setCount] = useState(0);
64+
useEffect(() => {
65+
setCount(tasks.filter(t => t.completed).length);
66+
}, [tasks]);
67+
```
68+
69+
### When useEffect IS Appropriate
70+
71+
```tsx
72+
// External subscriptions
73+
useEffect(() => {
74+
const sub = eventSource.subscribe(handler);
75+
return () => sub.unsubscribe();
76+
}, []);
77+
78+
// DOM measurements
79+
useEffect(() => {
80+
setHeight(ref.current?.getBoundingClientRect().height);
81+
}, []);
82+
```
83+
84+
### Toasts with Sonner
85+
86+
```tsx
87+
import { toast } from 'sonner';
88+
89+
toast.success('Task created');
90+
toast.error('Failed to save');
91+
toast.promise(saveTask(), {
92+
loading: 'Saving...',
93+
success: 'Saved!',
94+
error: 'Failed',
95+
});
96+
```
97+
98+
## File Structure
99+
100+
### Colocate at Route Level
101+
102+
```
103+
app/(app)/[orgId]/tasks/
104+
├── page.tsx # Server component
105+
├── components/
106+
│ └── TaskList.tsx # Client component
107+
├── hooks/
108+
│ └── useTasks.ts # SWR hook
109+
└── data/
110+
└── queries.ts # Server queries
111+
```
112+
113+
### Share Only When Reused 3+ Times
114+
115+
```
116+
src/components/shared/ # Cross-page components
117+
src/hooks/ # Shared hooks (useApiSWR, useDebounce)
118+
```
119+
120+
## Code Quality
121+
122+
### File Size Limit: 300 Lines
123+
124+
Split large files into focused components.
125+
126+
### Named Parameters for 2+ Args
127+
128+
```tsx
129+
// ✅ Named
130+
const createTask = ({ title, assigneeId }: CreateTaskParams) => { ... };
131+
createTask({ title: 'Review PR', assigneeId: user.id });
132+
133+
// ❌ Positional
134+
const createTask = (title: string, assigneeId: string) => { ... };
135+
createTask('Review PR', user.id); // What's the 2nd param?
136+
```
137+
138+
### Early Returns
139+
140+
```tsx
141+
// ✅ Early return
142+
function processTask(task: Task | null) {
143+
if (!task) return null;
144+
if (task.deleted) return null;
145+
return <TaskCard task={task} />;
146+
}
147+
148+
// ❌ Nested
149+
function processTask(task) {
150+
if (task) {
151+
if (!task.deleted) {
152+
return <TaskCard task={task} />;
153+
}
154+
}
155+
return null;
156+
}
157+
```
158+
159+
### Event Handler Naming
160+
161+
```tsx
162+
// ✅ Prefix with "handle"
163+
const handleClick = () => { ... };
164+
const handleSubmit = (e: FormEvent) => { ... };
165+
const handleTaskCreate = (task: Task) => { ... };
166+
```
167+
168+
## Accessibility
169+
170+
```tsx
171+
// Interactive elements need keyboard support
172+
<div
173+
role="button"
174+
tabIndex={0}
175+
onClick={handleClick}
176+
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
177+
aria-label="Delete task"
178+
>
179+
<TrashIcon />
180+
</div>
181+
182+
// Form inputs need labels
183+
<label htmlFor="task-name">Task Name</label>
184+
<input id="task-name" type="text" />
185+
```

0 commit comments

Comments
 (0)