|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Working Preferences |
| 6 | + |
| 7 | +- **Small iterations**: Make one small change at a time, explain it, and wait for approval before proceeding |
| 8 | +- **Alignment**: Features, branches, and Jira tasks must always be aligned (e.g., branch `feature/ap-15-role-based-route-protection` for Jira ticket AP-15) |
| 9 | +- **Consistency**: Keep code consistent with existing patterns in the codebase |
| 10 | +- **Proven solutions**: Use robust, well-established approaches - no experimental or "clever" solutions |
| 11 | +- **Report updates**: When updating `docs/report.md`, check `docs/Assesment-criteria.md` and `docs/planning/ksbs.md`. Try to phrase content to align with assessment criteria where natural, but never force it - not every change needs to match a criterion. The report tracks all interesting technical decisions. |
| 12 | +- **No AI attribution**: Never add "Co-Authored-By" or "Generated with Claude" messages to commits or PRs |
| 13 | + |
| 14 | + |
| 15 | +## Commands |
| 16 | + |
| 17 | +```bash |
| 18 | +npm run dev # Start development server |
| 19 | +npm run build # Build for production |
| 20 | +npm run test # Run all tests (Vitest) |
| 21 | +npm run test:unit # Run tests in watch mode |
| 22 | +npm run lint # Run ESLint |
| 23 | +npm run check # TypeScript type checking |
| 24 | +``` |
| 25 | + |
| 26 | +Run a single test file: |
| 27 | +```bash |
| 28 | +npx vitest run src/lib/server/auth.spec.ts |
| 29 | +``` |
| 30 | + |
| 31 | +## Architecture |
| 32 | + |
| 33 | +Apprentice Pulse is a SvelteKit application that automates attendance tracking, progress reviews, and early intervention alerts for FAC apprentices. It sits on top of existing Airtable bases. |
| 34 | + |
| 35 | +### Key Layers |
| 36 | + |
| 37 | +- **Frontend**: Mobile-first PWA for student check-in (NFC/QR → magic link auth → one-tap attendance) |
| 38 | +- **API Routes**: `/api/auth/*`, `/api/checkin`, `/api/events`, `/api/webhooks` |
| 39 | +- **Cron Jobs**: Attendance chase, survey reminders, EPA alerts (Vercel Cron) |
| 40 | +- **External Services**: Airtable (database), Resend (email), Discord (webhooks) |
| 41 | + |
| 42 | +### Airtable Integration |
| 43 | + |
| 44 | +Tables and fields are referenced by **IDs** (not names) to prevent breakage when users rename things. IDs are centralized in `src/lib/airtable/config.ts`. |
| 45 | + |
| 46 | +```typescript |
| 47 | +import { TABLES, APPRENTICE_FIELDS } from '$lib/airtable/config'; |
| 48 | +``` |
| 49 | + |
| 50 | +Use `returnFieldsByFieldId: true` in queries. Note: `filterByFormula` still requires field **names** (Airtable limitation). |
| 51 | + |
| 52 | +Schema documentation: `docs/schema.md` |
| 53 | + |
| 54 | +### Authentication |
| 55 | + |
| 56 | +Magic link auth with JWT tokens (15-min expiry). Sessions stored as HTTP-only cookies (90 days). |
| 57 | + |
| 58 | +- `src/lib/server/auth.ts` - Token generation/verification |
| 59 | +- `src/lib/server/session.ts` - Cookie helpers (get/set/clear) |
| 60 | +- `src/hooks.server.ts` - Route protection middleware |
| 61 | + |
| 62 | +User types: `'staff'` | `'student'`. Route protection: |
| 63 | +- `/admin/*` → staff only |
| 64 | +- `/checkin` → any authenticated user |
| 65 | +- `/login` → redirects if already authenticated |
| 66 | + |
| 67 | +### Code Style |
| 68 | + |
| 69 | +ESLint with `@stylistic/eslint-plugin`: |
| 70 | +- Tabs for indentation |
| 71 | +- Single quotes |
| 72 | +- Semicolons required |
| 73 | +- Brace style: `else`/`catch` on new line after closing brace |
| 74 | + |
| 75 | +Svelte 5 runes syntax (`$state`, `$derived`, `$props`). Use `$app/state` not `$app/stores`. |
| 76 | + |
| 77 | +**DOM element references** must use `$state` - never use plain variables: |
| 78 | +```typescript |
| 79 | +// Correct |
| 80 | +let container = $state<HTMLDivElement | null>(null); |
| 81 | + |
| 82 | +// Wrong - causes "non_reactive_update" warning |
| 83 | +let container: HTMLDivElement; |
| 84 | +``` |
| 85 | + |
| 86 | +## Testing Auth in Development |
| 87 | + |
| 88 | +Magic links log to console (not emailed). To test: |
| 89 | + |
| 90 | +1. Start dev server: `npm run dev` |
| 91 | +2. POST to login: `curl -X POST http://localhost:5173/api/auth/login -H "Content-Type: application/json" -d '{"email": "your@email.com"}'` |
| 92 | +3. Copy token from server console |
| 93 | +4. Visit in browser: `http://localhost:5173/api/auth/verify?token=YOUR_TOKEN` |
0 commit comments