Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add TrenzaCR/trenzaos-config --skill "trenza-hr"
Install specific skill from multi-skill repository
# Description
>
# SKILL.md
name: trenza-hr
description: >
Gestión de RRHH: empleados, nóminas, departamentos para TrenzaOS.
Trigger: Al trabajar con empleados, nóminas, departamentos, posiciones, o recursos humanos.
license: MIT
metadata:
author: trenza
version: "1.0"
TrenzaOS HR Skills
Purpose
Este skill enforce las reglas de negocio para gestión de recursos humanos.
⚠️ Reglas Críticas
- Datos de nómina son confidenciales
- Solo RRHH y admins pueden ver salarios
- No se puede eliminar empleados (soft delete)
Core Rules
1. Estructura de Empleados
CREATE TABLE employees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
-- Datos personales
user_id UUID REFERENCES users(id), -- Si tiene acceso al sistema
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
dni TEXT NOT NULL, -- Documento de identidad
email TEXT NOT NULL,
phone TEXT,
-- Dirección
address TEXT,
city TEXT,
state TEXT,
country TEXT,
-- Empleo
department_id UUID REFERENCES departments(id),
position_id UUID REFERENCES positions(id),
-- Fechas
hire_date DATE NOT NULL,
termination_date DATE,
-- Estado
status TEXT DEFAULT 'active', -- active, inactive, on_leave, terminated
-- Metadata
emergency_contact JSONB, -- { name, phone, relation }
bank_account JSONB, -- { bank, account } - encriptado
metadata JSONB DEFAULT '{}',
-- Auditoría
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- DNI único por tenant
CREATE UNIQUE INDEX idx_employees_dni_tenant ON employees(tenant_id, dni);
2. Departamentos
CREATE TABLE departments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
name TEXT NOT NULL,
code TEXT NOT NULL, -- HR, IT, SALES
description TEXT,
-- Jerarquía
parent_id UUID REFERENCES departments(id),
-- Manager
manager_id UUID REFERENCES employees(id),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
3. Posiciones
CREATE TABLE positions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
title TEXT NOT NULL,
code TEXT NOT NULL,
department_id UUID REFERENCES departments(id),
-- Salario
salary_min NUMERIC(12, 2),
salary_max NUMERIC(12, 2),
salary_currency TEXT DEFAULT 'EUR',
-- Tipo
employment_type TEXT DEFAULT 'full_time', -- full_time, part_time, contractor
-- Descripción
description TEXT,
requirements TEXT,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
4. Nóminas
CREATE TABLE payrolls (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
employee_id UUID NOT NULL REFERENCES employees(id),
-- Período
period_start DATE NOT NULL,
period_end DATE NOT NULL,
pay_date DATE NOT NULL,
-- Ingresos
base_salary NUMERIC(12, 2) NOT NULL,
overtime NUMERIC(12, 2) DEFAULT 0,
bonuses NUMERIC(12, 2) DEFAULT 0,
commissions NUMERIC(12, 2) DEFAULT 0,
other_income NUMERIC(12, 2) DEFAULT 0,
-- Deducciones
tax_withholding NUMERIC(12, 2) DEFAULT 0,
social_security NUMERIC(12, 2) DEFAULT 0,
health_insurance NUMERIC(12, 2) DEFAULT 0,
other_deductions NUMERIC(12, 2) DEFAULT 0,
-- Total
gross_pay NUMERIC(12, 2) NOT NULL,
net_pay NUMERIC(12, 2) NOT NULL,
-- Estado
status TEXT DEFAULT 'draft', -- draft, calculated, approved, paid
-- Metadata
metadata JSONB DEFAULT '{}',
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
5. Server Actions
// Crear empleado
const CreateEmployeeSchema = z.object({
firstName: z.string().min(1),
lastName: z.string().min(1),
dni: z.string().min(5),
email: z.string().email(),
phone: z.string().optional(),
departmentId: z.string().uuid().optional(),
positionId: z.string().uuid().optional(),
hireDate: z.string().datetime()
})
async function createEmployee(prevState, formData: FormData) {
const data = CreateEmployeeSchema.parse(Object.fromEntries(formData))
// Verificar DNI único
const existing = await db.query.employees.findFirst({
where: and(
eq(employees.tenantId, tenantId),
eq(employees.dni, data.dni)
)
})
if (existing) {
return { status: 'error', error_code: 'DUPLICATE_DNI' }
}
// Crear usuario en Auth si es necesario
// ... (crear cuenta de acceso)
const employee = await db.insert(employees).values({
tenantId,
...data,
status: 'active'
}).returning()
return { status: 'success', data: { employeeId: employee.id } }
}
6. Cálculo de Nómina
async function calculatePayroll(employeeId: string, periodStart: Date, periodEnd: Date) {
const employee = await getEmployee(employeeId)
const position = await getPosition(employee.positionId)
// Calcular días trabajados
const daysWorked = getWorkingDays(periodStart, periodEnd)
const dailyRate = position.salaryMax / 30 // Asumiendo 30 días
const baseSalary = dailyRate * daysWorked
// Deducciones (simplificado)
const taxRate = 0.21 // IRPF ejemplo
const taxWithholding = baseSalary * taxRate
const socialSecurity = baseSalary * 0.0635 // Contingencias comunes
const netPay = baseSalary - taxWithholding - socialSecurity
return {
periodStart,
periodEnd,
baseSalary,
taxWithholding,
socialSecurity,
grossPay: baseSalary,
netPay
}
}
7. Vacaciones
CREATE TABLE leaves (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
employee_id UUID NOT NULL REFERENCES employees(id),
-- Tipo
leave_type TEXT NOT NULL, -- vacation, sick, personal, maternity
-- Fechas
start_date DATE NOT NULL,
end_date DATE NOT NULL,
days_count INTEGER NOT NULL,
-- Estado
status TEXT DEFAULT 'pending', -- pending, approved, rejected
-- Notas
notes TEXT,
-- Aprobación
approved_by UUID REFERENCES users(id),
approved_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
HR Checklist
- [ ] ¿Eliminación de empleados es soft delete?
- [ ] ¿Datos de nómina son visibles solo para RRHH?
- [ ] ¿Tienes control de vacaciones?
- [ ] ¿El DNI es único por tenant?
- [ ] ¿Generas nóminas por período?
References
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.