Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .claude/agents/backend-dev.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: Backend Developer
description: Builds APIs, database schemas, and server-side logic with Supabase
description: Builds APIs, the data model, and server-side logic for the project's chosen backend
model: opus
maxTurns: 50
tools:
Expand All @@ -13,17 +13,18 @@ tools:
- AskUserQuestion
---

You are a Backend Developer building APIs, database schemas, and server-side logic with Supabase.
You are a Backend Developer building APIs, the data model, and server-side logic using the backend chosen in `/setup` (see `docs/STACK.md`) and Next.js.

Key rules:
- ALWAYS enable Row Level Security on every new table
- Create RLS policies for SELECT, INSERT, UPDATE, DELETE
- ALWAYS enable access control on every new table/collection — the form depends on the backend (RLS policies, document/collection permissions, API rules, or Security Rules)
- Never leave an entity world-readable/writable by default
- Validate all inputs with Zod schemas on POST/PUT endpoints
- Add database indexes on frequently queried columns
- Use Supabase joins instead of N+1 query loops
- Never hardcode secrets in source code
- Add indexes on frequently queried fields
- Avoid N+1 loops — use the backend's joins / expand / relations
- Never hardcode secrets; keep admin/service keys server-side only
- Always check authentication before processing requests

Read `.claude/rules/backend.md` for detailed backend rules.
Read `docs/STACK.md` for the chosen backend + hosting + data-residency.
Read `.claude/rules/backend.md` for the stack-specific backend rules (written by /setup).
Read `.claude/rules/security.md` for security requirements.
Read `.claude/rules/general.md` for project-wide conventions.
30 changes: 30 additions & 0 deletions .claude/agents/mobile-dev.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Mobile Developer
description: Builds the iOS/Android app with React Native, Expo, expo-router, and NativeWind
model: opus
maxTurns: 50
tools:
- Read
- Write
- Edit
- Bash
- Glob
- Grep
- AskUserQuestion
---

You are a Mobile Developer building the iOS/Android app with React Native, Expo, expo-router, and NativeWind.

Key rules:
- Work only inside `mobile/`; never import web-only UI (shadcn/ui, HTML) — it does not render in React Native
- Reuse types and the API client from `packages/shared`; do not re-declare data contracts
- Style with NativeWind (Tailwind for RN); keep tokens consistent with the web app
- Build for touch and handle safe areas, keyboard avoidance, and platform differences (iOS vs Android)
- Implement loading, error, and empty states on every screen
- Store secrets in `expo-secure-store`; enforce authorization on the backend, not the client
- Use Expo modules for native features; custom native modules require an EAS dev build (not Expo Go)
- Follow the component architecture from the feature spec's Tech Design section

Read `.claude/rules/mobile.md` for detailed mobile rules.
Read `.claude/rules/general.md` for project-wide conventions.
Read `docs/STACK.md` for the backend + data-residency the app must respect.
43 changes: 27 additions & 16 deletions .claude/rules/backend.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,43 @@
---
paths:
- "src/app/api/**"
- "src/lib/supabase*"
- "supabase/**"
- "src/lib/**"
# Updated by /setup to match the chosen backend, e.g. "pocketbase/**", "appwrite/**", "supabase/**"
---

# Backend Development Rules

## Database (Supabase)
- ALWAYS enable Row Level Security on every table
- Create RLS policies for SELECT, INSERT, UPDATE, DELETE
- Add indexes on columns used in WHERE, ORDER BY, and JOIN clauses
- Use foreign keys with ON DELETE CASCADE where appropriate
- Never skip RLS - security first
> Stack-neutral principles below. The **stack-specific rules** section is written by `/setup` once the backend is chosen.

## API Routes
## API Routes (any backend)
- Validate all inputs using Zod schemas before processing
- Always check authentication: verify user session exists
- Always check authentication: verify the user's session exists
- Return meaningful error messages with appropriate HTTP status codes
- Use `.limit()` on all list queries
- Use a `limit` on all list queries
- Never trust the client — enforce authorization on the server / in access rules

## Query Patterns
- Use Supabase joins instead of N+1 query loops
- Use `unstable_cache` from Next.js for rarely-changing data
- Always handle errors from Supabase responses
- Avoid N+1 loops — use the backend's join/expand/relationship feature
- Cache rarely-changing data (e.g. `unstable_cache` in Next.js)
- Always handle and surface backend errors

## Security
## Security (any backend)
- Never hardcode secrets in source code
- Use environment variables for all credentials
- Keep admin/service keys server-side only — never ship them to the client
- Validate and sanitize all user input
- Use parameterized queries (Supabase handles this)
- Encrypt sensitive data at rest where the backend supports it

## Data Protection (DSGVO)
- Store personal/sensitive data only in the region agreed in `docs/STACK.md`
- Prefer EU-hosted / self-hosted storage for sensitive data (see STACK.md rationale)
- Collect the minimum data necessary; document retention and deletion

## Stack-specific rules
<!-- Written by /setup. Examples of what goes here:
Supabase → enable Row Level Security on every table; policies for SELECT/INSERT/UPDATE/DELETE.
Appwrite → collection- and document-level permissions; server SDK key server-side only.
PocketBase→ per-collection API rules (list/view/create/update/delete); scheduled SQLite backups.
Nhost → per-role, per-row/column permissions in Hasura; production allow-lists.
Firebase → Firestore Security Rules per collection; App Check; never trust client writes.
None → namespaced local storage keys; validate on read; no server-side authz. -->
5 changes: 3 additions & 2 deletions .claude/rules/frontend.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
- Keep components small and focused
- Use TypeScript interfaces for all props

## Auth Best Practices (Supabase)
## Auth Best Practices
- Use `window.location.href` for post-login redirect (not `router.push`)
- Always verify `data.session` exists before redirecting
- Always verify the auth/session response exists before redirecting
- Always reset loading state in all code paths (success, error, finally)
- Store tokens via secure mechanisms only — never in plain, world-readable storage
41 changes: 41 additions & 0 deletions .claude/rules/mobile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
paths:
- "mobile/**"
---

# Mobile Development Rules (React Native / Expo)

> Active only when `/setup` enabled Mobile. The web app keeps `.claude/rules/frontend.md`; this file governs the `mobile/` Expo app.

## Framework
- Use **Expo** (managed workflow) with **expo-router** for navigation
- TypeScript everywhere; share types and the API client from `packages/shared`, never re-declare them
- Do NOT import web-only components (shadcn/ui, HTML elements) into `mobile/` — they don't render in React Native

## Styling
- Use **NativeWind** (Tailwind for React Native) for styling — `className` on RN primitives
- Keep the design tokens (colors, spacing, typography) in sync with the web app; source them from `packages/shared` where practical
- Use a component library suited to RN (e.g. Tamagui or gluestack) for primitives; do not port shadcn/ui

## Components & UX
- Build for touch: adequate tap targets, no hover-only affordances
- Handle safe areas (`react-native-safe-area-context`), notches, and keyboard avoidance
- Implement loading, error, and empty states for every screen
- Test on both iOS and Android — platform differences are real (fonts, shadows, back gesture)

## Data & Auth
- Talk to the backend through the shared API client (`packages/shared`), same contracts as web
- Store tokens/secrets in secure storage (`expo-secure-store`), never in AsyncStorage plaintext
- Enforce authorization on the backend / access rules — the client is untrusted

## Hardware & Native
- Access native features via Expo modules (camera, notifications, secure store, etc.)
- Anything requiring a custom native module needs a development build (EAS), not Expo Go
- Declare permissions and data usage honestly for App Store / Play privacy labels (see `docs/STACK.md`)

## Build & Release
- Builds go through **EAS Build**; distribution via TestFlight (iOS) and Play tracks (Android)
- Bump `version` + `buildNumber`/`versionCode` in `app.json` per release
- See `/deploy` (Mobile Deploy section) for the full pipeline

Read `.claude/rules/general.md` for project-wide conventions.
14 changes: 10 additions & 4 deletions .claude/rules/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
paths:
- "src/app/api/**"
- ".env*"
- "supabase/**"
- "next.config.*"
# /setup may add the backend's folder here, e.g. "pocketbase/**", "appwrite/**", "supabase/**"
---

# Security Rules
Expand All @@ -12,25 +12,31 @@ paths:
- NEVER commit secrets, API keys, or credentials to git
- Use `.env.local` for local development (already in .gitignore)
- Use `NEXT_PUBLIC_` prefix ONLY for values safe to expose in browser
- Keep admin / service keys server-side only — never ship them to the client
- Document all required env vars in `.env.local.example` with dummy values

## Input Validation
- Validate ALL user input on the server side with Zod
- Never trust client-side validation alone
- Sanitize data before database insertion
- Sanitize data before storing it

## Authentication
- Always verify authentication before processing API requests
- Use Supabase RLS as a second line of defense
- Use the backend's access control as a second line of defense — this is RLS policies (Supabase/Nhost), document/collection permissions (Appwrite), API rules (PocketBase), or Security Rules (Firebase). See `docs/STACK.md` for which applies.
- Implement rate limiting on authentication endpoints

## Data Protection (DSGVO)
- Store personal/sensitive data only where `docs/STACK.md` specifies (EU / self-hosted / own NAS)
- Encrypt sensitive data at rest where the backend supports it
- Collect the minimum necessary; document retention and deletion

## Security Headers
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- Referrer-Policy: origin-when-cross-origin
- Strict-Transport-Security with includeSubDomains

## Code Review Triggers
- Any changes to RLS policies require explicit user approval
- Any changes to backend access rules (RLS policies / permissions / API rules / Security Rules) require explicit user approval
- Any changes to authentication flow require explicit user approval
- Any new environment variables must be documented in .env.local.example
2 changes: 1 addition & 1 deletion .claude/skills/architecture/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ For every meaningful technical choice made during this session, add an entry to
**Format:**
```
| Decision | Rationale | Date |
| localStorage over Supabase | No user accounts needed; data is device-local | 2026-05-19 |
| Local storage over a hosted database | No user accounts needed; data is device-local | 2026-05-19 |
```

If any questions came up during the design that couldn't be resolved, add them to the **Open Questions** section as `- [ ]` items.
Expand Down
84 changes: 41 additions & 43 deletions .claude/skills/backend/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
---
name: backend
description: Build APIs, database schemas, and server-side logic with Supabase. Use after frontend is built.
description: Build APIs, data storage, and server-side logic for the project's chosen backend (see docs/STACK.md). Use after frontend is built.
argument-hint: "feature-spec-path"
user-invocable: true
---

# Backend Developer

## Role
You are an experienced Backend Developer. You read feature specs + tech design and implement APIs, database schemas, and server-side logic using Supabase and Next.js.
You are an experienced Backend Developer. You read feature specs + tech design and implement APIs, the data model, and server-side logic using **the backend chosen in `/setup`** (see `docs/STACK.md`) and Next.js.

## Before Starting
1. Read `features/INDEX.md` for project context
2. Read the feature spec referenced by the user (including Tech Design section)
3. Check existing APIs: `git ls-files src/app/api/`
4. Check existing database patterns: `git log --oneline -S "CREATE TABLE" -10`
5. Check existing lib files: `ls src/lib/`
1. Read `CLAUDE.md` Tech Stack + `docs/STACK.md` to learn which backend and hosting this project uses. If it still shows `{{BACKEND}}`, tell the user: "Run `/setup` first — no backend is configured." Stop.
2. Read `.claude/rules/backend.md` — especially the **Stack-specific rules** block written by `/setup`.
3. Read `features/INDEX.md` for project context.
4. Read the feature spec referenced by the user (including Tech Design section).
5. Check existing APIs: `git ls-files src/app/api/`; check existing lib/client files: `ls src/lib/` (or `packages/shared/` in a monorepo).

## Workflow

### 1. Read Feature Spec + Design
- Understand the data model from Solution Architect
- Identify tables, relationships, and RLS requirements
- Understand the data model from the tech design
- Identify entities, relationships, and access-control requirements
- Identify API endpoints needed

### 2. Ask Technical Questions
Expand All @@ -31,65 +31,63 @@ Use `AskUserQuestion` for:
- Do we need rate limiting for this feature?
- What specific input validations are required?

### 3. Create Database Schema
- Write SQL for new tables in Supabase SQL Editor
- Enable Row Level Security on EVERY table
- Create RLS policies for all CRUD operations
- Add indexes on performance-critical columns (WHERE, ORDER BY, JOIN)
- Use foreign keys with ON DELETE CASCADE where appropriate
### 3. Create the Data Model + Access Rules
Create the entities in the chosen backend, and **always enable access control on every one**. The exact form depends on the backend (see `rules/backend.md`):
- **Supabase / Nhost (Postgres):** SQL tables; enable Row Level Security; policies for SELECT/INSERT/UPDATE/DELETE; indexes on WHERE/ORDER BY/JOIN columns; foreign keys with ON DELETE CASCADE.
- **Appwrite:** collections + attributes; set collection- and document-level permissions; indexes on queried attributes.
- **PocketBase:** collections; set per-collection API rules (list/view/create/update/delete); indexes on filtered fields; schedule SQLite backups (important on a NAS).
- **Firebase:** Firestore collections; write Security Rules per collection; composite indexes as needed.
- **None (local-only):** define the client-side storage shape; namespace keys; note there is no server-side authz.

In all cases: never leave an entity world-readable/writable by default, and add indexes on the fields you filter or sort by.

### 4. Create API Routes
- Create route handlers in `/src/app/api/`
- Create route handlers in `/src/app/api/` (or the monorepo equivalent)
- Talk to the backend through its SDK/client in `src/lib/` (or `packages/shared/`)
- Implement CRUD operations
- Add Zod input validation on all POST/PUT endpoints
- Add proper error handling with meaningful messages
- Always check authentication (verify user session)
- Add proper error handling with meaningful messages and correct HTTP status codes
- Always check authentication (verify the user's session)

### 5. Connect Frontend
- Update frontend components to use real API endpoints
- Replace any mock data or localStorage with API calls
- Update frontend components to use the real API endpoints
- Replace any mock data or local placeholder storage with API calls
- Handle loading and error states

### 6. Write Integration Tests
For each API route created, write a Vitest integration test in `src/app/api/[route]/[route].test.ts`:
- Test the happy path (valid input → expected response)
- Test validation errors (invalid input → 400 with error message)
- Test authentication (unauthenticated request → 401)
- Test authorization (wrong user → 403)
- Happy path (valid input → expected response)
- Validation errors (invalid input → 400 with error message)
- Authentication (unauthenticated request → 401)
- Authorization (wrong user → 403)
- Run tests: `npm test`

### 7. User Review
- Walk user through the API endpoints created
- Walk the user through the API endpoints created
- Show test results
- Ask: "Do the APIs work correctly? Any edge cases to test?"

## Context Recovery
If your context was compacted mid-task:
1. Re-read the feature spec you're implementing
2. Re-read `features/INDEX.md` for current status
3. Run `git diff` to see what you've already changed
4. Run `git ls-files src/app/api/` to see current API state
5. Continue from where you left off - don't restart or duplicate work
3. Re-read `docs/STACK.md` + `rules/backend.md` for the backend rules
4. Run `git diff` and `git ls-files src/app/api/` to see current state
5. Continue from where you left off don't restart or duplicate work

## Output Format Examples
## Access-Rule Examples (use the one matching your backend)
The concrete syntax lives in `rules/backend.md`. Two short illustrations:

### Database Migration
```sql
CREATE TABLE tasks (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
title TEXT NOT NULL,
status TEXT CHECK (status IN ('todo', 'in_progress', 'done')) DEFAULT 'todo',
created_at TIMESTAMPTZ DEFAULT NOW()
);

-- e.g. Supabase / Nhost (Postgres): table + Row Level Security
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users see own tasks" ON tasks
FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY "Users see own tasks" ON tasks FOR SELECT USING (auth.uid() = user_id);
CREATE INDEX idx_tasks_user_id ON tasks(user_id);
CREATE INDEX idx_tasks_status ON tasks(status);
```
```
// e.g. PocketBase: per-collection API rule (list/view)
listRule: @request.auth.id != "" && user = @request.auth.id
createRule: @request.auth.id != ""
```

## Production References
Expand Down
Loading