From 1b5eb253f2bdeeae8b66cefd43c54dc6410ffa01 Mon Sep 17 00:00:00 2001 From: Jose Selesan Date: Fri, 12 Jun 2026 16:22:11 -0300 Subject: [PATCH] Updated AGENTS.md --- AGENTS.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 9526b9d..2a17933 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,6 +33,62 @@ packages/api-contract/ # Shared Zod schemas, types, route definitions 2. Implement handler in `apps/backend` 3. Consume from `apps/frontend` via workspace import `@repo/api-contract` +## Endpoint Pattern + +Every new endpoint must follow the **Result pattern** with the **validate helper**. + +### Files + +| File | Purpose | +|------|---------| +| `apps/backend/src/lib/result.ts` | `Result` type, `ok()`, `err()` | +| `apps/backend/src/lib/errors.ts` | `AppError` discriminated union, `Errors` factory | +| `apps/backend/src/lib/http/handle-result.ts` | `handleResult()` — bridges `Result` to HTTP | +| `apps/backend/src/lib/http/validate.ts` | `validate.json()`, `.query()`, `.param()`, `.header()`, `.form()` | + +### Layers + +**1. Route** — Use `validate.json(schema)`, `validate.param(schema)`, etc. as Hono middleware. + +```typescript +import { validate } from '@/lib/http/validate'; +import { z } from 'zod'; + +const idParams = z.object({ id: z.string() }); +router.post('/', validate.json(createSchema), createHandler); +router.get('/:id', validate.param(idParams), getHandler); +``` + +**2. Service** — Return `Result`. Use `ok(value)` on success, `err(Errors.*(...))` on failure. + +```typescript +import { Result, ok, err } from '@/lib/result'; +import { Errors } from '@/lib/errors'; + +export async function doSomething(input: Input): Promise> { + if (conflict) return err(Errors.conflict('Already exists')); + return ok(result); +} +``` + +**3. Handler** — Call the service and pass the `Result` to `handleResult`. + +```typescript +import { handleResult } from '@/lib/http/handle-result'; +import { doSomething } from './service'; + +export async function myHandler(c: AppContext) { + const payload = c.req.valid('json') as Input; + return handleResult(c, await doSomething(payload), 201); +} +``` + +### Never + +- ❌ Throw custom error classes from services +- ❌ Use try/catch in handlers for business logic errors +- ❌ Use `zValidator` directly — always use `validate.*` + ## Authentication (Better Auth) The project uses **Better Auth** for session management, replacing the legacy Supabase Auth.