- Replace Bun with pnpm 9 + Turborepo + tsx; apps/api renamed to apps/backend - Split backend into http/, modules/, lib/ layers mirroring tai-specguard - Add use-case + Result pattern, Problem Details RFC 7807, basePath /api/v1 - Mount Better Auth at /api/v1/auth, keep session-auth whitelist - Split Prisma schema into prisma/models/*, generate into generated/ - Rework packages/shared into lib/ + schemas/ with pagination DTOs - Implement health, groups, students, payments, waitlist modules - Add vitest suite with prisma mocks (21 tests), biome lint - Point web client to /api/v1/auth and /api/v1/groups/from-organization
6.5 KiB
6.5 KiB
AGENTS.md — Gruperly
Monorepo web + API para gestión de cobros grupales. Reglas optimizadas para agentes.
Stack & ejecutables de verdad
- Package manager: pnpm 9 (
packageManageren la raíz). Usapnpmpara instalar (pnpm install), scripts y filtros. No uses bun/npm/yarn. - Monorepo: pnpm workspaces (
pnpm-workspace.yaml) orquestado con Turborepo (turbo.json). Dependencias entre paquetes usanworkspace:*. - Runtime: Node (
"type": "module"). El backend se ejecuta con tsx (tsx watch src/server.ts); no es Bun. - Lockfile:
pnpm-lock.yaml(se versiona). No existebun.lock/bun.lockb.
Comandos
pnpm install # instala dependencias
pnpm dev # levanta API (4000) y web (6173) vía turborepo
pnpm typecheck # tsc --noEmit en todos los paquetes. Principal verificación; corre tras tocar código
pnpm build # build de backend (prisma generate + tsc) y web (vite build)
pnpm lint # biome check en backend y shared
pnpm lint:fix # biome check --write
pnpm --filter @gruperly/backend typecheck # verificación de un solo paquete
pnpm --filter @gruperly/backend test # vitest (backend)
pnpm --filter @gruperly/backend db:* # db:generate / db:migrate / db:push / db:studio
Estructura y fronteras
apps/backend— Backend Node + Hono. Entry pointsrc/server.ts(serve de@hono/node-server, puerto 4000 víaPORT).src/app.tsmontabasePath('/api/v1')+ rutas de módulos + notFound/onError en RFC 7807. Capas:src/http/— infraestructura HTTP:env.ts,problem-details.ts(+problem-builders.ts,problem-domain.ts),validate.ts(wrapper de@hono/zod-validator),request-id.ts,request-logger.ts,security-headers.ts,session-auth.ts(middleware con whitelist pública/api/v1/health,/api/v1/auth,/api/auth).src/modules/<modulo>/— por módulo:index.ts,routes.tsyfeatures/<accion>/{route,use-case}.ts. Patrón: el route valida (validate.query/json) y delega en un use-case que devuelveResult<T, ProblemDetails>(ok/errdesde@gruperly/shared); el route responde conresultJson(oproblemJson).src/lib/—prisma.ts(getPrismaClient, proxydefaulty claseUnitOfWork),pagination.ts(offset/metadata),email.ts,error-message.ts.src/logger.ts— pino + pino-pretty.- Módulos existentes:
health-check,auth(Better Auth 1.7.2 público, montado en/api/v1/authvíabasePathdel server; cookie de sesión conpath: "/"),groups,students,payments,waitlist(listados paginados{ data, pagination }).
apps/web— Frontend React 19 + Vite + Tailwind v4. Entrysrc/main.tsx→src/router.tsx. Puerto 6173 (vite.config.ts). Auth client conbasePath: '/api/v1/auth'(src/lib/auth-client.ts); el backend llama a/api/v1/groups/from-organization(src/routes/organizations.tsx).packages/shared— Esquemas Zod (v3.24) + tipos +Result+ Problem Details. Se consume como TS fuente directo (exportsapunta asrc/index.ts, sin build previo); se resuelve vía el symlink de pnpm ennode_modules(@gruperly/sharedno está enpathsde los tsconfig). Elpathsde los tsconfig solo mapea@/*→src/*y@generated/*→generated/*.packages/config—tsconfig.base.json; tsconfigs lo extienden con"extends": "@gruperly/config/tsconfig.base.json"(por eso@gruperly/configes devDependency de cada paquete).
Gotchas operativos
- Prisma 7: requiere
apps/backend/.env(conDATABASE_URL). El CLI leeapps/backend/prisma.config.ts(datasourceurlvíaenv('DATABASE_URL')); el schema es multi-archivo:prisma/schema.prisma(generator con output../generated/prisma+ datasource simple) que incluyeprisma/models/*.prisma(auth.prisma,domain.prisma). El cliente se regenra conpnpm --filter @gruperly/backend db:generatey se importa desde@generated/prisma/client(alias →generated/prisma, gitignoreado); se instancia con@prisma/adapter-pg. Sin.envel CLI falla; copia desdeapps/backend/.env.example. - Tests (vitest): viven en
apps/backend/test/. Mockean el módulo@/lib/prismaconvi.mock(usandovi.hoistedsi el mock se comparte comotx); los use-cases ponen el db mockable enconstructor(deps). Los tests NO pasan porsessionAuthMiddleware; si el route leec.get('user'), inyecta un usuario con un middleware en el harness. - zod en v3.24 (pin exacto), no v4:
better-call(transitiva de better-auth) pidezod ^4— ese peer warning es conocido y aceptado. .env,dist/,.turbo/,apps/backend/generated/,node_modules/están gitignoreados (que no te extrañe su ausencia).
Convenciones repo-específicas
- Frontend en español: copy de UI, comentarios y textos en español.
- Base de datos: todas las tablas usan snake_case vía
@@mapenprisma/models/*.prisma(p. ej.User→users,WaitlistEntry→waitlist_entries). Al agregar un modelo nuevo, incluir siempre@@map("nombre_tabla"). - API responde errores en Problem Details RFC 7807 (
application/problem+json) y resultados como{ data, pagination }; los "use cases" devuelvenResulty nunca lanzan excepciones de dominio. - Tailwind v4 con tokens en
@themedentro deapps/web/src/index.css(p. ej.--color-accent: #1e90ff). Se usan como clases auto-generadas:text-accent,bg-success-soft, etc. Radius por defecto0.75rem(rounded-xl). - Router NO es file-based (aunque
stack.mdlo diga): las rutas se declaran manualmente enapps/web/src/router.tsxconcreateRoute+addChildreny se registran vía module augmentation. Cada vista nueva debe añadirse ahí. - Nav (Inicio/Grupos/Cobros/Ajustes) vive en
apps/web/src/components/layout/nav-items.ts; es la fuente única paraBottomNav(móvil) ySidebar(desktop) — no dupliques la lista. - UI: primitivos propios en
apps/web/src/components/ui/(avatar, button, badge) más helpercn()ensrc/lib/utils.ts(clsx + tailwind-merge). Aunquestack.mdmencione Shadcn, todavía no está instalado (sin Radix); úsalos directos. - Layout mobile-first:
RootLayoutusa columnamax-w-mden móvil y dos columnas (Sidebar + contenidomax-w-6xl) enlg+.
Fuentes de contexto
stack.md— arquitectura y spec técnica de referencia (UI tokens exactos, stack por app).README.md— setup de la base de datos y comandos generales.