Files
gruperly/AGENTS.md
Jose Selesan 6246bf2341 refactor: migrate monorepo from pnpm to Bun runtime and workspaces
- root: bun workspaces via package.json, packageManager bun@1.4.0, scripts use bun --filter
- backend: Bun.serve, bun test (vitest removed), bun --watch dev script, tsconfig types bun
- tests: migrate 6 test files from vitest to bun:test (mock.module)
- validate: replace @hono/zod-validator with hono validator + zod safeParse (fixes TS2589)
- lockfile: bunfig.toml saveTextLockfile, regenerated bun.lock (text) for turbo
- docs: AGENTS.md, README.md, stack.md updated to Bun stack
2026-09-14 10:58:56 -03:00

6.9 KiB

AGENTS.md — Gruperly

Monorepo web + API para gestión de cobros grupales. Reglas optimizadas para agentes.

Stack & ejecutables de verdad

  • Package manager: Bun 1.4 (packageManager en la raíz). Usa bun para instalar (bun install), scripts y filtros. No uses pnpm/npm/yarn.
  • Monorepo: bun workspaces ("workspaces" en el package.json raíz) orquestado con Turborepo (turbo.json). Dependencias entre paquetes usan workspace:*.
  • Runtime: Bun ("type": "module"). El backend usa Bun.serve (bun --watch src/server.ts); no es Node/tsx.
  • Lockfile: bun.lock (texto; bunfig.toml fija [install] saveTextLockfile = true porque el ~/.bunfig.toml global lo tiene en false). Se versiona. No existe pnpm-lock.yaml/bun.lockb.

Comandos

bun install                     # instala dependencias
bun dev                         # levanta API (4000) y web (6173) vía turborepo
bun run typecheck               # tsc --noEmit en todos los paquetes. Principal verificación; corre tras tocar código
bun run build                   # build de backend (prisma generate + tsc) y web (vite build)
bun run lint                    # biome check en backend y shared
bun run lint:fix                # biome check --write
bun --filter @gruperly/backend typecheck   # verificación de un solo paquete
bun --filter @gruperly/backend test        # bun test (backend)
bun --filter @gruperly/backend db:*        # db:generate / db:migrate / db:push / db:studio

Estructura y fronteras

  • apps/backend — Backend Bun + Hono. Entry point src/server.ts (Bun.serve, puerto 4000 vía PORT). src/app.ts monta basePath('/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 del validator de hono —hono/validator— + schema.safeParse), 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.ts y features/<accion>/{route,use-case}.ts. Patrón: el route valida (validate.query/json) y delega en un use-case que devuelve Result<T, ProblemDetails> (ok/err desde @gruperly/shared); el route responde con resultJson (o problemJson).
    • src/lib/ — prisma.ts (getPrismaClient, proxy default y clase UnitOfWork), 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/auth vía basePath del server; cookie de sesión con path: "/"), groups, students, payments, waitlist (listados paginados { data, pagination }).
  • apps/web — Frontend React 19 + Vite + Tailwind v4. Entry src/main.tsx → src/router.tsx. Puerto 6173 (vite.config.ts). Auth client con basePath: '/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 (exports apunta a src/index.ts, sin build previo); se resuelve vía el symlink de bun en node_modules (@gruperly/shared no está en paths de los tsconfig). El paths de 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/config es devDependency de cada paquete).

Gotchas operativos

  • Prisma 7: requiere apps/backend/.env (con DATABASE_URL). El CLI lee apps/backend/prisma.config.ts (datasource url vía env('DATABASE_URL')); el schema es multi-archivo: prisma/schema.prisma (generator con output ../generated/prisma + datasource simple) que incluye prisma/models/*.prisma (auth.prisma, domain.prisma). El cliente se regenra con bun --filter @gruperly/backend db:generate y se importa desde @generated/prisma/client (alias → generated/prisma, gitignoreado); se instancia con @prisma/adapter-pg. Sin .env el CLI falla; copia desde apps/backend/.env.example.
  • Tests (bun test): viven en apps/backend/test/. Mockean el módulo @/lib/prisma con mock.module (si el mock se comparte como tx, declara la const fuera del mock; vi de bun:test NO tiene vi.mocked). Los use-cases ponen el db mockable en constructor(deps). Los tests NO pasan por sessionAuthMiddleware; si el route lee c.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) pide zod ^4 — ese peer warning es conocido y aceptado. validator de hono (hono/validator) sustituyó a @hono/zod-validator (sus tipos duales zod v3/v4 causaban TS2589/exhaustion no resolubles con ZodTypeAny); las rutas tipan c.req.valid vía el ValidationInput derivado del schema.
  • .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 @@map en prisma/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" devuelven Result y nunca lanzan excepciones de dominio.
  • Tailwind v4 con tokens en @theme dentro de apps/web/src/index.css (p. ej. --color-accent: #1e90ff). Se usan como clases auto-generadas: text-accent, bg-success-soft, etc. Radius por defecto 0.75rem (rounded-xl).
  • Router NO es file-based (aunque stack.md lo diga): las rutas se declaran manualmente en apps/web/src/router.tsx con createRoute + addChildren y 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 para BottomNav (móvil) y Sidebar (desktop) — no dupliques la lista.
  • UI: primitivos propios en apps/web/src/components/ui/ (avatar, button, badge) más helper cn() en src/lib/utils.ts (clsx + tailwind-merge). Aunque stack.md mencione Shadcn, todavía no está instalado (sin Radix); úsalos directos.
  • Layout mobile-first: RootLayout usa columna max-w-md en móvil y dos columnas (Sidebar + contenido max-w-6xl) en lg+.

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.