Skip to content

Commit fa744b8

Browse files
committed
docs: record the demo as built and what is left before going public
- DECISIONS: ADR-039, the local database is a documented install again and Aiven stays the only shared one; ADR-015 points to it - TODO: the demo entry now lists only what is left (scheduling base, role migration on Aiven, production variables); demo-admin, local database removal and the schema comparison entries go; three findings added (excludeMantenimiento is a deny list, the old disable_demo_user script, blank Settings tab) - SESSION and ROADMAP: phase 5 built and tested on preview; next steps - VERIFY: one row per commit since the switch to the new repository - INDEX.md: 20261005_drop_demo_admin_role.sql logged Why: ADR-038 relies on the local database ADR-015 had dropped, and the pending list has to match what is done.
1 parent 4884e78 commit fa744b8

6 files changed

Lines changed: 95 additions & 64 deletions

File tree

‎backend/db-mysql/INDEX.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ db-mysql/
108108
| 2026-10-05 | `20261005_add_demo_reset_log.sql` | Crea `demo_reset_log`: un registro por cada reinicio diario de la demo y por cada base de horarios guardada (ADR-038). La base vive en tablas `demo_snapshot_scheduling_*` que crea el backend al guardarla. Hay que aplicarla antes de desplegar el código. `CREATE TABLE IF NOT EXISTS`. | ✅ local · ✅ Aiven |
109109
| 2026-10-05 | `20261005_complete_fresh_install.sql` | Completa una instalación desde cero: el baseline congelado no crea `cashier_history` (nombre de clave duplicado), `scheduling_assignments` (referencia a una tabla creada después) ni `demo_activity_log`, y deja `roles.name` en `varchar(50)`. Definiciones copiadas de Aiven. En Aiven no cambia nada; en local creó `demo_activity_log`, que faltaba. `pnpm setup:local` además corrige esos dos fallos del baseline en memoria. | ✅ local · ✅ Aiven (sin cambios) |
110110
| 2026-10-05 | `20261005_fix_bo_monthly_summary_view.sql` | Recrea `v_bo_monthly_summary` con `period` en el `GROUP BY`. Con `ONLY_FULL_GROUP_BY` (activo en Aiven y local) toda consulta a la vista fallaba con el error 1055 y `GET /api/backoffice/stats/monthly` respondía siempre 500. Mismas columnas y mismos grupos; comprobada contra un cálculo directo sobre `bo_invoices`. | ✅ local · ✅ Aiven |
111+
| 2026-10-05 | `20261005_drop_demo_admin_role.sql` | Borra el rol `demo-admin` si ningún usuario lo tiene (ADR-038): la cuenta demo es un admin con `is_demo` y el código ya no conoce ese rol. En local no existía. | ✅ local (sin cambios) · ⏳ Aiven |
111112

112113
### Verificación (99)
113114

‎docs/DECISIONS.md‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@
244244

245245
## ADR-015 — Una sola base de datos: Aiven, con datos de prueba
246246

247-
- **Estado:** ✅ aceptada (2026-09-28)
247+
- **Estado:** ✅ aceptada (2026-09-28) · 📌 BD local revisada por
248+
[ADR-039](#adr-039--la-bd-local-vuelve-como-instalación-documentada-aiven-sigue-siendo-la-única-compartida)
248249
- **Fecha:** 2026-09-28
249250
- **Decisión:** el proyecto trabaja contra **una única BD, la de Aiven**, que
250251
solo contiene datos de ejemplo. No se mantiene una BD local de desarrollo ni
@@ -817,3 +818,27 @@
817818
el solver y las escrituras del usuario demo. El README pasa a explicar la
818819
instalación local.
819820
- **Revisa:** ADR-037 en los usuarios demo y su acceso.
821+
822+
## ADR-039 — La BD local vuelve como instalación documentada; Aiven sigue siendo la única compartida
823+
824+
- **Estado:** ✅ aceptada (2026-10-05)
825+
- **Fecha:** 2026-10-05
826+
- **Decisión:**
827+
- **Aiven** sigue siendo la única BD del proyecto que se comparte:
828+
producción, preview y la demo pública.
829+
- **La BD local** vuelve a ser parte documentada del proyecto: quien clona el
830+
repositorio la monta con `pnpm setup:local` (con MySQL propio o en Docker)
831+
y el propietario puede seguir usando la suya con `pnpm dev:local`. Se
832+
mantienen `DB_ENVIRONMENT`, el preset `local` y `LOCAL_DB_*`.
833+
- **Motivo:** ADR-038: quien quiera ver la aplicación entera la instala en
834+
local con un admin completo. Y lo que ADR-015 rechazaba ya existe: una
835+
instalación desde los scripts del repositorio, comprobada el 2026-10-05 en
836+
un MySQL limpio, deja la misma estructura que Aiven (1161 de 1161 columnas,
837+
índices, claves, triggers y procedimientos) y los mismos catálogos.
838+
- **Rechazado:** quitar el soporte de BD local (la tarea pendiente de
839+
ADR-015).
840+
- **Consecuencias:** las migraciones se siguen aplicando en local y en Aiven
841+
(`INDEX.md`). Dos fallos del baseline congelado, que impedían instalar desde
842+
cero, se corrigen en `setup:local` y con
843+
`20261005_complete_fresh_install.sql` sin tocar `aiven/` (ADR-021).
844+
- **Revisa:** ADR-015 en la BD local.

‎docs/ROADMAP.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,7 @@ rotación de credenciales (ADR-007) no bloquea: va en «Después de publicar» d
6565
Que cualquiera pruebe la aplicación en la propia web, que es solo un escaparate
6666
(ADR-037): un admin demo restringido que entra con un botón, datos ficticios,
6767
generación de horarios y reinicio diario; y quien quiera verlo todo lo instala
68-
en local con admin completo (ADR-038). Pasos en `TODO.md`, «Demo pública en la
69-
propia web». El repositorio se hace público cuando la demo esté lista.
68+
en local con admin completo (ADR-038, ADR-039). Hecho en código y probado en
69+
preview el 2026-10-05; lo que falta, en `TODO.md`, «Demo pública en la propia
70+
web: lo que falta». El repositorio se hace público cuando la demo esté en
71+
producción.

‎docs/SESSION.md‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ y auditado (`GITCLEAN.md`).
2121
El historial limpio está en `bpstack/four-points`, **todavía privado**. El
2222
original sigue privado como `four-points-archive`. Vercel y Render despliegan ya
2323
desde el nuevo, en producción y en preview (`VERIFY.md`, «Cambio al repositorio
24-
nuevo»). Decisiones en `DECISIONS.md`, hasta ADR-038.
24+
nuevo»). Decisiones en `DECISIONS.md`, hasta ADR-039.
25+
26+
La demo pública (fase 5) está hecha en código y probada en preview el
27+
2026-10-05: cuenta demo con botón, bloqueos, límites, reinicio diario,
28+
Configuración → Demo, instalación local con `pnpm setup:local` y `demo-admin`
29+
retirado. `DEMO_MODE` y `NEXT_PUBLIC_DEMO_MODE` solo están en preview.
2530

2631
## ⚠️ Empieza por aquí
2732

@@ -38,10 +43,12 @@ nuevo»). Decisiones en `DECISIONS.md`, hasta ADR-038.
3843

3944
## Siguiente
4045

41-
1. Construir la demo en la propia web, paso a paso: `TODO.md`, «Demo pública
42-
en la propia web» (ADR-037, ADR-038). Empieza por la marca `is_demo`.
43-
2. Pasar `four-points` a público y activar secret scanning y push protection.
44-
3. «Después de publicar» de `TODO.md`, empezando por la rotación de
46+
1. Terminar la demo: `TODO.md`, «Demo pública en la propia web: lo que
47+
falta» (base de horarios, migración del rol en Aiven, variables en
48+
producción tras el merge).
49+
2. PR a `main` y probar el botón demo en la web.
50+
3. Pasar `four-points` a público y activar secret scanning y push protection.
51+
4. «Después de publicar» de `TODO.md`, empezando por la rotación de
4552
credenciales (se puede adelantar).
4653

4754
Hecho el 2026-10-05: Vercel y Render despliegan solos desde este repositorio
@@ -64,6 +71,10 @@ Nada ahora mismo.
6471
`SCHEDULING-CONSTRAINTS.md §7.5`** en un comentario: los scripts 01–19 no se
6572
tocan (ADR-021). La sección equivalente es
6673
`docs/scheduling/constraints.md §7.5`.
74+
- **La cuenta demo es un admin** (`users.is_demo = 1`): lo que no deba tocar
75+
se bloquea en la ruta con `denyDemo`/`denyDemoWrites` o en
76+
`demoRestriction`. Una ruta nueva que escriba fuera de lo que reinicia el
77+
mock (usuarios, catálogos, configuración) necesita su guarda.
6778
- **Enlaces rotos conocidos** tras archivar: `backend/README.md` (enlaces a
6879
`docs/backend/…`) y comentarios que citan `Global-Plan.md` o
6980
`SCHEDULING-SOLVER-PLAN.md`. Se arreglan al escribir cada módulo (ADR-010).

‎docs/TODO.md‎

Lines changed: 27 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,6 @@ sigue siendo donde se arregla este fichero y se prueba en el entorno preview.
136136
`PK-AAAAMMDD` del trigger, `CURRENT_TIMESTAMP` de las tablas) van 1–2 h
137137
por detrás de Madrid: entre las 00:00 y las 02:00 «hoy» sigue siendo ayer.
138138
_Comprobado el 2026-09-28._
139-
- [ ] **Quitar el soporte de BD local del código** (ADR-015) — `DB_ENVIRONMENT`
140-
y el preset `local` de `backend/config/db.ts`, el script `dev:local`, las
141-
variables `LOCAL_DB_*` y las menciones a «local primero» en
142-
`backend/db-mysql/`.
143-
- [ ] **Comprobar que los scripts del repo reproducen Aiven** — hoy Aiven es la
144-
única BD y `backend/db-mysql/` la fuente de verdad (ADR-016), pero nadie
145-
ha verificado que coincidan. Pista: la BD local, instalada desde esos
146-
scripts, difería de Aiven en `demo_activity_log`, `notifications.module`,
147-
`roles.name` y 7 claves foráneas (comparación del 2026-09-28).
148139
- [ ] **Logbook: papelera e historial solo ocultos en la pantalla** — el backend
149140
da `/trashed`, `include_trashed`, el historial y los comentarios de
150141
entradas borradas a cualquier rol con acceso. _Según la revisión
@@ -288,6 +279,20 @@ sigue siendo donde se arregla este fichero y se prueba en el entorno preview.
288279

289280
### 🟢 Baja
290281

282+
- [ ] **`excludeMantenimiento` es una lista de exclusión** — parking, lista
283+
negra, caja, partes, conciliación y departamentos dejan pasar cualquier
284+
rol salvo `mantenimiento`, y `services/auth/module-access.ts` lo replica.
285+
Hoy solo hay roles conocidos (el rol va en el token firmado y sale de
286+
`roles`), pero un rol nuevo tendría acceso sin que nadie lo decida. Pasar
287+
a lista de permitidos. _Comprobado el 2026-10-05 al retirar
288+
`demo-admin`._
289+
- [ ] **`20260512_disable_demo_user.sql` desactivaría la cuenta demo** si se
290+
volviera a ejecutar (`UPDATE users SET is_active = 0 WHERE username =
291+
'demo'`). `setup:local` no la ejecuta (es anterior al baseline); no
292+
aplicarla a mano. _Comprobado el 2026-10-05._
293+
- [ ] **Configuración: `?tab=` de una pestaña sin permiso deja el contenido en
294+
blanco** — p. ej. recepción con `?tab=users`; debería caer en la primera
295+
pestaña disponible. _Visto el 2026-10-05._
291296
- [ ] **Scheduling: vista de solo lectura para los demás roles** — hoy
292297
`/dashboard/scheduling` es solo de `admin` y el resto no ve el cuadrante.
293298
El dueño quiere que los demás (salvo `mantenimiento`) vean el cuadrante
@@ -299,57 +304,23 @@ sigue siendo donde se arregla este fichero y se prueba en el entorno preview.
299304
pestaña muestra las rechazadas. Una factura incorrecta hoy se borra. El
300305
dueño decidió el 2026-10-04 no añadirlo porque casi nunca pasa; si se
301306
añade, hace falta también reabrir (`rejected` → `pending`).
302-
- [ ] **Demo pública en la propia web** (fase 5 de `ROADMAP.md`, ADR-037 y
303-
ADR-038) — la web es solo un escaparate, así que la demo va en
304-
`four-points.stackbp.es` con su BD. Un paso por PR, probado en preview:
305-
1. **Marca `is_demo`** en `users` (migración en `scripts/`), en el token y
306-
en un middleware que bloquea, para usuarios demo: `/api/users` (salvo
307-
lecturas), `/api/auth/register`, `/api/auth/me/*`, escrituras en
308-
`/api/departments`, toda petición `multipart`, `/api/demo-activity` y
309-
la configuración de horarios (turnos, `config`, empleados y
310-
contratos). Tests de cada bloqueo y de que el resto pasa.
311-
2. **Un solo usuario demo, rol admin**, con contraseña aleatoria que nadie
312-
conoce. Ruta de entrada sin contraseña y botón «Probar la demo» en el
313-
login, los dos solo con `DEMO_MODE=true`; la ruta con límite propio.
314-
Las cuentas del dueño (`admin`, `qa_*`) siguen aparte.
315-
3. **Límites:** generar horarios unas 5 veces por hora por IP y usuario
316-
(el solver ya tiene 30 s de máximo y va de uno en uno; Render
317-
gratuito tiene 512 MB) y escrituras más estrictas para el usuario
318-
demo.
319-
4. **Reinicio diario** con la primera entrada a la demo del día: recarga
320-
`mock-data.sql` (fechas relativas a hoy; hay que poder ejecutarlo desde
321-
Node, y hoy usa `DELIMITER`) y restaura una foto de las tablas de
322-
horarios guardada en la BD. La base de horarios se genera una vez con
323-
el solver; no se saca de los meses actuales, que vienen de bajas
324-
reales. Ojo: el mock elige autores por rol y verá al usuario demo.
325-
5. **Instalación local con admin completo:** `docker-compose.yml` solo
326-
con MySQL (opcional), `pnpm setup:local` (tablas con
327-
`MASTER_INSTALL.sql`, primer admin con contraseña que da quien
328-
instala, departamentos y mock) y README en inglés con los pasos y el
329-
entorno de Python del solver. Comprobar antes que `MASTER_INSTALL.sql`
330-
deja una BD igual que la actual.
331-
6. **Seguridad:** test de que un `POST` desde otro origen recibe 403
332-
(CSRF) y de que un enlace `javascript:` en las notas del checklist no
333-
se ejecuta (XSS).
334-
7. **Retirar `demo-admin`** (ver entrada siguiente) y documentar.
335-
- [ ] **Retirar el rol `demo-admin`** (lo sustituye la marca `is_demo`,
336-
ADR-038) — el único usuario con
337-
ese rol, `demo`, está desactivado (`is_active = 0`, comprobado en Aiven el
338-
2026-10-04). El rol sigue en los middlewares de `roleCheck.ts`, en
339-
`demoRestriction` (lista blanca de escrituras y registro de intentos
340-
bloqueados), en las rutas `/demo` y en el frontend (`isAdminRole`). Las
341-
reglas añadidas el 2026-10-02 ya no lo incluyen. En producción, mientras
342-
exista, `demo-admin` entra en backoffice y lee los PDFs de facturas por
343-
`/pdf-url`, `/pdf-download` y el ZIP (antes un punto 🔴 aparte; se movió
344-
aquí el 2026-10-04 porque no hay ninguna cuenta activa). Retirarlo
345-
incluye la migración que quita el usuario `demo` y el rol.
307+
- [ ] **Demo pública en la propia web: lo que falta** (fase 5 de `ROADMAP.md`,
308+
ADR-037 y ADR-038) — el código está hecho y probado en preview el
309+
2026-10-05 (cuenta demo, bloqueos, límites, reinicio diario, pestaña
310+
Configuración → Demo, `setup:local`). Queda:
311+
1. **Base de horarios:** borrar los meses actuales de Aiven (vienen de
312+
bajas reales), generar 2 o 3 meses limpios con el solver y pulsar
313+
«Guardar horarios actuales como base». Hasta entonces el reinicio no
314+
toca horarios y lo que genere un visitante se queda.
315+
2. **Aplicar en Aiven `20261005_drop_demo_admin_role.sql`** (borra el rol
316+
sin usuarios; enseñar antes qué borra).
317+
3. **Producción:** tras el merge, `DEMO_MODE=true` en el servicio de
318+
producción de Render y `NEXT_PUBLIC_DEMO_MODE=true` en Production de
319+
Vercel (hoy solo están en preview). Probar el botón en la web.
346320
- [ ] **Conciliation: `GET /api/conciliations` sin paginar ni filtrar** —
347321
devuelve todo el histórico a cualquier rol con acceso. _Según la revisión
348322
`security` L3 del 2026-09-28 (fichero y línea en el informe); no repasado
349323
por mí._
350-
- [ ] **Backoffice: `demo-admin` ve IBAN, CIF y datos de contacto completos** de
351-
los proveedores. _Según la revisión `security` L3 del 2026-09-28 (fichero
352-
y línea en el informe); no repasado por mí._
353324
- [ ] **Checklist: `checklist_config` existe pero no se usa.** _Comprobado por
354325
mí el 2026-09-28._
355326
- [ ] **Scheduling: reiniciar un mes no usa transacción** — si falla a mitad, el

‎docs/VERIFY.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,24 @@ Vercel y Render se reconectaron de `four-points-archive` a `bpstack/four-points`
231231
| `d197ad6` | docs(todo): drop the local path of the harness repository | (documentación) | no aplica | — |
232232
| `5b216a0` | docs(roadmap): close phases 1c and 2 and make publication current | (documentación) | no aplica | — |
233233
| `0f237d0` | docs(decisions): record the publication order and when to rotate | (documentación) | no aplica | — |
234+
| `2009f39` | docs(verify): record the switch to the new repository | (documentación) | no aplica | — |
235+
| `8194031` | docs(session): move the session to the publication phase | (documentación) | no aplica | — |
236+
| `0bb4c1f` | fix(db): require the Aiven user and port instead of defaulting them | Puerto y usuario de Aiven por defecto en el código | Producción arranca y conecta tras el merge (PR #2) | ✅ 2026-10-05 |
237+
| `a474007` | chore(db): rewrite the mock data without users and for the current schema | Datos ficticios para Aiven | Cargado en local y en Aiven; horarios intactos | ✅ 2026-10-05 |
238+
| `a889999` | docs: plan the demo on the showcase site before going public | (documentación) | no aplica | — |
239+
| `e332b8a` | docs: settle the demo design and the local install | (documentación) | no aplica | — |
240+
| `5789e83` | feat(auth): restrict the public demo account with an is_demo flag | Demo: marca `is_demo` y bloqueos | Preview, sesión demo real: 18 rutas, lecturas 200 y bloqueadas 403 | ✅ 2026-10-05 |
241+
| `a306d36` | docs(db): mark the is_demo migration as applied on Aiven | (documentación) | no aplica | — |
242+
| `8553963` | fix(auth): answer 403 to blocked demo requests without a JSON body | — | Local: DELETE y subidas bloqueadas dan 403, no 500/401 | ✅ 2026-10-05 |
243+
| `7507d58` | feat(auth): enter the public demo with one button, without a password | Demo: entrada con botón | Preview: botón visible, entra como Demo · Admin; login con contraseña de `demo` da 401 | ✅ 2026-10-05 |
244+
| `d8c23af` | feat(auth): rate limit the demo account's writes and schedule generation | Demo: límites | `demo-limits.test.ts` (5/h por IP, 30/h en total, 60 escrituras/15 min) | 🧪 |
245+
| `db8b356` | feat(demo): reset the demo data daily and from Settings | Demo: reinicio diario | Preview: primer reinicio del día registrado en Aiven (734 ms); local: base de horarios restaurada, fallo deshecho; pestaña Demo solo para admins | ✅ 2026-10-05 |
246+
| `a2395a7` | docs(db): mark the demo reset log migration as applied on Aiven | (documentación) | no aplica | — |
247+
| `7e7ed39` | test(auth): mock the demo reset in the login timing test | — | CI en verde | ✅ 2026-10-05 |
248+
| `ee9cbc0` | fix(db): load the mock data on a database with a single admin | — | `setup:local` en un MySQL limpio carga el mock | ✅ 2026-10-05 |
249+
| `a8882c4` | feat(db): install a local database from scratch with pnpm setup:local | Demo: instalación local | MySQL 8.0 limpio en Docker: estructura igual que Aiven (1161 de 1161) y mismos catálogos; la app entra con el admin | ✅ 2026-10-05 |
250+
| `9336716` | feat(db): give the local install a documented admin password | — | `setup-local.test.ts` | 🧪 |
251+
| `e3a642c` | fix(db): group the backoffice monthly summary view by its period | — (hallazgo del 2026-10-05) | `GET /api/backoffice/stats/monthly` en preview da 200; la vista coincide con un cálculo directo | ✅ 2026-10-05 |
252+
| `9991d79` | test(security): check the CSRF defence and the session cookies by behaviour | Demo: CSRF | `csrf-origin.test.ts` (servidor Express real), `session-cookies.test.ts`; preview: origen ajeno da 403 | ✅ 2026-10-05 |
253+
| `4449b7a` | fix(checklist): render unsafe links in step notes as plain text | Demo: XSS | `safe-href.test.ts` (11 URL maliciosas) | 🧪 |
254+
| `143882d` | refactor(auth): retire the demo-admin role | Retirar `demo-admin` | ⏳ preview tras el push; la migración del rol, pendiente en Aiven | ⏳ |

0 commit comments

Comments
 (0)