Vibe Coding Guide — 17 Ready-to-Paste Prompts
17 battle-tested prompts for Claude Code & Cursor. Copy a prompt, paste it into your AI chat, and ship features in minutes. Every prompt references real files from this codebase — no generic boilerplate.
How to Use This Guide
With Claude Code (CLI)
cd /path/to/heartco
claude
# Paste any prompt below into the chatWith Cursor
- Open this project in Cursor
- Press
Cmd+L(Mac) orCtrl+L(Windows) to open AI chat - Copy-paste any prompt below
- Reference files with
@filenamewhen indicated - Let it cook
🏗️ Modules & Features
1. Add a new module (full scaffold)
Prompt:
I need to create a new module called "{{module_name}}" in this HeartCo codebase.
Follow the module template structure in @src/modules/_template/.
Steps:
1. Copy src/modules/_template to src/modules/{{module_name}}
2. Create a Prisma model fragment (add to prisma/schema.prisma):
- Must include organizationId for multi-tenant isolation
- Add @@index([organizationId]) for query performance
- Add the model to ORG_SCOPED_MODELS in src/lib/prisma-org-scope.ts
3. Create a tRPC router at src/server/api/routers/{{module_name}}.ts:
- Implement CRUD operations (create, read, list, update, delete)
- Use staffProcedure for internal routes, protectedProcedure for client portal
- Validate all inputs with Zod
- Ensure organizationId filtering on all writes (update/delete)
4. Register the router in @src/server/api/root.ts:
- Import the new router
- Add it to the createTRPCRouter object
5. Create a page at src/app/dashboard/{{module_name}}/page.tsx:
- Use the DataTable and ItemDialog components from the template
- Fetch data via tRPC hook (api.{{module_name}}.list.useQuery())
6. Update navigation in src/components/layout/sidebar.tsx:
- Add a menu item pointing to /dashboard/{{module_name}}
7. Create unit tests in src/server/api/routers/__tests__/{{module_name}}.test.ts:
- Mock Prisma client
- Test all CRUD operations
- Test security (organizationId filtering)
After setup, run:
- pnpm prisma generate
- pnpm typecheck
- pnpm test
- pnpm lint:fix
Output: Full working CRUD module with page, router, components, and tests.
Context files: @src/modules/_template/ @src/server/api/root.ts @prisma/schema.prisma @src/lib/prisma-org-scope.ts
Expected result: A complete, production-ready module with page, tRPC router, Prisma model, components, and tests.
Verify it works:
pnpm typecheck
pnpm dev
# Navigate to http://localhost:3000/dashboard/{{module_name}}
# Try creating, reading, updating, and deleting items
pnpm test -- {{module_name}}2. Add a field to an existing model
Prompt:
I need to add a field to the "{{ModelName}}" Prisma model.
Field details:
- Name: {{fieldName}}
- Type: {{fieldType}} (e.g., String, Int, Boolean, DateTime)
- Required/Optional: {{required}}
- Default value: {{defaultValue}} (if any)
- Indexed: {{isIndexed}} (true/false)
Steps:
1. Add the field to prisma/schema.prisma in the {{ModelName}} model
2. If the model has organizationId, NO need to add it again
3. Create a Prisma migration:
- npx prisma migrate dev --name add_{{fieldName}}_to_{{model_name}}
4. Update the tRPC router in src/server/api/routers/{{router_name}}.ts:
- Update Zod schemas (input validation)
- Update the router procedures to include the new field in queries/mutations
5. Update the React component:
- If it's a form, add a form field using react-hook-form
- If it's a table, add a new column to DataTable
6. Run the full pipeline:
- pnpm prisma generate
- pnpm typecheck
- pnpm test
- pnpm lint:fix
Do NOT forget the migration step — migrations are committed to git.
Context files: @prisma/schema.prisma @src/server/api/routers/ (the relevant router)
Expected result: A new field added to the model, Prisma migration created, router and UI updated.
Verify it works:
npx prisma migrate status
pnpm typecheck
pnpm test -- {{router_name}}
pnpm dev
# Check that the field appears in forms/tables3. Create a KPI dashboard for
Prompt:
Create a KPI dashboard page for {{module_name}} at src/app/dashboard/{{module_name}}/analytics/page.tsx.
Requirements:
1. Show 4 key metrics in a metric card grid:
- {{metric1_name}} (value, trend, unit)
- {{metric2_name}} (value, trend, unit)
- {{metric3_name}} (value, trend, unit)
- {{metric4_name}} (value, trend, unit)
2. Add a date range picker (use shadcn DatePicker, optional)
3. Use Recharts for visualization:
- Line chart for time-series data
- Bar chart for comparison
4. Fetch data from a tRPC query (create if missing):
- src/server/api/routers/{{module_name}}.ts → analytics procedure
- Query returns: { metrics: {...}, chartData: [...] }
5. Styling:
- Use shadcn Card component
- Apply Tailwind for layout (grid-cols-4 on desktop, grid-cols-1 on mobile)
- Dark mode support (use tokens from design.md)
- Add subtle animations (Framer Motion on scroll)
6. Error handling:
- Show a loading skeleton while fetching
- Display error message if query fails
- Graceful fallback if no data
Use @src/components/landing/ for animation patterns and @src/lib/utils.ts for the cn() utility.
Context files: @src/components/ui/card.tsx @src/lib/utils.ts ./.claude/rules/design.md
Expected result: A polished analytics page with KPI cards, charts, and date filtering.
Verify it works:
pnpm dev
# Navigate to /dashboard/{{module_name}}/analytics
# Verify metrics load and charts render
# Check responsive design on mobile4. Add a page with a form (Create/Edit)
Prompt:
Create a form page for {{resource_name}} at src/app/dashboard/{{module_name}}/[id]/page.tsx (edit) and a create modal at src/components/{{module_name}}/{{resource_name}}Form.tsx.
Form details:
- Resource: {{resource_name}}
- Fields: {{field1_name}} (type: {{type1}}), {{field2_name}} (type: {{type2}}), ...
- Create endpoint: api.{{module_name}}.create.useMutation()
- Update endpoint: api.{{module_name}}.update.useMutation()
- Delete endpoint: api.{{module_name}}.delete.useMutation() (optional)
Implementation:
1. Create Zod schema in src/server/api/routers/{{module_name}}.ts:
- Define createInput and updateInput with proper validation
- Add custom refinements if needed (e.g., date validations)
2. Create tRPC procedures:
- create: staffProcedure + input validation → save to DB
- update: staffProcedure + input validation + organizationId check
- delete: staffProcedure + soft delete or hard delete (decide)
3. Create form component at src/components/{{module_name}}/{{resource_name}}Form.tsx:
- Use react-hook-form + react-hook-form/resolvers
- Connect form fields to Zod schema (zodResolver)
- Add submit handler: call mutation → navigate on success
- Show loading state during mutation
- Show error toast if mutation fails
4. Create page at src/app/dashboard/{{module_name}}/[id]/page.tsx:
- Fetch existing resource data if editing
- Pass data to form component
- Show 404 if resource not found (IDOR protection)
5. Add form fields:
- Text inputs: <Input /> from shadcn
- Select: <Select /> from shadcn
- Checkboxes: <Checkbox /> from shadcn
- Date/Time: <DatePicker /> from shadcn
- Rich text: Consider @tiptap/react if needed
6. Style the form:
- Use Tailwind for layout (flex, grid)
- Add proper spacing and typography
- Highlight required fields with asterisk
- Show validation errors inline
Use @src/modules/_template/components/ItemForm.tsx as the structural reference.
Context files: @src/modules/_template/components/ItemForm.tsx @src/components/ui/ @src/lib/utils.ts
Expected result: A fully functional create/edit form with validation, error handling, and type safety.
Verify it works:
pnpm typecheck
pnpm dev
# Navigate to create form
# Fill in fields and submit → verify data saved in DB
# Edit an existing resource → verify data loads and updates
# Trigger validation errors → verify error messages show5. Create a Kanban board for
Prompt:
Create a Kanban board (drag-and-drop) for {{resource_name}} at src/app/dashboard/{{module_name}}/kanban/page.tsx.
Requirements:
1. Status columns: {{status1}}, {{status2}}, {{status3}}, {{status4}} (from your domain)
2. Cards:
- Display {{field1}}, {{field2}}, {{field3}} on each card
- Color coding based on priority/category (optional)
- Click to open detail modal (ItemDialog pattern)
3. Drag-and-drop:
- Use dnd-kit library (already in project)
- Dragging card from one column to another updates status
- Optimistic UI update + server mutation
- Rollback if mutation fails
4. Data fetching:
- Fetch all items grouped by status
- Or fetch all items and group in React (simpler for small datasets)
5. Styling:
- Column containers with border and background
- Cards with shadow on hover
- Smooth drag animations
- Mobile: convert to vertical scrolling (not drag-drop on touch)
Reference the CRM kanban pattern in src/app/dashboard/crm/[id]/kanban/page.tsx.
Steps:
1. Create tRPC procedures in src/server/api/routers/{{module_name}}.ts:
- listByStatus: return items grouped by status
- updateStatus: change item status (mutation)
2. Create Kanban component at src/components/{{module_name}}/KanbanBoard.tsx:
- Use dnd-kit for drag-and-drop
- Render status columns in a horizontal grid
3. Create page at src/app/dashboard/{{module_name}}/kanban/page.tsx
4. Add to sidebar navigation
Context files: @src/app/dashboard/crm/ (for CRM kanban reference), @src/lib/utils.ts
Expected result: A fully functional Kanban board with drag-and-drop status updates.
Verify it works:
pnpm dev
# Navigate to /dashboard/{{module_name}}/kanban
# Drag cards between columns → verify status updates in DB
# Refresh page → verify persisted changes
# Mobile view → verify no drag-drop, but card details still clickable🔌 Integrations
6. Integrate an external API (with caching)
Prompt:
Integrate the {{api_name}} API into HeartCo.
API Details:
- Base URL: {{api_url}}
- Authentication: {{auth_type}} (Bearer, API Key, OAuth)
- Rate limit: {{rate_limit}}
- Key endpoints: {{endpoints}}
- Example response: {{example_response}}
Implementation:
1. Create a service layer at src/lib/api/{{api_name}}-client.ts:
- Authenticate with the API (use env variables for secrets)
- Implement typed functions for each endpoint
- Add error handling and retry logic (exponential backoff)
- Type responses with TypeScript interfaces
2. Add Redis caching layer:
- Cache GET requests for 5-60 min (based on endpoint)
- Invalidate cache on mutations
- Pattern: check Redis first → call API → store in Redis
- Use Redis key format: "{{api_name}}:{{resource_id}}"
3. Create tRPC procedures in src/server/api/routers/{{module_name}}.ts:
- Call the service → add to context response
- Add requirePermission() guards if needed
- Validate organizationId for multi-tenant isolation
4. Handle rate limits gracefully:
- If rate limited, return cached data (if available)
- Log rate limit warnings
- Implement backoff strategy
5. Add environment variables to src/env.js:
- {{API_NAME}}_API_KEY
- {{API_NAME}}_BASE_URL
- Validate on app startup
6. Create tests:
- Mock the API client in src/server/api/routers/__tests__/
- Test cache hits/misses
- Test error scenarios
Use @src/modules/bridge/bridge-client.ts as a reference for API integration patterns.
Context files: @src/modules/bridge/bridge-client.ts @src/env.js @src/lib/redis.ts (if Redis is set up)
Expected result: A production-grade API integration with caching, error handling, and type safety.
Verify it works:
pnpm typecheck
pnpm test -- {{module_name}}
pnpm dev
# Call the tRPC procedure → verify API response
# Call again → verify caching (check redis)
# Stop the API → verify graceful fallback7. Add incoming webhooks (with HMAC verification)
Prompt:
Add webhook support for {{webhook_provider}} (e.g., Stripe, Bridge, Mistral).
Webhook details:
- Provider: {{webhook_provider}}
- Event types: {{event_types}}
- Signature header: {{signature_header}} (e.g., "x-webhook-signature")
- Secret: stored in env as {{SECRET_ENV_VAR}}
- Expected payload: {{payload_structure}}
Implementation:
1. Create webhook handler at src/app/api/webhooks/{{webhook_provider}}/route.ts:
- Accept POST requests
- Extract the raw request body (required for HMAC verification)
- Verify HMAC signature with crypto.timingSafeEqual (never use ===)
- Parse and validate payload with Zod
- Respond 200 immediately (async processing)
2. Create webhook processor at src/server/webhooks/{{webhook_provider}}-processor.ts:
- Handle each event type (if/switch on event.type)
- Update database based on event
- Use organizationId from payload or event context
- Add error logging (log unparseable events)
3. Database updates:
- Example: on "payment.success" → update Invoice status
- Example: on "user.created" → sync to CRM
- Always wrap in try/catch, always log failures
4. Add tests in src/server/webhooks/__tests__/:
- Test valid signature passes, invalid signature rejected
- Test each event type processed correctly
- Test HMAC verification (crypto.timingSafeEqual)
5. Environment setup:
- Add {{SECRET_ENV_VAR}} to .env.example
- Validate in src/env.js
Critical security rules:
- ALWAYS use crypto.timingSafeEqual for HMAC verification
- NEVER use === to compare signatures (timing attack vulnerability)
- Verify signature before processing payload
- Log all signature failures (potential attacks)
- Respond 200 even if processing fails (don't retry forever)
- Use organizationId filtering on all DB updates
Use @src/modules/bridge/webhooks/ as reference for webhook patterns.
Context files: @src/modules/bridge/webhooks/ @src/env.js @src/app/api/webhooks/ (if other webhooks exist)
Expected result: A secure, production-grade webhook handler with HMAC verification and error logging.
Verify it works:
pnpm typecheck
pnpm test -- webhooks
# Use ngrok or Webhook.cool to tunnel localhost
# Send test webhook from provider
# Verify payload processed and DB updated
# Send invalid signature → verify rejected8. Add realtime events with Pusher
Prompt:
Add realtime notification support using Pusher.
Scenarios:
- {{scenario1}} (e.g., "When a new invoice is created, notify all managers")
- {{scenario2}} (e.g., "When a chat message is sent, notify recipient in real-time")
Implementation:
1. Set up Pusher client:
- Add NEXT_PUBLIC_PUSHER_KEY, PUSHER_SECRET, PUSHER_CLUSTER to .env
- Validate in src/env.js
- Create Pusher instance at src/lib/pusher.ts (if not exists)
2. Create server-side trigger in tRPC router:
- After creating a {{resource}} (e.g., Invoice), call pusher.trigger()
- Channel name: "org_{{organizationId}}_{{resource_type}}"
- Event name: "{{resource_type}}.created"
- Data: JSON payload (avoid sensitive data)
3. Create client-side subscription:
- Use useEffect to subscribe to Pusher channel
- Call pusher.subscribe("org_..." + organizationId)
- Listen for event: channel.bind("{{event_name}}", callback)
- Update React state on event
- Cleanup: unsubscribe on unmount
4. UI updates:
- Show toast notification when event received
- Optionally update list in real-time (re-fetch or add to state)
- Optimistic updates for better UX
5. Security:
- Only subscribe to channels for your organization (use organizationId)
- Verify Pusher signature on private channels (if using)
- Don't send sensitive data through Pusher events
6. Tests:
- Mock Pusher in unit tests (vi.mock() at test start)
- Test trigger called with correct channel/event
- Test subscription and callback
Use @src/lib/pusher.ts and look for existing Pusher usage in the codebase.
Context files: @src/lib/pusher.ts (if exists), @src/env.js, any existing Pusher usage
Expected result: Realtime notifications working across multiple browser tabs and users.
Verify it works:
pnpm dev
# Open 2 browser windows, same organization
# Create a {{resource}} in one window
# Verify notification appears in second window immediately
# Check browser console for Pusher debug logs9. Add an AI provider (Mistral, OpenAI, or Fal.ai)
Prompt:
Integrate {{ai_provider}} (Mistral/OpenAI/Fal.ai) for {{use_case}}.
Integration details:
- Provider: {{ai_provider}}
- API Key env var: {{API_KEY_VAR}}
- Model: {{model_name}}
- Use case: {{use_case}} (e.g., "generate invoice summaries", "analyze images")
- Input: {{input_structure}}
- Expected output: {{output_structure}}
- Rate limit/quota: {{quota_info}}
Implementation:
1. Create AI client at src/lib/ai/{{provider_name}}-client.ts:
- Initialize client with API key from env
- Implement function for your use case (e.g., generateSummary())
- Handle streaming if applicable (for longer responses)
- Add timeout (e.g., 30s) and retry logic
- Return typed response (TypeScript interface)
- Log API usage (tokens, latency) for freemium quota tracking
2. Add to freemium quota system (if applicable):
- Add {{ai_use_case}}PerMonth to src/lib/freemium/freemium-limits.ts
- Call checkFreemiumLimit() in tRPC router before API call
- Increment usage counter after successful API call
- Reference: ./.claude/rules/freemium.md
3. Create tRPC procedure in src/server/api/routers/{{module_name}}.ts:
- Input: {{input_fields}} (Zod validated)
- Check freemium quota
- Call AI client
- Store result in DB (if needed)
- Return typed response
4. Optional: Add to prompt context:
- If multi-turn: maintain conversation history in DB
- Store system prompt in config or database
5. Error handling:
- Rate limit errors → suggest retry later
- Invalid input → return BAD_REQUEST
- API errors → log and return generic error (don't expose API details)
6. Tests:
- Mock {{ai_provider}} API responses
- Test quota enforcement
- Test error scenarios
Use @src/lib/ai/ as reference for AI integration patterns (Mistral, OpenAI examples).
Context files: @src/lib/ai/ @src/env.js @src/lib/freemium/ ./.claude/rules/freemium.md
Expected result: A fully integrated AI feature with quota management and error handling.
Verify it works:
pnpm typecheck
pnpm dev
# Call the AI tRPC procedure
# Verify response returned and stored (if applicable)
# Check quota usage incremented
# Exceed quota → verify graceful error message🔐 Auth & Security
10. Add a new user role to RBAC
Prompt:
Add a new role "{{role_name}}" (e.g., "FINANCE_MANAGER") to the RBAC system.
Role details:
- Role name: {{role_name}} (must be UPPERCASE)
- Permissions: {{permission_list}} (e.g., "facturation:read", "comptabilite:export_fec")
- Can manage: {{manages_resources}} (optional)
- Parent role hierarchy: {{inherits_from}} (optional, e.g., inherits from MANAGER)
Implementation:
1. Add role to Type union in src/lib/permissions/matrix.ts:
- Add "{{role_name}}" to the Role type definition
2. Add to permissions matrix (same file):
- Define permissions object for {{role_name}}
- Assign array of permission strings
- Follow naming pattern: "resource:action"
- Reference existing permissions (don't create duplicates)
3. Update Prisma schema in prisma/schema.prisma:
- If role determines field defaults, add migration
- Example: "role: {{role_name}}" → read-only access to certain tables
4. Update role selection UI:
- Verify src/app/dashboard/organization/members/page.tsx shows new role in dropdown
- Ensure only ADMIN can assign this role
5. Create role seeding (if applicable):
- Add to database seeders if using Prisma seed
6. Add tests in src/__tests__/security/:
- Test that role has correct permissions
- Test that role cannot access denied resources
- Test role hierarchy if applicable
Follow RBAC matrix structure in @src/lib/permissions/matrix.ts — it's the source of truth.
Context files: @src/lib/permissions/matrix.ts @prisma/schema.prisma @src/__tests__/security/
Expected result: New role available in member management UI with correct permission restrictions.
Verify it works:
pnpm test:security
pnpm typecheck
pnpm dev
# Go to /dashboard/organization/members
# Verify new role appears in dropdown
# Assign role to test user
# Log in as that user → verify correct resources accessible
# Try accessing denied resource → verify 403 error11. Add a granular permission to RBAC matrix
Prompt:
Add a new granular permission "{{permission_string}}" (e.g., "invoices:void").
Permission details:
- Permission string: {{permission_string}} (format: "resource:action")
- Description: {{description}}
- Which roles can use it: {{role_list}} (e.g., ADMIN, DIRECTION, MANAGER)
- Replaces/adds to: {{existing_permission}} (if refactoring)
Implementation:
1. Add permission string to Permission type union in @src/lib/permissions/matrix.ts:
- Line 22, add: | "{{permission_string}}"
- Keep alphabetical within resource group
2. Update role permission assignments (in same file):
- For each role that should have this permission, add the string to their permissions array
3. Update tRPC router guard:
- Find the tRPC procedure that needs this permission
- Replace staffProcedure or other guards with: requirePermission("{{permission_string}}")
- Example: export const {{procName}} = {{procedure}}.use(requirePermission("{{permission_string}}"))
4. Update permission checks:
- If checking dynamically, use hasPermission(ctx.session, "{{permission_string}}")
5. Add to UI (role assignment dropdown):
- Verify new permission shows in organization settings (if you have a permission UI)
- Most projects manage this via matrix.ts only
6. Add test:
- src/__tests__/security/rbac.test.ts → test role has permission
Reference: @src/lib/permissions/matrix.ts (source of truth), @src/server/api/trpc.ts (requirePermission helper).
Context files: @src/lib/permissions/matrix.ts @src/server/api/trpc.ts @src/__tests__/security/
Expected result: New permission enforced in tRPC routers, only accessible to authorized roles.
Verify it works:
pnpm test:security
pnpm typecheck
pnpm dev
# As authorized role, call protected procedure → succeeds
# As unauthorized role, call procedure → fails with FORBIDDEN
# Check procedure uses requirePermission() guard12. Add an OAuth provider (GitHub, Google, etc.)
Prompt:
Add OAuth login via {{oauth_provider}} (e.g., GitHub, Google, Azure AD).
Provider details:
- Provider: {{oauth_provider}}
- Client ID: {{client_id_env_var}}
- Client Secret: {{client_secret_env_var}}
- Scopes: {{scopes}} (e.g., "user:email", "profile")
- Callback URL: https://{{domain}}/api/auth/callback/{{provider_slug}}
Implementation:
1. Set up provider credentials:
- Go to {{provider}} developer console
- Create OAuth app with callback URL above
- Copy Client ID and Secret
- Add to .env: {{CLIENT_ID_ENV_VAR}}={{id}}, {{CLIENT_SECRET_ENV_VAR}}={{secret}}
- Add to .env.example (WITHOUT secret)
2. Update NextAuth config at src/app/api/auth/[...nextauth]/route.ts:
- Import {{Provider}}Provider from next-auth/providers/{{provider_slug}}
- Add to providers array:
{{Provider}}Provider({
clientId: env.{{CLIENT_ID_ENV_VAR}},
clientSecret: env.{{CLIENT_SECRET_ENV_VAR}},
allowDangerousEmailAccountLinking: false,
})
3. Add env vars to src/env.js:
- {{CLIENT_ID_ENV_VAR}}: z.string(),
- {{CLIENT_SECRET_ENV_VAR}}: z.string(),
4. Test OAuth flow:
- Run pnpm dev
- Go to /api/auth/signin
- Click "{{OAuth Provider}}"
- Authorize app
- Verify redirected to dashboard
5. Handle new users:
- Existing logic in NextAuth callbacks should auto-create user
- Verify user.organizationId is set (may need custom callback)
6. Security:
- Store secrets in env (never commit)
- Use secure callback validation
- Validate tokens from provider
Reference: src/app/api/auth/[...nextauth]/route.ts for existing OAuth examples.
Context files: @src/app/api/auth/[...nextauth]/route.ts @src/env.js .env.example
Expected result: OAuth login working with automatic user provisioning.
Verify it works:
pnpm dev
# Go to /api/auth/signin
# Click {{OAuth Provider}}
# Authorize and verify logged in
# Check user created in database
# Log out and log back in → verify existing user found🎨 UI & Design
13. Customize the design system (theming)
Prompt:
Customize the HeartCo design system colors, fonts, and tokens.
Customizations:
- Brand color: {{hex_color}} (e.g., #6366f1)
- Accent color: {{accent_color}}
- Font family (headings): {{heading_font}} (e.g., "Plus Jakarta Sans")
- Font family (body): {{body_font}} (e.g., "Geist")
- Dark mode: enabled/disabled
- Additional tokens: {{custom_tokens}}
Implementation:
1. Update Tailwind config at tailwind.config.ts:
- colors.brand: update to {{brand_color}}
- colors.accent: update to {{accent_color}}
- fonts: update heading and body fonts
- Add custom color tokens if needed
2. Update CSS variables in src/styles/globals.css:
- --color-brand: {{hex_color}}
- --color-accent: {{accent_color}}
- --color-dark: {{dark_bg}}
- --color-light: {{light_bg}}
3. Update shadcn/ui theme (if using dark mode toggle):
- src/components/ui/theme-provider.tsx
- Adjust default scheme (light/dark/system)
4. Update marketing design tokens:
- Reference: @./.claude/rules/design.md
- Ensure no hardcoded colors in components
- Use token-based colors: bg-brand, text-brand, etc.
5. Test theme across pages:
- Dashboard pages
- Landing page sections
- Dark mode toggle
- Mobile responsiveness
6. Commit changes:
- Update tailwind.config.ts
- Update globals.css
- Commit as: chore: customize design system colors
Run:
- pnpm lint:fix (Tailwind class linting)
- pnpm format:write
Context files: @tailwind.config.ts @src/styles/globals.css @./.claude/rules/design.md
Expected result: Consistent theming across the entire app with updated brand colors.
Verify it works:
pnpm dev
# Check /dashboard and / pages for new colors
# Toggle dark mode → verify both themes use new colors
# No hardcoded colors should appear (use tokens)
# Mobile view → verify responsive14. Create a reusable component library
Prompt:
Create a reusable component {{component_name}} at src/components/{{component_name}}.tsx.
Component details:
- Name: {{component_name}} (e.g., "CardWithBadge")
- Props: {{prop_list}} (e.g., "title: string, badge: string, onClick?: () => void")
- Variants: {{variants}} (e.g., "primary, secondary, outline")
- Use case: {{use_case}}
- Where it's used: {{usage_locations}} (current/future)
Implementation:
1. Create component file at src/components/{{component_name}}.tsx:
- Accept props as TypeScript interface
- Use forwardRef if component should accept ref
- Implement multiple variants with cn() utility
- Add JSDoc comments (explain props and variants)
2. Styling:
- Use Tailwind classes (cn() for merging)
- Support dark mode (use color tokens, not hardcoded)
- Add hover/active/focus states
- Responsive design if applicable
3. Accessibility:
- Proper semantic HTML (button, div, section, etc.)
- ARIA labels where needed
- Keyboard navigation if interactive
- Focus visible states
4. Documentation:
- JSDoc on component and props
- Example usage comment
5. Export:
- Add export to src/components/index.ts (if centralized)
- Or export directly from the file
6. Create story (optional, if using Storybook):
- src/components/{{component_name}}.stories.tsx
- Show all variants
- Show with different content
Reference shadcn/ui components for patterns: @src/components/ui/
Context files: @src/components/ui/ @src/lib/utils.ts @./.claude/rules/design.md
Expected result: A well-documented, reusable component with multiple variants.
Verify it works:
pnpm typecheck
# Import and use {{component_name}} in a test page
pnpm dev
# Verify component renders correctly
# Test all variants
# Test dark mode
# Test responsive design on mobile🚀 DevOps & Deployment
15. Deploy to production (Vercel + Supabase)
Prompt:
Set up production deployment for HeartCo on Vercel with Supabase PostgreSQL.
Prerequisites:
- Vercel account created
- Supabase project created
- GitHub repo connected to Vercel
Steps:
1. Supabase setup:
- Create PostgreSQL project in Supabase
- Copy DATABASE_URL (environment variable)
- Run migrations: npx prisma migrate deploy
- Create backups in Supabase dashboard
2. Vercel environment variables:
- Set all .env variables in Vercel project settings:
- DATABASE_URL (from Supabase)
- NEXTAUTH_SECRET (generate: openssl rand -base64 32)
- NEXTAUTH_URL (https://yourdomain.com)
- OAuth provider secrets (GitHub, Google, etc.)
- Stripe keys, Pusher keys, Mistral API keys
- All variables from .env.example
- Do NOT commit .env to git
3. Prisma migrations:
- Ensure all migrations committed to git
- Vercel runs "pnpm install && pnpm build" automatically
- Build script should include: npx prisma generate && npx prisma migrate deploy
- Verify next.config.js has prisma build step (if needed)
4. Database backups:
- Enable automated daily backups in Supabase
- Store backup credentials securely
5. Monitoring:
- Set up error logging (Sentry recommended)
- Monitor Vercel logs in dashboard
- Set up database query monitoring in Supabase
6. Custom domain:
- Point DNS to Vercel
- Set CNAME in Vercel project settings
- Update NEXTAUTH_URL and OAuth callback URLs
7. SSL/TLS:
- Vercel auto-enables HTTPS
- Monitor SSL certificate status
8. Verify deployment:
- Trigger deploy from git push
- Check Vercel build logs (no errors)
- Open live app and test key features
- Verify database writes persisted
Use environment variable checklists from .env.example.
Context files: .env.example @next.config.js @prisma/schema.prisma @package.json
Expected result: App live on Vercel with auto-deployment on git push.
Verify it works:
# Push to main branch
# Check Vercel dashboard → build completes
# Visit live URL → verify all features work
# Check database → new data persists
# Monitor Vercel logs → no errors16. Add tests for a module (Vitest + Testing Library)
Prompt:
Create comprehensive tests for {{module_name}} module.
Test scope:
- Unit tests for router procedures (CRUD)
- Security tests (IDOR, permission checks)
- Integration tests (DB interactions)
- Optional: E2E tests with Playwright
Implementation:
1. Create test file at src/server/api/routers/__tests__/{{module_name}}.test.ts:
- Use Vitest (describe, it, expect)
- Mock Prisma client
- Mock tRPC context (user, session, permissions)
2. Test structure:
describe("{{module_name}} router", () => {
describe("create", () => {
it("should create item with valid input", async () => { ... })
it("should reject invalid input", async () => { ... })
it("should enforce organizationId isolation", async () => { ... })
})
describe("read/list", () => {
it("should return items filtered by organizationId", async () => { ... })
it("should paginate results", async () => { ... })
})
describe("update", () => {
it("should update own item", async () => { ... })
it("should reject update to other org items (IDOR)", async () => { ... })
})
describe("delete", () => {
it("should delete item with permission", async () => { ... })
it("should reject delete without permission", async () => { ... })
})
})
3. Security test cases:
- IDOR: Try to read/edit/delete item from different organization → expect NOT_FOUND
- Permissions: Try procedure without required permission → expect FORBIDDEN
- RBAC: Different roles should have different access
- Input validation: Invalid Zod input → expect BAD_REQUEST
4. Mock patterns:
- vi.mock("~/server/db") for Prisma
- createMockContext() helper for tRPC context
- Use faker.js for fake data
5. Database mocking:
- Never use real database in tests
- Mock Prisma methods with vi.spyOn()
- Return mock data from spies
6. Run tests:
- pnpm test -- {{module_name}}
- Check coverage: pnpm test -- --coverage
7. E2E (optional):
- Create e2e/{{module_name}}.spec.ts with Playwright
- Test full user flow (create form → submit → verify in list)
Reference: @src/server/api/routers/__tests__/ for existing test patterns.
Context files: @src/server/api/routers/__tests__/ @src/lib/test-utils.ts (if exists) @./.claude/rules/testing.md
Expected result: Comprehensive test suite with unit, security, and E2E tests.
Verify it works:
pnpm test -- {{module_name}}
# All tests pass
# All module tests pass
pnpm test:security
# Security tests pass (IDOR, permission checks)17. Debug a tRPC error (diagnostic guide)
Prompt:
I'm getting an error with tRPC procedure {{procedure_name}}.
Error details:
- Error message: {{error_message}}
- Procedure: {{procedure_path}} (e.g., "api.invoices.list")
- Context: {{context}} (what triggers the error)
- Stack trace: {{stack_trace}} (if available)
Diagnostic steps:
1. Check tRPC procedure exists:
- Verify src/server/api/routers/{{router}}.ts has export const {{procName}}
- Verify registered in src/server/api/root.ts: {{routerName}}: {{routerName}}Router
- Restart dev server if procedure just added
2. Check input validation:
- Verify Zod schema matches expected input
- Use Zod .parse() in tests to debug validation errors
- Check frontend sends correct input format (client-side console.log the input)
3. Check context and permissions:
- If error is UNAUTHORIZED → verify user logged in (check NextAuth session)
- If error is FORBIDDEN → verify user has permission (check RBAC matrix)
- If error is NOT_FOUND → verify organizationId filtering correct
4. Check database queries:
- Add console.log(input) inside procedure for debugging
- Verify Prisma query is correct (check prisma/schema.prisma)
- If multi-tenant: verify organizationId in WHERE clause
- Use findFirst (never findUnique for org-scoped resources)
5. Check error response format:
- tRPC errors should be TRPCError (not Error)
- Error codes: "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "BAD_REQUEST" | etc.
- Don't expose sensitive data in error messages
6. Check frontend error handling:
- Verify mutation/query has .useQuery()/.useMutation()
- Check error object: error.data.code and error.data.message
- Log error in browser console for details
7. Check logs:
- Run pnpm dev → check terminal for server-side logs
- Check browser console (F12) for client-side errors
- Add console.log() at each step to trace execution
8. Restart and rebuild:
- Kill dev server
- Delete .next and generated/prisma/
- Run pnpm install
- Run pnpm prisma generate
- Run pnpm dev
If still stuck:
- Share full stack trace
- Share tRPC error code (UNAUTHORIZED, FORBIDDEN, etc.)
- Share the procedure code (redact secrets)
- Share frontend code that calls procedure
Context files: @src/server/api/routers/ (the relevant router) @src/server/api/trpc.ts @src/lib/permissions/matrix.ts
Expected result: Error diagnosed and fixed with root cause identified.
Verify it works:
pnpm dev
# Trigger the procedure again
# Verify it succeeds without error
# Check browser/server logs are clean
# If persists, check error code and trace from step above💡 Pro Tips
- Always reference @CLAUDE.md at the start of your session — it contains your project's exact conventions
- Use @src/lib/permissions/matrix.ts when working on auth/security features — it's the source of truth
- Use @src/modules/_template/ as your starting point for any new module — saves 30 min
- Run
pnpm typecheckafter every AI-generated change — catches type errors early - Keep commits atomic: one feature = one commit — makes git history clean and reviewable
- When in doubt about multi-tenant isolation, add organizationId to the WHERE clause — better safe than sorry
- Test IDOR vulnerabilities by trying to access/edit resources from a different organization — critical security
- Use the freemium quota system before calling expensive APIs — prevents runaway costs
- Dark mode is mandatory — use CSS tokens, never hardcoded colors
- Use
ctx.orgDbfor reads (auto-filters organizationId), but add organizationId manually for writes
🎯 Workflow Checklist
After pasting a prompt and AI generates code:
- Typecheck:
pnpm typecheck— must pass - Tests:
pnpm test— no new failures - Lint:
pnpm lint:fix && pnpm format:write - Commit:
git add -A && git commit -m "type: message" - Dev:
pnpm dev→ verify feature works in browser
If Prisma schema was modified:
npx prisma generate→npx prisma migrate dev --name <descriptive>
That's it. You're shipping.
Good luck, vibecoder. Ship fast, break nothing. 🚀