Skip to content

skills management parity: bring admin skills UI to feature parity with the NestJS reference #60

@mpge

Description

@mpge

Goal

Mirror the canonical admin Skills management contract on this plugin so the shared @escalated-dev/escalated Admin → Skills UI works against it end-to-end.

Canonical contract: escalated-developer-context — domain-model/skills-management.md
ADR: 2026-05-13 — Skills routing uses explicit tag/department mapping
Reference implementation: escalated-nestjs PR #45 (merged)
Frontend the contract must satisfy: escalated PR #65 (merged)

Checklist

Database

  • Migration: escalated_skill_routing_tags (id, skill_id FK cascade, tag_id FK cascade, unique(skill_id, tag_id))
  • Migration: escalated_skill_routing_departments (id, skill_id FK cascade, department_id FK cascade, unique(skill_id, department_id))
  • Migration on escalated_agent_skills: ensure columns id, user_id (FK to host User), skill_id (FK cascade), proficiency smallint default 3, timestamps, unique(user_id, skill_id). If the table currently uses agent_profile_id, rename via backfill from agent_profiles.user_id.

Models / entities

  • Skill model exposes routingTags, routingDepartments, agentSkills relations + updated_at.
  • New AgentSkill / SkillAgent / equivalent junction model with proficiency.
  • If the host's AgentProfile (or User) had a direct skills many-to-many on the old join table, replace with a relation through AgentSkill.

Routes + Controller

  • Admin controller exposes 6 actions matching escalated.admin.skills.{index, create, store, edit, update, destroy}.
  • index payload: { skills: [{ id, name, agents_count, routing_tags_count, routing_departments_count, updated_at }] }.
  • create / edit payload includes availableAgents, availableTags, availableDepartments, plus (on edit) a skill object with routing_tag_ids, routing_department_ids, agents: [{user_id, proficiency}].
  • store / update body accepts {name, routing_tag_ids[], routing_department_ids[], agents: [{user_id, proficiency 1..5}]}.
  • Inertia render targets: Escalated/Admin/Skills/Index and Escalated/Admin/Skills/Form.

Service

  • SkillService (or equivalent) implements listForAdmin, findForEdit, getFormContext, create, update, delete with relation sync.
  • SkillRoutingService.findMatchingAgents(ticket) uses the new explicit mapping (tags overlap OR department membership), not name-match. Ordering: sum of proficiency desc, then existing capacity.

UI wire-up

  • Admin sidebar link added (or confirmed present) pointing at route('escalated.admin.skills.index').

Tests

  • Controller / feature tests covering index, store, edit-context, update, destroy round-trips.
  • Service-level tests for relation sync and proficiency persistence.
  • Routing service test asserting an agent is matched via a routing tag, not via skill-name == tag-name.

Verification

  • All host tests green locally.
  • Sidebar → admin Skills index renders.
  • Form save → reload preserves routing tags, departments, and agent proficiencies.

Notes

This plugin is not Kimi-permitted per the portfolio Kimi policy. Dispatch via Codex or Cursor.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions