Skip to content

Revisión de OpenCode: 20 ramas de arreglo, traducción de errores y acceso por rol - #28

Merged
bpstack merged 94 commits into
mainfrom
claude/compassionate-planck-gh6aof
Oct 12, 2026
Merged

bpstack merged 94 commits into
mainfrom
claude/compassionate-planck-gh6aof

Conversation

@bpstack

@bpstack bpstack commented Oct 12, 2026

Copy link
Copy Markdown
Owner

Cambios

Las 20 ramas de la revisión de OpenCode, fusionadas y probadas en preview (PR #7–#26), y el SESSION al día (#27):

  • Acceso y seguridad: lista de roles permitidos en vez de excluir a mantenimiento; los 403 y los accesos de admin a conversaciones ajenas quedan en el log, sin valores SQL; subidas de Backoffice comprobadas por su contenido.
  • Errores: los códigos del backend se traducen en es y en en el cliente.
  • Arreglos por módulo: Maintenance (historial en transacción, altas y fotos simultáneas), Parking (salida no anterior a la entrada, origen de la reserva), Groups (pagos coherentes, historial al borrar, ficha que se actualiza, contactos fuera para mantenimiento), notificaciones solo a usuarios activos, Scheduling (días fijos y solicitudes al generar, mes publicado de solo lectura), Caja, Checklist, facturas de Backoffice (negativas, duplicadas, fechas de pago) y una petición por periodo en el panel de inicio.
  • Tipos: sin any en el backend, con la regla como error.
  • Docs: TODO.md cerrado y reescrito, decisiones anotadas en cada módulo, SESSION.md al día.

Migraciones 20261011_keep_group_history_on_delete.sql y 20261012_unique_invoice_supplier_number.sql ya aplicadas en Aiven (2026-10-12).

Por qué

Cierre de la revisión de los informes de OpenCode: cada arreglo se contrastó con el código y se probó en local y en preview antes de llegar aquí.

bpstack added 30 commits October 8, 2026 09:34
- Remove SCHEDULING-SOLVER-PLAN.md references (archived)

- Add note about 2026-04-22 entry in decisions.md

- Fix TODO.md path (root → docs/TODO.md)

- Fix frontend AGENTS.md path (CLAUDE.md → AGENTS.md)
- main.py: SCHEDULING-SOLVER-PLAN.md §3.4 → docs/scheduling/solver.md «Where it runs»

- schemas.py: §3.1-§3.2 → docs/scheduling/solver.md «Input» y «Output»

- test_benchmark.py, test_corpus.py, solver-parity.test.ts: Fase 1/2 → docs/scheduling/decisions.md entrada 2026-04-22
- Add resolveSettingsTab helper to validate tab parameter

- Use helper in SettingsPanel to handle invalid ?tab= values

- Add 5 test cases for the helper
- Test excludeMantenimiento with 4 roles + missing user + uppercase

- Test canOpenModule with 4 roles x 6 modules matrix

- Verify 9 routers use excludeMantenimiento middleware
- excludeMantenimiento now uses allowedRoles = ['admin', 'recepcionista', 'group-admin'] instead of blockedRoles = ['mantenimiento'], so unknown roles are denied by default
- module-access.ts: rename allButMaintenanceRole to frontDeskRoles with an explicit allowlist
- role-access.test.ts: add 'auditor' role case (403 in middleware, false in all 6 modules)
- Add 57 BACKOFFICE codes to TRANSLATED set in errorCodeMessage.ts (alphabetical order)
- All codes have matching text in es/en errors.json and are sent with fixed text from backend
- Exclude 5 BACKOFFICE codes without translation: SUPPLIER_INACTIVE_EXISTS, SUPPLIER_HAS_INVOICES, INACTIVATE_SUPPLIER_ERROR, ACTIVATE_SUPPLIER_ERROR, DELETE_SUPPLIER_ERROR
- Add it.each test for all 57 codes (non-empty text in es and en)
- Add test for 5 excluded codes (return undefined)
- user-repository.ts: replace 6 'catch (error: any)' with 'catch (error)' and type assertions for .code and .message access
- user-repository.ts: replace 'as any' with explicit type 'Error & { code?: string }' for the duplicate entry error
- user-controllers.ts: replace 'catch (error: any)' with 'catch (error)' and type assertion for .message access
- Pattern used: (error as { code?: string }).code and (error as Error).message
- db-config.ts: ssl?: any → ssl?: object
- cron-service.ts: results?: any → results?: unknown
- checklist-report.ts: replace 9 any with proper types:
  - Import RowDataPacket from mysql2
  - Define interfaces RunRow, StepRow, CommentRow extending RowDataPacket
  - Use db.query<RowType[]> instead of (db as any).query
  - Replace (d: any) with (d: unknown) in fmt function
  - Remove all (s: any) and (c: any) from callbacks
- demo-restriction.test.ts: replace 9 'as any' with 'as unknown as Request[...]' or 'as unknown' for socket, user, headers, and mock access
- user-repository-login.test.ts: import RowDataPacket, replace db.query<any[]> with db.query<RowDataPacket[]>, replace (user as any) with (user as Record<string, unknown>)
- checklist.test.ts: import RowDataPacket, replace 7 'const [rows]: any' with 'const [rows] = await db.query<RowDataPacket[]>', remove (r: any) from callback
- employee-requests-repository.test.ts: import RowDataPacket, replace 'const [users]: any' with 'const [users] = await db.query<RowDataPacket[]>'
- Change '@typescript-eslint/no-explicit-any' from 'warn' to 'error' in eslint.config.js
- Remove outdated comment about 341 existing uses (now 0)
- All code is now free of explicit any types
…criteria

- test_benchmark.py: the 30x31 exit criterion lives in the 2026-05-09 entry
  of decisions.md, not in 2026-04-22.
- test_corpus.py, solver-parity.test.ts: point to «How it is tested» in
  solver.md and drop a quote that no document contains.

Why: the previous commit replaced the archived plan with references that
did not hold the cited text.
- Remove the "?tab= of a tab without permission" entry.

Why: resolveSettingsTab falls back to the first available tab. Checked in
the browser: admin with ?tab=xxx and ?tab=demo opens Users, a receptionist
with ?tab=users opens Notifications.
…ny role

- module-access.ts: export FRONT_DESK_ROLES and build frontDeskRoles on it.
- roleCheck.ts: excludeMantenimiento reads FRONT_DESK_ROLES instead of its
  own copy, and its 403 no longer says the role only reaches maintenance.

Why: the allowlist lived in two files that had to be kept in step, and
after the switch to an allowlist the old message was wrong for any role
other than mantenimiento.
- Remove the "excludeMantenimiento is an exclusion list" entry.

Why: the guard and module-access.ts share FRONT_DESK_ROLES, an allowlist;
role-access.test.ts pins the four roles and denies an unknown one.
- Remove the "55 uses of any left in the backend" entry.

Why: auth, config, cron, scripts and tests are typed and no-explicit-any
is an error again; the backend lint reports 0 problems.
- blacklist-controller.ts: getImage 404s carry code NOT_FOUND.
- demo-reset-controller.ts: failed reset and status 500s carry code
  INTERNAL_ERROR.

Why: the frontend translates errors by `code`; without it the user saw the
raw value of `error`, which is the code itself.
- errorCodeMessage.ts: add the 24 codes the backend sends that were still
  untranslated (AUTH, generic ones such as FORBIDDEN or INVALID_ID, and
  five supplier codes); keep the set in alphabetical order.
- errors.json (es, en): add texts for AUTH_DEMO_UNAVAILABLE and the five
  supplier codes that had none.
- errorBodyMessage: shared helper for errors read with a plain fetch.
  Used by the login, the invoice PDF download and SupplierInvoicesModal,
  which showed `error` as is.
- error-code-message.test.ts: new guard that every ERROR_CODES.X in the
  backend has a text in es and en; drop the assertions that required
  those codes to stay untranslated; cover errorBodyMessage.

Why: a failed login showed AUTH_INVALID_CREDENTIALS on screen. Checked in
the browser in es and en: wrong password and duplicate supplier name.
- Rewrite the entry: backend codes are translated on the client; what
  remains is the server actions, maintenance, the demo reset 409 and the
  login subtitle.

Why: the old entry described the whole job, most of which is now done.
…count

- TODO: remove the high-priority entry to apply
  20261011_keep_group_history_on_delete.sql on Aiven.
- database README: 26 migrations recorded and applied on Aiven, with the
  two applied on 2026-10-12.

Why: both migrations were applied on Aiven on 2026-10-12 after a dry run
and read-only checks, and verified afterwards; the README still said 15.
docs(scheduling): referencias rotas a la documentación del solver
fix(settings): un ?tab= inválido cae en la primera pestaña disponible
refactor(auth): acceso por rol con lista de permitidos
refactor(backend): quitar los any restantes y hacer no-explicit-any error
…of' into opencode/error-codes

# Conflicts:
#	docs/TODO.md
feat(i18n): traducir los códigos de error del backend en el cliente
fix(maintenance): cambios con su historial en una transacción y altas simultáneas
fix(parking): rechazar una salida anterior a la entrada
fix(parking): conservar el origen y la referencia externa de la reserva
…test

- manual-recipients.test.ts: mock config/db.js, which the controller loads
  through NotificationRepository.

Why: CI has no backend/.env, so loading the pool config threw "Falta
LOCAL_DB_PASSWORD" and the file failed before any test ran; locally the
.env hid it. Reproduced with LOCAL_DB_PASSWORD empty; now the whole suite
passes that way.
fix(notifications): avisos manuales solo a usuarios activos
fix(groups): importes, estado y porcentajes de los pagos coherentes
fix(groups): conservar el historial de un grupo al borrarlo
fix(groups): la ficha se actualiza al editar y mantenimiento no ve contactos
…of' into opencode/fix-backoffice-invoices

# Conflicts:
#	backend/db-mysql/INDEX.md
fix(scheduling): generar respetando días fijos y solicitudes, y mes publicado de solo lectura
fix(cashier): vales en estado final, alta de vales atómica y totales con permiso
fix(checklist): comentarios y fotos de un día cerrado solo los toca admin
fix(backoffice): comprobar las subidas por su contenido y limitar las descargas
fix(backoffice): rechazar importes negativos, facturas duplicadas y fechas de pago imposibles
fix(security): registrar decisiones de autorización y sacar los valores SQL del log
perf(home): una petición por periodo para las entradas importantes del libro
docs(todo): cerrar los puntos revisados y anotar las decisiones
- Estado: the 20 opencode/* branches are merged into the working branch
  (PR #7-#26) and tested on preview; both migrations applied on Aiven.
- Siguiente: the PR to main comes first; the credential rotation now names
  the plaintext application password found in the history; the time zone
  task is listed.
- Cuidado: only 3 SQL files still cite the archived plans.

Why: the session still described the state of 2026-10-05, said no
credential was in the history, and counted 10 broken references.
docs(session): cerrar la revisión de OpenCode y apuntar al PR a main
@vercel

vercel Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
four-points Ready Ready Preview Oct 12, 2026 7:16pm UTC

@bpstack
bpstack merged commit dbc230b into main Oct 12, 2026
4 checks passed
bpstack added a commit that referenced this pull request Oct 14, 2026
- SESSION: main now matches the branch (PR #29, merge 47f77b9), the
  OpenCode review is in main since PR #28, and the next steps start at
  the post-publication TODO list
- TODO: update the last merge into main, which still said PR #4

This branch was successfully deployed

1 active deployment
Preview — 856d3207 Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant