Skip to content

Commit 741d427

Browse files
committed
docs: add CI/CD best practices to CLAUDE.md
Document coding guidelines to ensure CI/CD passes on first push: - TypeScript strict mode rules (unused vars, Prisma enums) - Next.js 14 App Router requirements (Suspense for useSearchParams) - ESLint rules and pre-push checklist - External library compatibility (Stripe SDK versions) - Common CI failure fixes with solutions table - Stripe-specific guidelines for webhooks and enums
1 parent f4e41c2 commit 741d427

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,87 @@ GitHub Actions (`.github/workflows/ci.yml`):
157157
- PRs: Deploy preview
158158
- Main branch: Deploy production
159159

160+
### CI/CD Best Practices (MUST FOLLOW)
161+
162+
To ensure CI/CD checks pass on the first push, follow these rules when writing code:
163+
164+
#### 1. TypeScript Strict Mode
165+
- **No unused variables**: Remove any variable that is declared but never used
166+
- **No unused imports**: Remove imports that aren't used in the file
167+
- **Use Prisma enums directly**: When working with Prisma enum fields (like `SubscriptionStatus`, `SubscriptionTier`), import and use the enum from `@prisma/client`:
168+
```typescript
169+
import { SubscriptionStatus, SubscriptionTier } from '@prisma/client';
170+
171+
// CORRECT
172+
const status = SubscriptionStatus.ACTIVE;
173+
174+
// WRONG - will fail TypeScript
175+
const status = 'ACTIVE';
176+
```
177+
178+
#### 2. Next.js 14 App Router Rules
179+
- **Wrap `useSearchParams()` in Suspense**: Any component using `useSearchParams()` must be wrapped in a Suspense boundary:
180+
```typescript
181+
// CORRECT
182+
function PageContent() {
183+
const searchParams = useSearchParams();
184+
// ...
185+
}
186+
187+
export default function Page() {
188+
return (
189+
<Suspense fallback={<Loading />}>
190+
<PageContent />
191+
</Suspense>
192+
);
193+
}
194+
```
195+
- **Client components**: Add `"use client"` directive at top of files using React hooks
196+
- **Avoid `any` types**: Use proper TypeScript types instead of `any`
197+
198+
#### 3. ESLint Rules
199+
- **No `@typescript-eslint/no-unused-vars` errors**: Check all imports and variables are used
200+
- **Avoid `@typescript-eslint/no-explicit-any`**: Use specific types or `unknown` instead
201+
- **Run `npm run lint` locally** before committing to catch issues early
202+
203+
#### 4. External Library Compatibility
204+
- **Stripe SDK**: Use the API version that matches the installed SDK types
205+
```typescript
206+
// Check package.json for stripe version, use matching apiVersion
207+
apiVersion: '2025-11-17.clover' // Must match SDK types
208+
```
209+
- **Type casting for SDK changes**: When SDK types don't match runtime properties:
210+
```typescript
211+
// Cast to add missing properties
212+
const sub = subscription as Stripe.Subscription & {
213+
current_period_end: number;
214+
};
215+
```
216+
217+
#### 5. Pre-Push Checklist
218+
Before pushing code, run these commands locally:
219+
```bash
220+
npm run lint # Must pass with no errors (warnings OK)
221+
npm run build # Must complete successfully
222+
npm run test # All tests must pass
223+
```
224+
225+
#### 6. Common Fixes for CI Failures
226+
227+
| Error | Fix |
228+
|-------|-----|
229+
| `'X' is defined but never used` | Remove the unused import/variable |
230+
| `Type 'string' is not assignable to type 'EnumType'` | Import and use the Prisma enum directly |
231+
| `useSearchParams() should be wrapped in suspense` | Wrap component in `<Suspense>` |
232+
| `Property 'X' does not exist on type` | Add type cast or update to correct API |
233+
| `Unexpected any` | Replace `any` with proper type or `unknown` |
234+
235+
#### 7. Stripe-Specific Guidelines
236+
- Always import enums from Prisma for database operations
237+
- Use type assertions for Stripe webhook event data
238+
- Match Stripe API version to SDK types in `apps/api/src/config/stripe.ts`
239+
- Use `discounts` array instead of deprecated `promotion_code` property
240+
160241
## Docker
161242

162243
`docker-compose.yml` provides PostgreSQL 15, Redis 7, MinIO (S3-compatible storage).

0 commit comments

Comments
 (0)