Skip to main content

Overview

The AdminService provides administrative functionality for managing the P.FLEX system. It acts as a facade over the StateService, providing CRUD operations for:
  • Users - Application user accounts with roles and credentials
  • Roles - Role definitions with permission sets
  • Machines - Production equipment registration and status
  • Configuration - Global system settings
All operations are automatically logged via AuditService. Location: src/features/admin/services/admin.service.ts Provider: Root (singleton) Dependencies: StateService, AuditService

User Management

users

Gets the users signal from StateService.
get users(): Signal<AppUser[]>
Returns: Signal containing all application users
import { inject } from '@angular/core';
import { AdminService } from './features/admin/services/admin.service';

const adminService = inject(AdminService);
const allUsers = adminService.users();

console.log('Total users:', allUsers.length);
allUsers.forEach(user => {
  console.log(`${user.name} (${user.username}) - ${user.role}`);
});

addAdminUser

Creates a new user account.
addAdminUser(user: Partial<AppUser>): void
user
Partial<AppUser>
required
User data to create. Only required fields need to be provided.
User Properties:
  • name - Full display name (default: ”)
  • username - Login username (default: ”)
  • role - User role (default: ‘Operario’)
  • active - Account status (default: true)
  • assignedAreas - Array of assigned production areas (default: [])
Behavior:
  • Generates unique ID automatically
  • Applies defaults for missing fields
  • Appends to users array
  • Logs creation event with username and role
const newUser: Partial<AppUser> = {
  name: 'Roberto Martinez',
  username: 'rmartinez',
  role: 'Supervisor',
  active: true,
  assignedAreas: ['Nave A', 'Nave B']
};

adminService.addAdminUser(newUser);

// User is now available
const users = adminService.users();
const created = users.find(u => u.username === 'rmartinez');
console.log('Created user:', created);

updateAdminUser

Updates an existing user’s information.
updateAdminUser(updatedUser: AppUser): void
updatedUser
AppUser
required
Complete user object with updated properties. Must have matching ID.
Behavior:
  • Finds user by ID and replaces with updated object
  • Logs modification event with username
const users = adminService.users();
const user = users.find(u => u.username === 'rmartinez');

if (user) {
  adminService.updateAdminUser({
    ...user,
    role: 'Jefatura',
    assignedAreas: [...user.assignedAreas, 'Nave C']
  });
}

deleteAdminUser

Removes a user account.
deleteAdminUser(id: string): void
id
string
required
User ID to delete.
Behavior:
  • Removes user from array by ID
  • Logs deletion event with username (or ID if user not found)
const users = adminService.users();
const userToDelete = users.find(u => u.username === 'rmartinez');

if (userToDelete) {
  adminService.deleteAdminUser(userToDelete.id);
  console.log('User deleted');
}

Role Management

roles

Gets the roles signal from StateService.
get roles(): Signal<RoleDefinition[]>
Returns: Signal containing all role definitions Default Roles:
  • Jefatura - Full access to reports, KPIs, and approvals
  • Supervisor - Shift management and task assignment
  • Operario - Production recording
  • Sistemas - Full system administration
const allRoles = adminService.roles();

allRoles.forEach(role => {
  console.log(`${role.name}: ${role.description}`);
  console.log('Permissions:', role.permissions.join(', '));
});

updateRole

Updates a role’s definition and permissions.
updateRole(updatedRole: RoleDefinition): void
updatedRole
RoleDefinition
required
Complete role object with updated properties. Must have matching ID.
RoleDefinition Properties:
  • id - Unique role identifier
  • name - Role name
  • description - Role description
  • permissions - Array of permission strings
const roles = adminService.roles();
const supervisorRole = roles.find(r => r.name === 'Supervisor');

if (supervisorRole) {
  adminService.updateRole({
    ...supervisorRole,
    permissions: [...supervisorRole.permissions, 'Gestionar Inventario']
  });
}

deleteRole

Removes a role definition.
deleteRole(id: string): void
id
string
required
Role ID to delete.
Warning: Deleting a role does not automatically update users assigned to that role.
const roles = adminService.roles();
const customRole = roles.find(r => r.name === 'Custom Role');

if (customRole) {
  adminService.deleteRole(customRole.id);
}

Machine Management

machines

Gets the machines signal from StateService.
get machines(): Signal<Machine[]>
Returns: Signal containing all registered machines Machine Types:
  • Impresión - Printing presses (9 machines: IMP-01 to IMP-09)
  • Troquelado - Die cutting machines (12 machines: TRQ-01 to TRQ-12)
  • Acabado - Finishing equipment (13 machines: RBB-01 to RBB-13)
const allMachines = adminService.machines();

// Filter by type
const printingMachines = allMachines.filter(m => m.type === 'Impresión');
console.log('Printing machines:', printingMachines.length);

// Filter by status
const inMaintenance = allMachines.filter(m => m.status === 'Mantenimiento');
console.log('In maintenance:', inMaintenance.length);

// Group by area
const byArea = allMachines.reduce((acc, m) => {
  acc[m.area] = (acc[m.area] || 0) + 1;
  return acc;
}, {} as Record<string, number>);
console.log('Machines by area:', byArea);

addMachine

Registers a new machine.
addMachine(machine: Partial<Machine>): void
machine
Partial<Machine>
required
Machine data to register.
Machine Properties:
  • code - Machine code (e.g., ‘IMP-10’) (default: ”)
  • name - Machine name (default: ”)
  • type - Machine type: ‘Impresión’, ‘Troquelado’, ‘Acabado’ (default: ‘Impresión’)
  • area - Physical location (default: ”)
  • status - Current status: ‘Operativa’, ‘Mantenimiento’, ‘Detenida’, ‘Sin Operador’ (default: ‘Operativa’)
  • active - Active flag (default: true)
const newMachine: Partial<Machine> = {
  code: 'IMP-10',
  name: 'SUPERFLEX 300',
  type: 'Impresión',
  area: 'Nave A',
  status: 'Operativa',
  active: true
};

adminService.addMachine(newMachine);

// Machine is now available
const machines = adminService.machines();
const created = machines.find(m => m.code === 'IMP-10');
console.log('Registered:', created?.name);

updateMachine

Updates a machine’s information or status.
updateMachine(updatedMachine: Machine): void
updatedMachine
Machine
required
Complete machine object with updated properties. Must have matching ID.
Behavior:
  • Finds machine by ID and replaces with updated object
  • Logs modification event with machine name and status
const machines = adminService.machines();
const machine = machines.find(m => m.code === 'IMP-01');

if (machine) {
  // Update status to maintenance
  adminService.updateMachine({
    ...machine,
    status: 'Mantenimiento'
  });
  
  console.log(`${machine.name} set to maintenance`);
}

deleteMachine

Removes a machine from the registry.
deleteMachine(id: string): void
id
string
required
Machine ID to delete.
const machines = adminService.machines();
const machineToRemove = machines.find(m => m.code === 'IMP-10');

if (machineToRemove) {
  adminService.deleteMachine(machineToRemove.id);
  console.log('Machine removed from registry');
}

Configuration Management

config

Gets the system configuration signal from StateService.
get config(): Signal<SystemConfig>
Returns: Signal containing global system configuration SystemConfig Properties:
  • shiftName1 - Name of first shift (default: ‘Turno Día’)
  • shiftTime1 - Start time of first shift (default: ‘06:00’)
  • shiftName2 - Name of second shift (default: ‘Turno Noche’)
  • shiftTime2 - Start time of second shift (default: ‘18:00’)
  • passwordExpiryWarningDays - Days before password expiry warning (default: 15)
  • passwordPolicyDays - Password expiration period (default: 90)
  • plantName - Factory name (default: ‘Planta Central - Zona Industrial’)
  • autoLogoutMinutes - Auto-logout timeout (default: 30)
  • operatorMessage - Message displayed to operators
const config = adminService.config();

console.log('Plant:', config.plantName);
console.log('Shifts:');
console.log(`  ${config.shiftName1}: ${config.shiftTime1}`);
console.log(`  ${config.shiftName2}: ${config.shiftTime2}`);
console.log('Security:');
console.log(`  Password policy: ${config.passwordPolicyDays} days`);
console.log(`  Auto-logout: ${config.autoLogoutMinutes} minutes`);

updateConfig

Updates the global system configuration.
updateConfig(newConfig: SystemConfig): void
newConfig
SystemConfig
required
Complete configuration object with all properties.
Behavior:
  • Replaces entire configuration object
  • Logs configuration update event
const currentConfig = adminService.config();

const updatedConfig: SystemConfig = {
  ...currentConfig,
  shiftName1: 'Turno Mañana',
  shiftTime1: '07:00',
  shiftName2: 'Turno Tarde',
  shiftTime2: '19:00',
  autoLogoutMinutes: 45,
  operatorMessage: 'Recordar registrar todas las paradas en el sistema.'
};

adminService.updateConfig(updatedConfig);
console.log('Configuration updated');

Complete Admin Panel Example

import { Component, inject, signal } from '@angular/core';
import { AdminService } from './features/admin/services/admin.service';
import { AppUser, Machine, RoleDefinition, SystemConfig } from './features/admin/models/admin.models';

@Component({
  selector: 'app-admin-panel',
  template: `
    <div class="admin-panel">
      <h1>Panel de Administración</h1>
      
      <!-- Users Section -->
      <section class="admin-section">
        <h2>Usuarios ({{ adminService.users().length }})</h2>
        <button (click)="showAddUserDialog()">Agregar Usuario</button>
        
        <table>
          <thead>
            <tr>
              <th>Nombre</th>
              <th>Usuario</th>
              <th>Rol</th>
              <th>Estado</th>
              <th>Acciones</th>
            </tr>
          </thead>
          <tbody>
            @for (user of adminService.users(); track user.id) {
              <tr>
                <td>{{ user.name }}</td>
                <td>{{ user.username }}</td>
                <td>{{ user.role }}</td>
                <td>{{ user.active ? 'Activo' : 'Inactivo' }}</td>
                <td>
                  <button (click)="editUser(user)">Editar</button>
                  <button (click)="deleteUser(user.id)">Eliminar</button>
                </td>
              </tr>
            }
          </tbody>
        </table>
      </section>
      
      <!-- Machines Section -->
      <section class="admin-section">
        <h2>Máquinas ({{ adminService.machines().length }})</h2>
        <button (click)="showAddMachineDialog()">Agregar Máquina</button>
        
        <div class="machine-filters">
          <button (click)="filterMachines('all')">Todas</button>
          <button (click)="filterMachines('Impresión')">Impresión</button>
          <button (click)="filterMachines('Troquelado')">Troquelado</button>
          <button (click)="filterMachines('Acabado')">Acabado</button>
        </div>
        
        <div class="machines-grid">
          @for (machine of filteredMachines(); track machine.id) {
            <div class="machine-card" [class.inactive]="!machine.active">
              <h3>{{ machine.name }}</h3>
              <p>{{ machine.code }}</p>
              <p>Tipo: {{ machine.type }}</p>
              <p>Área: {{ machine.area }}</p>
              <p>Estado: <span [class]="'status-' + machine.status">{{ machine.status }}</span></p>
              <button (click)="editMachine(machine)">Editar</button>
            </div>
          }
        </div>
      </section>
      
      <!-- Configuration Section -->
      <section class="admin-section">
        <h2>Configuración del Sistema</h2>
        <button (click)="editConfig()">Modificar Configuración</button>
        
        <div class="config-display">
          <h3>{{ adminService.config().plantName }}</h3>
          
          <div class="config-group">
            <h4>Turnos</h4>
            <p>{{ adminService.config().shiftName1 }}: {{ adminService.config().shiftTime1 }}</p>
            <p>{{ adminService.config().shiftName2 }}: {{ adminService.config().shiftTime2 }}</p>
          </div>
          
          <div class="config-group">
            <h4>Seguridad</h4>
            <p>Política de contraseñas: {{ adminService.config().passwordPolicyDays }} días</p>
            <p>Aviso de expiración: {{ adminService.config().passwordExpiryWarningDays }} días</p>
            <p>Auto-logout: {{ adminService.config().autoLogoutMinutes }} minutos</p>
          </div>
          
          <div class="config-group">
            <h4>Mensaje para Operadores</h4>
            <p>{{ adminService.config().operatorMessage }}</p>
          </div>
        </div>
      </section>
    </div>
  `
})
export class AdminPanelComponent {
  adminService = inject(AdminService);
  
  filteredMachines = signal<Machine[]>([]);
  
  constructor() {
    this.filteredMachines.set(this.adminService.machines());
  }
  
  filterMachines(type: string) {
    if (type === 'all') {
      this.filteredMachines.set(this.adminService.machines());
    } else {
      this.filteredMachines.set(
        this.adminService.machines().filter(m => m.type === type)
      );
    }
  }
  
  showAddUserDialog() {
    // Open dialog to add user
  }
  
  editUser(user: AppUser) {
    // Open dialog to edit user
  }
  
  deleteUser(id: string) {
    if (confirm('¿Eliminar usuario?')) {
      this.adminService.deleteAdminUser(id);
    }
  }
  
  showAddMachineDialog() {
    // Open dialog to add machine
  }
  
  editMachine(machine: Machine) {
    // Open dialog to edit machine
  }
  
  editConfig() {
    // Open dialog to edit configuration
  }
}

Audit Integration

All AdminService operations automatically create audit log entries: User Operations:
  • Module: ‘ADMIN’
  • Actions: ‘Crear Usuario’, ‘Editar Usuario’, ‘Eliminar Usuario’
Role Operations:
  • Module: ‘ADMIN’
  • Actions: ‘Actualizar Rol’, ‘Eliminar Rol’
Machine Operations:
  • Module: ‘ADMIN’
  • Actions: ‘Crear Máquina’, ‘Actualizar Máquina’, ‘Eliminar Máquina’
Configuration Operations:
  • Module: ‘ADMIN’
  • Action: ‘Configuración’
Audit logs include:
  • Current user name and role (from StateService)
  • Timestamp
  • Simulated IP address
  • Detailed description with affected entity identifiers

Notes

  • AdminService is a facade over StateService for administrative operations
  • All signals are managed by StateService
  • Default data includes 4 users, 4 roles, and 34 machines
  • Machine registry covers all production areas (Nave A, B, C, D)
  • Role permissions are stored as string arrays for flexibility
  • No actual authentication/authorization is enforced - implement guards in production
  • All delete operations are immediate - implement soft deletes for production

Build docs developers (and LLMs) love