Skip to main content
The Karma Ecommerce authentication system provides secure user login functionality using Angular’s reactive patterns and clean architecture principles.

Overview

The authentication feature follows the CQRS (Command Query Responsibility Segregation) pattern with a clear separation of concerns:
  • UI Layer: Login page component handles user interaction
  • Application Layer: Query handlers process login requests
  • Domain Layer: Repository abstraction defines contracts
  • Infrastructure Layer: AuthService implements API communication

Login Flow

1

User initiates login

The user clicks the login button, triggering the login() method with credentials.
2

Component calls repository

The LoginPage component invokes the UsuarioRepository’s loginUsuario() method.
3

API request sent

The AuthService makes an HTTP GET request to http://localhost:8080/login/{usuario}/{contrasena}.
4

Response handling

RxJS operators process the response and provide user feedback via alerts.

Component Implementation

The login page is located at ~/workspace/source/src/app/usuario/infrastructure/ui/pages/login-page/login-page.ts:1:
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../../services/auth-service';
import { tap } from 'rxjs';
import { UsuarioRepository } from '../../../../domain/repositories/usuario.repository';

@Component({
  selector: 'app-login-page',
  imports: [],
  templateUrl: './login-page.html',
  styleUrl: './login-page.css',
})
export class LoginPage implements OnInit {
  
  constructor(private authService: UsuarioRepository) {}

  ngOnInit(): void {}

  login(usuario: string, contrasena: string) {
    this.authService.loginUsuario(usuario, contrasena).pipe(tap(usuario => {
      console.log(usuario);
      usuario ? alert('usuario y contraseña correctos!') : alert('usuario o contraseña incorrectos');       
    })).subscribe();
  }
}

Template

The login template at ~/workspace/source/src/app/usuario/infrastructure/ui/pages/login-page/login-page.html:1:
<button (click)="login('jose', 'chivito3000ydash')">LOGIN</button>
Security Note: The current implementation hardcodes credentials in the template for demonstration purposes. In production, credentials should be captured via form inputs with proper validation.

CQRS Pattern: Query & Handler

Login Query

The LoginUserQuery encapsulates login request data at ~/workspace/source/src/app/usuario/application/queries/login-user.query.ts:1:
export class LoginUserQuery {
    constructor(readonly usuario: string, readonly contrasena: string) {}
}

Login Handler

The LoginUserHandler processes login queries at ~/workspace/source/src/app/usuario/application/usecases/queryHandlers/login-user.handler.ts:1:
import { Observable } from "rxjs";
import { UsuarioRepository } from "../../../domain/repositories/usuario.repository";
import { LoginUserQuery } from "../../queries/login-user.query";
import { Usuario } from "../../../domain/models/usuario";
import { Injectable } from "@angular/core";

@Injectable()
export class LoginUserHandler {

    constructor(private usuarioRepository: UsuarioRepository){}

    handle(query: LoginUserQuery): Observable<Usuario> {
        return this.usuarioRepository.loginUsuario(query.usuario, query.contrasena);
    }
}

Repository Pattern

Domain Repository Interface

The abstract repository defines the contract at ~/workspace/source/src/app/usuario/domain/repositories/usuario.repository.ts:1:
import { Observable } from "rxjs";
import { Usuario } from "../models/usuario";

export abstract class UsuarioRepository {
    abstract loginUsuario(usuario: string, contrasena: string): Observable<Usuario>;
    abstract registrarUsuario(usuario: string, contrasena: string): Observable<Usuario>;
}

AuthService Implementation

The concrete implementation at ~/workspace/source/src/app/usuario/infrastructure/services/auth-service.ts:1:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Usuario } from '../../domain/models/usuario';
import { UsuarioRepository } from '../../domain/repositories/usuario.repository';

@Injectable({
  providedIn: 'root',
})
export class AuthService implements UsuarioRepository {

  private readonly BASE_URL = 'http://localhost:8080/'
  constructor(private httpClient: HttpClient) { }

  loginUsuario(usuario: string, contrasena: string): Observable<Usuario> {
    return this.httpClient.get<Usuario>(this.BASE_URL + 'login' + '/' + usuario + '/' + contrasena);
  } 
  
  registrarUsuario(usuario: string, contrasena: string): Observable<Usuario> {
    const body = { usuario, contrasena };
    return this.httpClient.post<Usuario>(
      `${this.BASE_URL}registro`,
      body,
      { headers: { 'Content-Type': 'application/json' } }
    );
  }
}

API Integration

Login Endpoint

URL: http://localhost:8080/login/{usuario}/{contrasena}
Method: GET
Response: Usuario object
interface Usuario {
    id: number,
    usuario: string,
    contrasena: string
}

Request Example

curl http://localhost:8080/login/jose/chivito3000ydash

RxJS Response Handling

The authentication system uses RxJS operators for reactive programming:
  • tap: Side effects for logging and user feedback
  • subscribe: Triggers the observable execution
this.authService.loginUsuario(usuario, contrasena).pipe(
  tap(usuario => {
    console.log(usuario);
    usuario ? 
      alert('usuario y contraseña correctos!') : 
      alert('usuario o contraseña incorrectos');       
  })
).subscribe();
Important: The current implementation uses browser alerts for user feedback. Consider replacing with toast notifications or inline validation messages for better UX.

User Model

The Usuario interface defines the user entity at ~/workspace/source/src/app/usuario/domain/models/usuario.ts:1:
export interface Usuario {
    id: number,
    usuario: string,
    contrasena: string
}

Build docs developers (and LLMs) love