|
| 1 | +--- |
| 2 | +applyTo: "**/*.ts" |
| 3 | +--- |
| 4 | + |
| 5 | +# Cloudflare Workers + Hono + Angular SaaS |
| 6 | + |
| 7 | +Full-stack SaaS on Cloudflare Workers with Hono API, Angular frontend, and enterprise integrations. |
| 8 | + |
| 9 | +## Stack |
| 10 | +CF Workers+Hono v4.12+ | Angular 21+Ionic 8+PrimeNG 21 | D1/Neon | Drizzle v1 | Zod | Clerk Core 3 | Stripe | Inngest v4 | Resend | Bun 1.3 | Playwright v1.59+ | Vitest |
| 11 | + |
| 12 | +## TypeScript |
| 13 | +- Strict mode, never `any` (use `unknown`), prefer `interface` over `type` |
| 14 | +- `readonly` when not reassigned, `undefined` over `null` |
| 15 | +- Zod as source of truth for validation |
| 16 | +- ESLint flat config + typescript-eslint + Prettier |
| 17 | + |
| 18 | +## Hono API |
| 19 | +- Inline handlers for RPC type inference (never separate controller files) |
| 20 | +- Method chaining: `app.use().get().post()` preserves types |
| 21 | +- `hc<AppType>(BASE_URL)` for typed client |
| 22 | +- `@hono/zod-validator` on ALL request bodies |
| 23 | +- `app.onError()` + `app.notFound()` centralized |
| 24 | +- Split: `app.route('/path', subApp)` |
| 25 | +- Error: `{ error: string, code?: string, details?: unknown }` |
| 26 | +- `createFactory<{ Bindings: Env }>()` for reusable middleware |
| 27 | +- `GET /health` returns `{ status, version, timestamp }` |
| 28 | + |
| 29 | +## Angular 21 |
| 30 | +- Standalone only, zoneless by default |
| 31 | +- Signals: `signal()`, `computed()`, `effect()`, `linkedSignal()`, `resource()` |
| 32 | +- `HttpResource` for data fetching |
| 33 | +- Control flow: `@if`/`@for`/`@switch`/`@defer` |
| 34 | +- kebab-case files, `providedIn: 'root'`, PrimeNG |
| 35 | + |
| 36 | +## Drizzle v1 + D1 |
| 37 | +- `sqliteTable`, plural snake_case tables |
| 38 | +- `$inferSelect`/`$inferInsert` for types |
| 39 | +- Batch API (D1 doesn't support transactions) |
| 40 | +- Prepared statements for repeated queries |
| 41 | + |
| 42 | +## CF Workers |
| 43 | +- `ctx.waitUntil()` for post-response work |
| 44 | +- `ctx.passThroughOnException()` for graceful degradation |
| 45 | +- Bindings typed via `Env` interface |
| 46 | + |
| 47 | +## Inngest v4 |
| 48 | +- `eventType()` per-event with Zod schema |
| 49 | +- `inngest/cloudflare` adapter for Workers |
| 50 | +- `step.ai.infer()` offloads inference |
| 51 | + |
| 52 | +## Testing (TDD) |
| 53 | +- Failing test FIRST |
| 54 | +- Playwright 6 breakpoints (375, 390, 768, 1024, 1280, 1920) |
| 55 | +- Vitest for units |
| 56 | +- No sleeps, `data-testid` selectors, axe-core |
| 57 | + |
| 58 | +## Security |
| 59 | +- HSTS, CSP (nonce-based), COOP, COEP, CORP |
| 60 | +- Turnstile + Zod on all forms |
| 61 | +- Clerk JWT auth, webhook sync to D1 |
| 62 | + |
| 63 | +## Quality |
| 64 | +- Lighthouse a11y ≥95, perf ≥75 |
| 65 | +- WCAG 2.2 AA, LCP ≤2.5s, CLS ≤0.1 |
| 66 | + |
| 67 | +Source: [megabytespace/claude-skills](https://github.com/megabytespace/claude-skills) |
0 commit comments