schema: spec-driven
id: admin-filament-mysql
version: 1.0.0
name: "Admin Laravel + Filament (MySQL)"
description: "Especificación funcional y técnica para un panel admin con Laravel 11, Filament v3, Spatie Permission y módulos dinámicos."

context:
  date: "2026-01-31"
  stack:
    framework: "Laravel 11"
    admin_panel: "FilamentPHP v3"
    auth: "Spatie Permission"
    database: "MySQL"

objectives:
  - "Proveer un admin seguro con login y dashboard."
  - "Administrar usuarios con estado activo/inactivo."
  - "Definir roles y permisos con Spatie Permission."
  - "Asignar roles a usuarios con efecto inmediato."
  - "Registrar módulos dinámicos en base de datos y mostrarlos como vistas vacías."

functional_requirements:
  authentication:
    description: "Inicio de sesión mediante credenciales seguras y acceso restringido a usuarios activos."
    acceptance_criteria:
      - "Acceso solo mediante inicio de sesión válido."
      - "Usuarios inactivos no pueden iniciar sesión."
      - "Credenciales seguras (hashing bcrypt/argon2)."
    filament:
      login_page: true
      protected_panel: true

  dashboard:
    description: "Dashboard principal con widgets base y accesos rápidos."
    acceptance_criteria:
      - "Visible solo a usuarios autenticados."
      - "Muestra accesos a módulos disponibles según permisos."

  users_module:
    description: "CRUD de usuarios con estado activo/inactivo."
    user_story: "Como administrador, quiero crear, editar y desactivar usuarios del sistema, para controlar quién puede acceder a la plataforma."
    acceptance_criteria:
      - "Creación y mantenimiento de usuarios."
      - "Estado del usuario: activo / inactivo."
      - "Autenticación mediante credenciales seguras."
      - "Acceso solo mediante inicio de sesión válido."
    fields:
      - name: "name"
        type: "string"
        required: true
      - name: "email"
        type: "string"
        required: true
        unique: true
      - name: "password"
        type: "string"
        required_on_create: true
      - name: "is_active"
        type: "boolean"
        default: true
    rules:
      - "No permitir desactivar el último usuario con rol administrador."
      - "Email único a nivel global."
      - "Al desactivar usuario, se revocan sesiones activas."

  roles_permissions:
    description: "Gestión de roles y permisos con Spatie Permission."
    user_story: "Como administrador, quiero definir roles y permisos, para controlar el acceso a funcionalidades y datos del sistema."
    acceptance_criteria:
      - "Roles configurables: administrador, operador, tienda, logística y solo lectura."
      - "Todos los accesos se perfilan bajo permisos."
      - "Rol con visibilidad total de pedidos."
      - "Rol con visibilidad restringida a tiendas específicas."
    roles:
      - "administrador"
      - "operador"
      - "tienda"
      - "logística"
      - "solo lectura"
    permissions:
      - "users.view"
      - "users.create"
      - "users.update"
      - "users.deactivate"
      - "roles.view"
      - "roles.create"
      - "roles.update"
      - "roles.delete"
      - "modules.view"
      - "orders.view"
      - "picking.view"
      - "shipping.view"
      - "inventory.view"
    visibility_rules:
      total_orders:
        role: "administrador"
        rule: "Acceso total a pedidos"
      store_scoped_orders:
        role: "tienda"
        rule: "Acceso a pedidos solo de tiendas asociadas"

  role_assignment:
    description: "Asignación de uno o más roles a usuarios."
    user_story: "Como administrador, quiero asignar uno o más roles a los usuarios, para determinar sus capacidades dentro del sistema."
    acceptance_criteria:
      - "Asociación flexible entre usuarios y roles."
      - "Cambios de rol aplicados de forma inmediata."
      - "Validación de permisos al iniciar sesión y durante la navegación."
    rules:
      - "Un usuario puede tener múltiples roles."
      - "Los permisos efectivos son la unión de los roles asignados."
      - "Los cambios de rol invalidan cachés de permisos."

  dynamic_modules:
    description: "Registro de módulos creados por Artisan en base de datos y render de vistas vacías."
    acceptance_criteria:
      - "Los módulos se crean desde Artisan y se guardan en BD."
      - "El admin lista módulos disponibles según permisos."
      - "Las vistas iniciales son vacías con título: Ordenes, Picking, Envio, Inventario."
    placeholders:
      - "Ordenes"
      - "Picking"
      - "Envio"
      - "Inventario"

non_functional_requirements:
  security:
    - "Protección CSRF en formularios."
    - "Rate limiting en login."
    - "Auditoría básica de cambios críticos (usuarios/roles)."
  performance:
    - "Listados con paginación nativa de Filament."
  quality:
    - "Prácticas de Clean Code y separación de responsabilidades."

ui_spec:
  filament_resources:
    - name: "UserResource"
      capabilities: ["list", "create", "edit", "deactivate"]
    - name: "RoleResource"
      capabilities: ["list", "create", "edit", "delete"]
    - name: "ModuleResource"
      capabilities: ["list", "view"]
  pages:
    - name: "Dashboard"
      widgets: ["Resumen de usuarios activos", "Accesos rápidos a módulos"]
    - name: "Ordenes"
      type: "placeholder"
    - name: "Picking"
      type: "placeholder"
    - name: "Envio"
      type: "placeholder"
    - name: "Inventario"
      type: "placeholder"

entities:
  User:
    table: "users"
    fields:
      id: "bigint"
      name: "string"
      email: "string"
      password: "string"
      is_active: "boolean"
      created_at: "timestamp"
      updated_at: "timestamp"
    relations:
      roles: "many-to-many (spatie model_has_roles)"
  Role:
    table: "roles"
    fields:
      id: "bigint"
      name: "string"
      guard_name: "string"
  Permission:
    table: "permissions"
    fields:
      id: "bigint"
      name: "string"
      guard_name: "string"
  Module:
    table: "modules"
    fields:
      id: "bigint"
      name: "string"
      slug: "string"
      is_active: "boolean"
      created_at: "timestamp"
      updated_at: "timestamp"

seeders:
  roles_permissions:
    description: "Seeder para roles y permisos base."
    roles: ["administrador", "operador", "tienda", "logística", "solo lectura"]
    permissions: ["users.view", "users.create", "users.update", "users.deactivate", "roles.view", "roles.create", "roles.update", "roles.delete", "modules.view", "orders.view", "picking.view", "shipping.view", "inventory.view"]
  modules:
    description: "Seeder para módulos placeholder."
    modules: ["Ordenes", "Picking", "Envio", "Inventario"]

artisan_commands:
  - name: "module:create"
    description: "Crea módulos en BD con name, slug y is_active."

tests:
  unit:
    - name: "UserIsActiveScope"
      description: "Filtra usuarios activos en autenticación."
    - name: "RolePermissionUnion"
      description: "Valida unión de permisos por roles múltiples."
  feature:
    - name: "LoginDeniedForInactiveUser"
      description: "Impide login si is_active=false."
    - name: "AdminCanCreateUser"
      description: "Crea usuario desde Filament y asigna rol."
    - name: "RoleAssignmentImmediate"
      description: "Cambios de roles reflejan permisos en navegación."
    - name: "ModulesListedByPermission"
      description: "Solo muestra módulos con permiso correspondiente."

clean_code_guidelines:
  - "Acciones en clases dedicadas (Use Cases / Actions)."
  - "Validaciones en FormRequest o Resources de Filament."
  - "Políticas por recurso (UserPolicy, RolePolicy, ModulePolicy)."
  - "Evitar lógica de negocio en controladores."