Improvement Plan

Ecosistema completo para organización y gestión de contenido con interfaces espaciales

Security Library - Improvement Plan

Date: 2025-09-29 Library: @libs-core/security Status: Analysis Complete - Ready for Implementation Priority: High - Core security library


Executive Summary

The security library is well-structured and functional, but requires improvements to align with project standards defined in CLAUDE.md. This document outlines specific violations, technical debt, and a prioritized action plan.

Current State


Critical Violations (Must Fix)

1. Timer Usage - NO SETIMEOUTS Rule Violation

Location: libs/core/security/src/lib/auth/token.service.ts:116

// ❌ VIOLATION: Using timer for periodic checks
this.autoRefreshSubscription = timer(0, 30000) // verificar cada 30 segundos
  .pipe(
    filter(() => this.shouldRefresh()),
    switchMap(() => this.refreshAccessToken()),
    catchError((error) => {
      console.error('Error en auto-refresh:', error);
      return EMPTY;
    })
  )
  .subscribe();

Impact: Violates core principle "do not use setTimeouts"

Solution: Implement event-driven token refresh

Priority: 🔴 Critical


2. Console Usage - Missing LoggerService Integration

Locations: Multiple files use console.error/log instead of LoggerService

Files affected:

  1. token.service.ts:100
  2. token.service.ts:106
  3. token.service.ts:122
  4. token.service.ts:244
  5. token.service.ts:291
  6. token.service.ts:303
  7. auth.service.ts:182
  8. auth.service.ts:198
  9. auth.service.ts:209
  10. auth.service.ts:538
  11. auth.service.ts:601
  12. auth.service.ts:620
  13. auth.service.ts:642

Impact: Missing centralized logging, debugging, and monitoring capabilities

Solution:

Priority: 🔴 Critical


3. Promises Instead of RxJS

Location: libs/core/security/src/lib/utils/crypto.utils.ts

Problem: Functions encryptForStorage and decryptFromStorage use async/await with Promises

// ❌ VIOLATION: Using Promises
export async function encryptForStorage(
  data: string,
  password: string
): Promise<{ encrypted: string; salt: string; iv: string }> {
  // ... async/await code
}

Impact: Violates "Always use rxJS, never use promises"

Solution: Convert to Observable-based API

export function encryptForStorage(
  data: string,
  password: string
): Observable<{ encrypted: string; salt: string; iv: string }> {
  return from(performEncryption(data, password));
}

Priority: 🔴 Critical


High Priority Issues

4. Test Failures - CSRFTokenService Injection

Test Results:

❌ CSRFTokenService > token management > should get token for specific tenant
   → NG0203: The `LoggerService2` token injection failed. inject() must be called from an injection context

❌ CSRFTokenService > token management > should clear all tokens
   → NG0203: The `LoggerService2` token injection failed. inject() must be called from an injection context

❌ CSRFTokenService > token management > should clear token for specific tenant
   → NG0203: The `LoggerService2` token injection failed. inject() must be called from an injection context

Root Cause: CSRFTokenService tries to inject LoggerService outside of Angular injection context

Solution:

Priority: 🟡 High


5. Missing Input/Output Signal Usage

Current State: Most directives still use @Input() and @Output() decorators

Affected Files:

Solution: Migrate to Angular 20 signal inputs/outputs

// ❌ Current
@Input() permission!: string;
@Output() accessDenied = new EventEmitter<void>();

// ✅ Preferred
permission = input.required<string>();
accessDenied = output<void>();

Priority: 🟡 High


Medium Priority Improvements

6. Enhance SOLID Principles

Single Responsibility Violations:

AuthService (883 lines) handles too many responsibilities:

Recommendation: Split into smaller, focused services:

Priority: 🟠 Medium


7. Improve Error Handling

Current Issues:

Example:

// ❌ Current
catch (error) {
  console.error('Error inicializando tokens:', error);
  return this.clearTokens();
}

// ✅ Improved
catch (error) {
  this.logger.error('Token initialization failed', {
    error,
    operation: 'token_init',
    tenantId: this.contextService.getCurrentTenantId(),
    correlationId: this.generateCorrelationId()
  });

  throw new TokenInitializationError(
    'Failed to initialize authentication tokens',
    { cause: error, recoverable: true }
  );
}

Priority: 🟠 Medium


8. Add Performance Decorators

Current State: No performance monitoring on critical methods

Solution: Use @performance decorator from log-system

@performance({ threshold: 100, level: 'warn' })
login(credentials: LoginCredentials): Observable<LoginResult> {
  // ...
}

@performance({ threshold: 50 })
refreshAuthentication(): Observable<void> {
  // ...
}

Priority: 🟠 Medium


9. Improve Change Detection Strategy

Current State: Not all directives explicitly declare OnPush

Solution: Ensure all directives use OnPush

@Directive({
  selector: '[hasPermission]',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush // Add this
})

Priority: 🟠 Medium


Low Priority Enhancements

10. Documentation Improvements

Missing Documentation:

Priority: 🟢 Low


11. Add More Unit Tests

Current Coverage: Good, but could be improved

Areas needing more tests:

Priority: 🟢 Low


12. TypeScript Strict Mode Compliance

Current Issues: Some any types still exist

Solution: Replace with proper types or SafeAny from utilities

Priority: 🟢 Low


Implementation Roadmap

Phase 1: Critical Fixes (Week 1)

Goal: Fix all critical violations

  1. ✅ Create improvement plan document
  2. ⬜ Remove timer-based auto-refresh in TokenService
  3. ⬜ Replace all console.* with LoggerService
  4. ⬜ Convert crypto.utils Promises to Observables
  5. ⬜ Fix CSRFTokenService test failures
  6. ⬜ Run full test suite and ensure all pass

Success Criteria:


Phase 2: High Priority Improvements (Week 2)

Goal: Modernize to Angular 20 standards

  1. ⬜ Migrate directives to signal inputs/outputs
  2. ⬜ Add @performance decorators to critical methods
  3. ⬜ Improve error handling with proper error classes
  4. ⬜ Enhance logging with correlation IDs
  5. ⬜ Add OnPush change detection to all directives

Success Criteria:


Phase 3: Architecture Improvements (Week 3)

Goal: Enhance SOLID principles and maintainability

  1. ⬜ Evaluate AuthService split (SRP)
  2. ⬜ Implement extracted services if needed
  3. ⬜ Add integration tests for complex flows
  4. ⬜ Document authentication flows
  5. ⬜ Add architectural decision records (ADRs)

Success Criteria:


Phase 4: Polish & Documentation (Week 4)

Goal: Complete documentation and add remaining tests

  1. ⬜ Complete API documentation
  2. ⬜ Add usage examples
  3. ⬜ Create migration guide (if breaking changes)
  4. ⬜ Add edge case tests
  5. ⬜ Final code review and cleanup

Success Criteria:


Risk Assessment

Breaking Changes Risk: Medium

Potential breaking changes:

Mitigation:

Performance Impact: Low

Changes unlikely to affect performance:

Testing Effort: Medium

Testing requirements:


Success Metrics

Code Quality

Architecture

Documentation


Dependencies & Coordination

Internal Dependencies

External Dependencies

Coordination Required


Next Steps

  1. Review this plan with team/stakeholders
  2. Prioritize items based on project timeline
  3. Create Nx tasks for each phase
  4. Start Phase 1 - Critical fixes
  5. Track progress using TodoWrite tool

Appendix A: File-by-File Analysis

Authentication Services

AuthService

TokenService

SessionService

Utilities

crypto.utils

jwt.utils

Interceptors

context.interceptor

csrf.interceptor

Directives

All directive files need:

Files:

Priority: High


Appendix B: Code Examples

Example 1: Token Refresh (Event-Driven)

Current (timer-based):

private setupAutoRefresh(): void {
  this.autoRefreshSubscription = timer(0, 30000) // ❌ Poll every 30 seconds
    .pipe(
      filter(() => this.shouldRefresh()),
      switchMap(() => this.refreshAccessToken()),
      catchError((error) => {
        console.error('Error en auto-refresh:', error);
        return EMPTY;
      })
    )
    .subscribe();
}

Proposed (event-driven):

private setupAutoRefresh(): void {
  // Calculate exact time to refresh
  const timeToRefresh$ = this.accessToken.pipe(
    filter(token => token !== null),
    map(token => {
      const expiryTime = getJWTTimeToExpiry(token!);
      const refreshTime = expiryTime * 0.8; // Refresh at 80% lifetime
      return Math.max(0, refreshTime * 1000);
    }),
    distinctUntilChanged()
  );

  // Schedule refresh at exact time
  this.autoRefreshSubscription = timeToRefresh$.pipe(
    switchMap(delayMs => timer(delayMs)),
    switchMap(() => this.refreshAccessToken()),
    tap(() => this.logger.debug('Token refreshed automatically', {
      operation: 'token_auto_refresh'
    })),
    catchError(error => {
      this.logger.error('Token auto-refresh failed', {
        error,
        operation: 'token_auto_refresh',
        recoverable: true
      });
      return EMPTY;
    }),
    repeat() // Restart the cycle after each refresh
  ).subscribe();
}

Example 2: LoggerService Integration

Current:

catch (error) {
  console.error('Error inicializando tokens:', error);
  return this.clearTokens();
}

Proposed:

catch (error) {
  this.logger.error('Token initialization failed', {
    error,
    operation: 'token_initialization',
    tenantId: this.contextService.getCurrentTenantId(),
    correlationId: this.sessionService.getCorrelationId(),
    recoverable: true
  });

  return this.clearTokens().pipe(
    tap(() => this.logger.info('Tokens cleared after initialization failure', {
      operation: 'token_cleanup'
    }))
  );
}

Example 3: Signal Inputs/Outputs

Current:

@Directive({
  selector: '[hasPermission]',
  standalone: true
})
export class HasPermissionDirective {
  @Input() permission!: string;
  @Output() accessDenied = new EventEmitter<void>();

  // ...
}

Proposed:

@Directive({
  selector: '[hasPermission]',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HasPermissionDirective {
  permission = input.required<string>();
  accessDenied = output<void>();

  // Computed signals for reactive logic
  hasAccess = computed(() =>
    this.authService.hasPermission(this.permission())
  );

  // ...
}

Appendix C: Testing Strategy

Unit Tests

Integration Tests

E2E Tests


Conclusion

The security library is fundamentally solid but requires targeted improvements to align with project standards. The most critical issues (timer usage, console logging, Promise usage) can be fixed within a week. Following the phased roadmap will result in a production-ready, maintainable, and standards-compliant security library.

Estimated Total Effort: 3-4 weeks Risk Level: Medium (some breaking changes possible) Business Value: High (core security improvements)


Document Version: 1.0 Last Updated: 2025-09-29 Next Review: After Phase 1 completion