Skip to content

refactor(front): drop auth structural directives in favor of native @if (closes #248)#11

Merged
dherrero merged 1 commit into
mainfrom
refactor/front-auth-directives-control-flow
May 19, 2026
Merged

refactor(front): drop auth structural directives in favor of native @if (closes #248)#11
dherrero merged 1 commit into
mainfrom
refactor/front-auth-directives-control-flow

Conversation

@dherrero
Copy link
Copy Markdown
Owner

@dherrero dherrero commented May 19, 2026

Summary

Cierra ticket #248 (tech-debt, front, auth, angular-21, prioridad alta).

Elimina las cuatro directivas estructurales custom basadas en TemplateRef + ViewContainerRef y migra al control flow nativo de Angular 21 (@if).

  • *appHasPermission@if (auth.hasPermission(...))
  • *appHasAnyPermission@if (auth.hasAnyPermission([...]))
  • *appHasAllPermissions@if (auth.hasAllPermissions([...]))
  • *appIfLoggedIn@if (auth.isLoggedIn()) { ... } @else { ... }

Se cazó un bug por el patrón "nombre-del-input ≠ selector estructural" — el azúcar *appHasPermission="X" desugarea en [appHasPermission]="X", pero el @Input() interno se llamaba hasPermission, así que el valor nunca llegaba y el botón "Panel admin" no aparecía nunca. El alias @Input('appHasPermission') mitigaba, pero @if cierra la categoría entera.

Tabla antes → después

Antes Después
<el *appHasPermission=\"Permission.ADMIN\">…</el> @if (auth.hasPermission(Permission.ADMIN)) { <el>…</el> }
<el *appHasAnyPermission=\"[A, B]\">…</el> @if (auth.hasAnyPermission([A, B])) { <el>…</el> }
<el *appHasAllPermissions=\"[A, B]\">…</el> @if (auth.hasAllPermissions([A, B])) { <el>…</el> }
<el *appIfLoggedIn=\"true\">…</el> @if (auth.isLoggedIn()) { <el>…</el> }
<el *appIfLoggedIn=\"false\">…</el> @if (!auth.isLoggedIn()) { <el>…</el> }
Positivo + negativo combinados @if (auth.isLoggedIn()) { … } @else { … }

Breaking change (API de plantillas)

Cualquier proyecto que importe estas directivas dejará de compilar:

  • HasPermissionDirective
  • HasAnyPermissionDirective
  • HasAllPermissionsDirective
  • IfLoggedInDirective

Migración mecánica documentada en apps/front/src/app/libs/auth/directives/USAGE.md.

Cambios

  • apps/front/src/app/libs/auth/services/auth.service.ts: nuevo helper público isLoggedIn() que lee el signal token, lo que hace que @if re-evalúe automáticamente al hacer login/logout o rotar el access token.
  • apps/front/src/app/pages/home/home.component.html: único consumidor real; migrado a @if (auth.isLoggedIn()) { … } @else { … }.
  • apps/front/src/app/pages/home/home.component.ts: standalone + OnPush, expone auth como inyección pública. Saca CommonModule e IfLoggedInDirective de imports.
  • apps/front/src/app/libs/auth/index.ts: deja de re-exportar las 4 directivas.
  • Borrados: las 4 directivas + sus 4 specs + el barrel directives/index.ts.
  • apps/front/src/app/libs/auth/directives/README.md y USAGE.md: reescritos como guía de migración (tabla antes/después, ejemplos prácticos, explicación del bug histórico).

Test plan

  • npm run test:front63 / 63 verde (los 31 tests removidos son los de las propias directivas borradas).
  • npx nx run front:lint → clean.
  • npx nx run front:build --configuration=development → succeeds.
  • Grep final en apps/front/src/**/*.{html,ts}: 0 ocurrencias de appHasPermission|appHasAnyPermission|appHasAllPermissions|appIfLoggedIn (sólo quedan referencias en docs como tabla histórica).
  • Grep final: 0 *ngIf / *ngFor en plantillas tocadas.
  • HomeComponent sigue standalone + inject() + OnPush.
  • Smoke manual sugerido tras merge: levantar el stack, entrar a /, verificar que el card de "no logueado" aparece; hacer login; verificar que el card de "logueado" reemplaza al anterior sin recargar; logout vuelve al estado inicial.

Criterios de aceptación del ticket #248

  • Cero ocurrencias de las 4 directivas estructurales en código.
  • Cero *ngIf / *ngFor en plantillas tocadas.
  • Componentes standalone (sin NgModule) con inject().
  • Tests, lint y build en verde.
  • Documentación de la lib actualizada.

Closes ticket #248 (tech-debt/front/auth/angular-21).

Eliminates the four custom structural directives that wrapped
TemplateRef + ViewContainerRef:
  - *appHasPermission
  - *appHasAnyPermission
  - *appHasAllPermissions
  - *appIfLoggedIn

and migrates every consumer to Angular 21's native control flow
(`@if`), which is type-safe, lives in the template language (no
imports), and closes the family of bugs caused when the directive's
@input() name didn't match its structural selector (real incident in
the sibling devia-saas repo: an "Admin panel" button never rendered
for ADMIN users because the input was `hasPermission` while the
selector desugars to `[appHasPermission]`).

Changes:
- AuthService gains a template-friendly `isLoggedIn()` helper that
  reads the `token` signal so `@if` re-evaluates automatically.
- The single consumer (home.component) now uses
  `@if (auth.isLoggedIn()) { … } @else { … }` and exposes `auth` as
  a public injected member. Component becomes OnPush and drops the
  CommonModule import (no longer needed).
- 4 directives + 4 specs + the directives barrel `index.ts` are
  deleted. The libs/auth root barrel no longer re-exports them.
- README.md and USAGE.md under libs/auth/directives rewritten as a
  before/after migration guide so derived projects can replay the
  refactor mechanically.

Verification:
- npm run test:front → 63 / 63 passing (the 31 directive-spec tests
  removed along with the directives themselves).
- npx nx run front:lint → clean.
- npx nx run front:build (development) → succeeds.
- No remaining occurrences of the four directive selectors in
  application code; surviving references live only inside the
  migration docs as historical examples.

Breaking change: any external consumer of the lib that still imports
HasPermissionDirective / HasAnyPermissionDirective /
HasAllPermissionsDirective / IfLoggedInDirective will need to follow
the table in directives/USAGE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dherrero dherrero merged commit ca2d23a into main May 19, 2026
@dherrero dherrero deleted the refactor/front-auth-directives-control-flow branch May 19, 2026 07:50
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