@@ -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