# CLAUDE.md — Plataforma BALAM XVII

## Resumen

Plataforma web **interna** para ~10 personas del equipo operativo de
BALAM XVII. NO es pública. Gestiona: información de estudiantes que
compraron kit, armado y estados de kits, inventario de piezas, y
asistencia a bootcamps. Todos los usuarios tienen el mismo nivel de
permisos (no hay roles).

Plazo: 1 semana de desarrollo.

## Conexión con `../balam_db/`

- **Misma base de datos** MySQL `balam_2026`.
- El **esquema** de las tablas de negocio (estudiantes, kits, piezas,
  bootcamps, etc.) lo gestiona el proyecto Python en `../balam_db/`
  con los archivos `01_schema.sql`, `02_seed.sql`, `03_views.sql` y
  `04_migration_kits_inventario.sql`.
- Esta plataforma **NO crea ni modifica** esas tablas. Solo las
  consume vía Prisma (`db pull` para introspectar).
- La tabla `users` (autenticación interna) también vive en `balam_2026`
  pero se gestiona por SQL file (`balam_db/05_users.sql`), no por Prisma
  migrate — para consistencia con el resto del esquema. Prisma la
  conoce vía `db pull` y `prisma generate`.

## Stack

- **Backend**: Express + TypeScript + Prisma
- **Frontend**: React + Vite + TypeScript + TailwindCSS + shadcn/ui
- **BD**: MySQL `balam_2026`
- **Auth**: username + password, bcrypt, JWT en cookie HTTP-only
- **Validación**: zod
- **Headers de seguridad**: helmet
- **Monorepo**: pnpm workspaces
- **Deploy**: DigitalOcean (servidor propio)
- **Sin tests automatizados** en esta fase

## Convenciones de código

- **Código en inglés**: rutas (`/api/students`), tablas nuevas
  (`users`), nombres de variables, archivos, modelos Prisma nuevos,
  componentes React.
- **UI y mensajes visibles en español**: labels, botones, mensajes de
  error del API que se renderizan tal cual (ej. `"Credenciales
  inválidas"`).
- **Tablas existentes en español**: `estudiantes`, `kits`, `colegios`,
  etc. quedan así. Cuando empecemos a usarlas, los modelos Prisma se
  renombran a inglés con `@@map("nombre_original")`.
- **TypeScript estricto** en backend (`"strict": true`).
- **Estructura por rol** (`routes/`, `middleware/`, `lib/`) hasta tener
  más de 3 features.
- **Errores**: `throw new HttpError(400, "mensaje en español")`; el
  middleware `error.ts` los formatea.
- **Cero comentarios decorativos**. Solo cuando expliquen un porqué no
  obvio.

## Seguridad — qué riesgo previene cada decisión

- **bcrypt** en passwords → si filtran la BD, no se ven en claro.
- **JWT en cookie HTTP-only** → el JS del navegador no puede leerlo,
  mitiga robo por XSS.
- **Cookie `Secure` en producción** → no viaja en HTTP plano (evita
  man-in-the-middle).
- **Cookie `SameSite=Lax`** → mitiga CSRF en navegación normal.
- **helmet** → headers como X-Frame-Options, HSTS, Referrer-Policy.
- **CORS estricto a 1 origen** → otros dominios no pueden llamar al
  API desde un navegador.
- **Rate limit en `/auth/login`** → frena fuerza bruta de contraseñas.
- **zod en cada input** → no llegan tipos raros a Prisma ni a la BD.
- **`.env` fuera de git** → `JWT_SECRET` y `DATABASE_URL` no se filtran
  al repo.
- **Mensaje genérico `"Credenciales inválidas"`** → no revela si un
  usuario existe.

## Los 4 módulos

### Module 1 — Students (estudiantes con kit)
Fuente: vista `v_estudiantes_completos` filtrando `categoria_crea IS
NOT NULL`. Tabla con filtros (colegio, departamento, categoría,
modalidad, estado de pago, estado del kit), búsqueda por nombre y
correo, detalle por estudiante, export CSV.

### Module 2 — Kits assembly (armado de kits)
Fuente: vista `v_armado_kits`. Editar inline dirección de entrega y
bootcamp de recogida. Dropdown de estado: `asignado → empacado →
enviado → recibido / recogido_en_bootcamp`. Filtros por categoría y
estado. Buscador por código de kit y nombre. Vista de progreso
(opcional) con contadores.

### Module 3 — Inventory (inventario)
- (a) CRUD de `piezas` (nombre, descripción, `stock_actual`).
- (b) Configurar `componentes_kit` por categoría.
- (c) Pantalla "ingreso de kits armados": input `(N, categoría)`,
      sube `stock_kits_armados.cantidad_armados`, baja `piezas.stock_actual`
      según `componentes_kit`. **Bloquear si una pieza no alcanza.**
- Registrar mermas en tabla `mermas`. Stock de playeras por talla en
  `playeras_stock`.

### Module 4 — Bootcamp attendance
Selector de bootcamp (los 7 sembrados). Lista de estudiantes previstos
(`crea_inscripciones.bootcamp_id`). Checkbox por estudiante. Botón
"agregar estudiante no previsto" que busca en `estudiantes` y agrega a
`asistencia_bootcamp`. Contador en vivo: previstos / asistieron /
adicionales.

## Fuera de alcance

- Dashboards o gráficas (irán en Power BI conectado a la misma BD).
- App pública para participantes o padres.
- Notificaciones por correo o SMS.
- Sincronización con Google Forms.
- Histórico/auditoría de cambios.
- Verificación de pagos en la app (sigue manual en Sheets).
- Diferenciación de roles (todos hacen todo).
- 2FA, verificación de email, recuperación pública de contraseña.
- App para el día del evento (Compite).

## Cómo correr (resumen)

```bash
pnpm install
cp .env.example backend/.env  # completar
pnpm db:pull                  # solo la primera vez (o si balam_db agrega tablas)
pnpm --filter backend exec prisma generate
pnpm dev
```

> ⚠️ **Sobre `pnpm db:pull`**: re-corerlo SOBRESCRIBE
> `prisma/schema.prisma`, incluido el modelo `User` con sus `@@map` y
> `@map`. Si lo corres después de modificaciones manuales al schema,
> tenés que re-agregar el modelo `User` y los mappings a inglés.

Más detalle en [README.md](README.md).
