Core HR (HRCORE) — PRD+FSD Hybrid¶
Module Code: HRCORE Product: [BOTH] (Papillon HR Suite + ALTARYS ENTERPRISE HR Suite) Country Scope: CI (Côte d'Ivoire) — MVP Version: 1.0 Date: 01/03/2026 Author: ANALYST (Claude Code) Input documents: - docs/prd/platform-vision-prd.md (Platform Vision PRD) - docs/specs/platform-vision.md (Tier 1 human-written spec) - docs/research/3_validated/core-hr-legal-validated.md (legal research — validated) - docs/research/2_audit/core-hr-legal-audit.md (legal audit — gaps)
PART A — Product Requirements (PRD)¶
A.1 Executive Summary¶
The Problem¶
Businesses in Côte d'Ivoire must maintain a dossier du personnel (employee file) for every employee, per the Code du Travail 2015 (Loi n°2015-532) and the employer register obligations. Most SMEs manage this with paper folders, Excel spreadsheets, or WhatsApp photos of documents. This creates:
- Compliance risk: Missing mandatory documents (medical certificates, CNPS attestations, identity copies) discovered only during labor inspections.
- Data fragility: Employee files scattered across physical folders, USB drives, and multiple Excel files — no single source of truth.
- Operational inefficiency: HR managers spend hours searching for employee information, manually generating registers, and responding to employee requests for certificates or profile information.
- Privacy risk: Sensitive personal data (national ID numbers, bank information, medical records) stored in unprotected files without audit trails or access controls.
The Solution¶
Core HR (HRCORE) is the enriched employee data layer that transforms the Control Plane's baseline employee record into a complete, compliant, and searchable dossier du personnel. It is:
- A data enrichment module: Layer 2 on top of the Control Plane's baseline employee entity (Layer 1). It adds personal data, bank information, emergency contacts, photos, documents, and dependents management.
- NOT a process module: Contract lifecycle management, onboarding/offboarding workflows, administrative events, declarations, trial period tracking, and termination procedures belong to Employee Management (EMPMGT). Core HR is the data, EMPMGT is the process.
- An optional sellable module: Tenants without Core HR use the Control Plane baseline, which is sufficient for Absence, Attendance, and Payroll. Core HR enriches the employee record for compliance, reporting, and a richer user experience.
Module Position in the Platform¶
Control Plane (Layer 1 — always present)
└── Baseline employee: last_name, first_name, email, phone,
employee_number, contract_type, org_unit, position,
category, hire_date, status, preferred_contact
↓ Sufficient for Absence, Attendance, Payroll
Core HR (Layer 2 — optional, sellable)
└── Enriched employee: date_of_birth, nationality, national_id,
cnps_number, marital_status, dependents[], bank_info,
emergency_contacts[], photo, documents[], address,
gender, blood_type, place_of_birth, parents, qualifications,
previous_employer, change_history_view
↓ Complete "dossier du personnel"
Employee Management (Layer 3 — optional, sellable)
└── Process layer: onboarding, offboarding, contract lifecycle,
trial period tracking, administrative events, declarations
↓ "Actes administratifs"
Key Correction from Platform Vision¶
⚠️ CORRECTION: The Platform Vision PRD Layer 1 defines full_name as a single field. This PRD corrects this to last_name + first_name as separate fields at the Control Plane level. full_name becomes a computed display value. This is a fundamental data modeling correction — West African naming conventions require separate name fields for:
- Legal documents (registre du personnel, CNPS declarations)
- Formal display conventions (NOM Prénoms format: KOUASSI Jean-Pierre)
- Search (search by last name or first name independently)
This correction must be propagated to the Control Plane PRD.
A.2 User Personas¶
P2: Responsable RH / HR Manager — [BOTH]¶
- Primary user of Core HR
- Uses: Creates and enriches employee profiles, manages documents, generates registre du personnel, manages bank info, responds to employee data requests
- Key concern: "Complete employee files, find information quickly, be ready for inspections."
- Papillon context: Often a single person (DG's spouse, trusted assistant) managing 5-50 employee files. Transitioning from paper/Excel. Needs simplicity and guidance — e.g., visual indicators of which employee files are incomplete.
- Enterprise context: Professional HR officer managing hundreds of profiles. Needs bulk operations and efficient data entry. (Note: Core HR is [BOTH] with no brand differentiation for V1.)
P1: Directeur Général (DG) / CEO — [BOTH]¶
- Secondary user
- Uses: Views employee profiles, approves nothing in Core HR (approval workflows are in EMPMGT), accesses dashboards and statistics
- Papillon context: In very small businesses (S1-S2), the DG IS the HR Manager — same person wearing both hats.
P4: Employé / Employee — [BOTH]¶
- Self-service user
- Uses: Views own profile (enriched when HR Core is active), updates personal contact info (phone, email, address), manages emergency contacts, uploads/updates photo
- Key concern: "See my information, update my phone number, check that my CNPS number is correct."
- Papillon context: Low digital literacy, Android phone, intermittent connectivity. Needs absolute simplicity.
P3: Comptable / Accountant — [BOTH]¶
- Read-only financial user
- Uses: Reads employee financial data (bank info, employee category) for payroll/accounting reconciliation
- Key concern: "Verify bank details match payroll records."
- Does NOT: Edit employee profiles, access personal data (national ID, medical docs)
P-MGR: Manager (N+1) — [BOTH]¶
- Read-only team user
- Uses: Views profiles of direct reports (employees in their org unit). Read-only access.
- Key concern: "Know my team members' key information without going through HR."
A.3 User Stories¶
US-HRCORE-001: Enriched Employee Profile [BOTH]¶
As an HR Manager, I want to enrich an employee's profile with personal data, emergency contacts, bank information, photo, and documents, So that I maintain a complete and compliant dossier du personnel.
Acceptance Criteria:
- Given I have HRCORE module active and HR Manager role, When I open an employee's profile, Then I see all Layer 2 fields available for editing.
- Given I fill in all mandatory HR Core fields, When I save the profile, Then the system logs the changes in the audit trail and publishes an EmployeeUpdated event.
- Given I leave the CNPS number field empty, When I save, Then the system saves successfully but creates a persistent alert reminding me to register the employee with CNPS.
US-HRCORE-002: Employee Self-Service Profile View [BOTH]¶
As an employee, I want to view my complete profile (personal data, bank info summary, emergency contacts, documents), So that I can verify my information is correct and up to date.
Acceptance Criteria: - Given I am an employee with an active account and HR Core is active for my tenant, When I navigate to "Mon Profil", Then I see my enriched profile with all Layer 2 data. - Given I view my bank info, Then I see only the last 4 digits of my account number (masked display). - Given I am offline, When I view my profile, Then I see the cached version from my last online access.
US-HRCORE-003: Employee Self-Service Edit [BOTH]¶
As an employee, I want to update my phone number, personal email, address, emergency contacts, and photo, So that my information stays current without waiting for HR.
Acceptance Criteria:
- Given I am an employee, When I edit my phone number and save, Then the change takes effect immediately (no approval needed) and an EmployeeUpdated event is published.
- Given I am offline, When I edit my address and save, Then the change is queued in IndexedDB and synced when connectivity returns within 30s.
- Given I try to edit my national ID number, Then the field is read-only and I see a message: "Contactez les RH pour modifier cette information."
US-HRCORE-004: Bank Info Management [BOTH]¶
As an HR Manager, I want to manage employee bank account information (bank name, account number, IBAN/RIB), So that Payroll can process salary payments correctly (post-MVP).
Acceptance Criteria:
- Given I have HR Manager or DG role, When I update an employee's bank info, Then the change is logged in audit trail and an EmployeeBankInfoChanged event is published.
- Given I am an employee, When I try to edit my bank info, Then the field is read-only.
- Given I am a Comptable, When I view an employee's bank info, Then I see the full bank details (read-only).
US-HRCORE-005: Document Attachment with Taxonomy [BOTH]¶
As an HR Manager, I want to attach documents to an employee's profile with structured categories (contract, medical certificate, identity, CNPS attestation, etc.), So that I can organize and find documents easily and track file completeness.
Acceptance Criteria: - Given I upload a document, When I select a category from the dropdown, Then the document is stored in MinIO with the category metadata. - Given the system has seeded categories, When I need a category not in the list, Then I can contact the DG/admin to add a custom category (V1: admin-managed; V2: inline creation). - Given I view an employee's documents tab, When I filter by category, Then I see only documents of that category.
US-HRCORE-006: Fulltext Employee Search [BOTH]¶
As an HR Manager, I want a single search field that searches across employee names and configurable fields using PostgreSQL fulltext search, So that I can find any employee quickly without navigating complex filter forms.
Acceptance Criteria:
- Given I type "Kouassi" in the search field, When I press Enter, Then I see all employees whose last_name or first_name match "Kouassi".
- Given I type "Comptabilité" in the search field, When I press Enter, Then I see all employees in the Comptabilité department (department is a default search field).
- Given I am a DG/RH Manager, When I go to search configuration, Then I can add or remove fields from the fulltext search index (e.g., add cnps_number or national_id_number).
US-HRCORE-007: Bulk Employee Import [BOTH]¶
As an HR Manager or DG, I want to bulk-import employees via Excel with HR Core enrichment fields included, So that I can migrate our existing employee data quickly instead of entering profiles one by one.
Acceptance Criteria: - Given HR Core is active, When I download the import template, Then it includes all Layer 1 (CP) fields + Layer 2 (HR Core) enrichment fields. - Given I upload a filled Excel file, When the system parses it, Then I see an editable confirmation table with validation errors highlighted (e.g., duplicate employee numbers, invalid CNPS format). - Given some HR Core fields are left blank in the import, When I submit, Then the employees are created with whatever data is provided — no validation failure on empty optional HR Core fields.
US-HRCORE-008: Registre du Personnel Export (Fascicule 1) [BOTH]¶
As an HR Manager, I want to export the registre du personnel (Fascicule 1 — personnel data) as a compliant PDF or Excel document, So that I am ready for labor inspections and CNPS audits.
Acceptance Criteria: - Given I click "Exporter Registre du Personnel", When the export is generated, Then it contains all active and terminated employees with the legally required fields (sequential registration number, full name, date of birth, nationality, position, category, hire date, CNPS number, etc.). - Given an employee's CNPS number is missing, When the export is generated, Then the field shows "Non renseigné" and the export includes a warning summary of incomplete records.
US-HRCORE-009: Employee Photo Management [BOTH]¶
As an HR Manager or Employee (self-service), I want to upload and crop an employee photo for their profile, So that the employee is visually identifiable in the platform and for ID badges.
Acceptance Criteria: - Given I upload a photo, When I reach the crop step, Then I see a crop tool enforcing 3:4 portrait aspect ratio. - Given I confirm the crop, Then the system generates a thumbnail (48px for list views) and a medium version (150px for profile card), stored in MinIO. - Given the photo exceeds 2 MB, When I upload, Then I see an error: "La photo ne doit pas dépasser 2 Mo."
US-HRCORE-010: Dependents Management [BOTH]¶
As an HR Manager, I want to manage a detailed list of employee dependents (spouse, children, other persons à charge) with their personal information, So that Payroll can correctly calculate tax deductions (ITS) and social contributions (allocations familiales CNPS).
Acceptance Criteria:
- Given I add a dependent, When I fill in name, date_of_birth, relationship (conjoint(e), enfant, autre personne à charge), gender, Then the dependent is saved and dependents_count and number_of_children are automatically recomputed.
- Given I mark a child dependent as "scolarisé" and attach a school attestation, Then the school_attestation_attached flag is set to true.
- Given I delete a dependent, Then the counts are recomputed and the change is logged in the audit trail.
US-HRCORE-011: Change History View [BOTH]¶
As an HR Manager, I want to see a human-readable timeline of changes made to an employee's profile, So that I can trace who changed what and when for audit and compliance purposes.
Acceptance Criteria: - Given I open an employee's "Historique des modifications" tab, When I view it, Then I see a chronological list of changes with: date, user who made the change, field name (in French), old value, new value. - Given the change history is sourced from the platform audit trail (AuditEntry), When I view it, Then the raw audit data is translated into a user-friendly French format.
US-HRCORE-012: Missing Data Alerts [BOTH]¶
As an HR Manager, I want the system to alert me when employee profiles are missing critical information (CNPS number, medical certificate, identity document), So that I can proactively complete files before inspections or audits.
Acceptance Criteria: - Given an employee's CNPS number is empty, When I view the HR dashboard or the employee list, Then I see a persistent alert badge. - Given the alert has been active for 30+ days, When I view the dashboard, Then the alert is escalated (highlighted in red). - Given I fill in the missing CNPS number, Then the alert is automatically dismissed.
A.4 Non-Functional Requirements¶
| Requirement | Target | Notes |
|---|---|---|
| Profile load time | < 1.5 seconds on 3G connection | Employee profile page (all tabs) |
| Search response time | < 500ms for fulltext search with up to 350 employees | PostgreSQL FTS must be indexed |
| Bulk import | Process 500 employees in < 30 seconds | Background job with progress indicator |
| Photo upload | < 3 seconds (upload + crop + thumbnail generation) | Client-side crop, server-side thumbnail |
| Registre export | < 10 seconds for 350 employees | Background generation with download link |
| Offline profile view | Available within 200ms from IndexedDB | Cached on first online view |
| Concurrent profile edits | Online-only for HR Manager edits → no conflict risk | Self-service edits offline → single-editor (the employee), no conflict |
| Document storage | Per-tenant MinIO bucket, subject to segment storage quotas (S1-S6) | Follows Platform Vision §A.8 storage quotas |
| Audit trail | Every create/update/delete on employee data produces immutable AuditEntry | Platform-wide requirement (FR-PV-090-091) |
A.5 MVP Scope (Core HR V1)¶
In V1 (First Release of Core HR)¶
- Enriched employee profile (all Layer 2 fields per §B.1)
- Detailed dependents list (name, DOB, relationship, gender, school attestation)
- Emergency contacts (1-2 per employee)
- Employee photo (upload + client-side crop + thumbnail generation)
- Bank info management (HR-only write, masked employee view, full Comptable read)
- Document attachment with structured taxonomy (system-seeded + admin-custom categories)
- Employee self-service profile view (enriched when HR Core active)
- Employee self-service minimal edit (phone, personal email, address, emergency contacts, photo)
- Single fulltext search field (PostgreSQL FTS, configurable search fields)
- Bulk employee import (dynamic template including HR Core fields)
- Registre du personnel Fascicule 1 export (PDF/Excel)
- Formatted change history (UI view on platform audit trail)
- Employee number auto-generation (
{PREFIX}-{YEAR}-{MM}-{SEQ}) - Missing data alerts (CNPS number, mandatory documents)
- Permission matrix: DG/RH full, Manager read team, Comptable financial read, Employé self-service
Out of V1 — Core HR V2 (Future Enhancements)¶
- Custom employee fields (tenant-defined additional fields beyond standard schema)
- Employee data export to Excel/CSV with column selection
- Advanced photo management (bulk photo upload, photo directory generation)
- Employee self-service: request profile changes with approval workflow (submit bank info change → HR approves)
- Mobile payment methods (Orange Money, MTN MoMo, Wave) as first-class payment options alongside bank accounts
- Employee organigramme (visual org chart)
- Employee directory (company-wide searchable employee directory)
- Integration with government portals (CNPS online, e-impôts CI)
- Multi-country expansion (BJ, CM country-specific fields and registers)
- Custom retention policies per document category (requires ADVDOC)
A.6 Open Questions¶
| # | Question | Priority | Status |
|---|---|---|---|
| OQ-HRCORE-01 | CI data privacy (Loi n°2013-450): Core HR stores the most sensitive employee data (national ID, bank info, medical certificates, marital status). What are the specific obligations for collecting, storing, and processing this data? What consent is required from employees? Does the employer need to register data processing with ARTCI? | 🔴 CRITICAL | Unresolved — deferred from Platform Vision OQ-01. Requires targeted legal research on Loi 2013-450 as it applies to employer HR data processing. |
| OQ-HRCORE-02 | CCI 1977 current status: Employee categories (Cadre, Agent de maîtrise, Employé, Ouvrier) are sourced from the CCI 1977. Has this convention been revised or superseded? If so, category names and definitions may have changed. | 🟡 HIGH | Unresolved. Using CCI 1977 categories as default. See TV-HRCORE-01. |
| OQ-HRCORE-03 | Délégué du personnel threshold (CI): At what headcount are CI employers required to have délégués du personnel? Affects SME workflows (Papillon target: 2-350 employees). Many tenants will be below or near this threshold. | 🟡 HIGH | Unresolved. Flagged in legal audit CHECK 4 + CHECK 5 gap #3. Relevant for EMPMGT more than Core HR, but the threshold affects the employee count dashboard Core HR might display. |
| OQ-HRCORE-04 | Record retention: statutory basis: 10-year retention adopted (aligned with OHADA AUDCIF for simplicity). But no explicit CI statutory basis found for employee personal data retention specifically. The 5-year inference (statute of limitations + CNPS audits) is from the legal research. Needs confirmation. | 🟢 MEDIUM | Temporarily validated at 10 years. See TV-HRCORE-02. |
| OQ-HRCORE-05 | CNPS number format validation: What is the exact format of a CI CNPS registration number? How many digits/characters? Is there a check digit? The system should validate format on input. | 🟢 MEDIUM | Unresolved. Implement as free-text with optional regex validation when format is confirmed. |
| OQ-HRCORE-06 | Medical fitness certificate requirements: When must a certificate be obtained (pre-employment? periodic?)? By whom? At what frequency? Cost borne by employer? Affects document completeness checks. | 🟢 MEDIUM | Unresolved. Flagged in legal audit CHECK 5 gap #13. Core HR should track the document, but frequency/renewal logic may belong to HSE module. |
| OQ-HRCORE-07 | Registre d'employeur: mandatory for all sizes?: Is the 3-fascicule employer register mandatory for all employers regardless of size, including a sole employee? Affects the registre export feature's applicability. | 🟢 MEDIUM | Unresolved. Flagged in legal audit CHECK 4. Assumed mandatory for all for Core HR V1. |
A.7 Temporarily Validated¶
| # | Item | Current Value | Risk | Action Required |
|---|---|---|---|---|
| TV-HRCORE-01 | Employee categories (CCI 1977) | System seeds: Cadre, Cadre supérieur, Agent de maîtrise, Employé/Technicien, Ouvrier. Sourced from CCI 1977. | CCI may have been revised. Categories and their definitions may have changed. | Verify CCI 1977 current status. If updated, adjust seeded categories. |
| TV-HRCORE-02 | Employee data retention period | 10 years after termination (aligned with OHADA AUDCIF payroll/accounting retention). | No explicit CI statutory basis for employee personal data specifically. May be over-retaining personal data, which could conflict with data minimization principles in Loi 2013-450. | Confirm with legal counsel whether 10-year retention of personal data (national ID, bank info) is proportionate or if a shorter period with anonymization is required. |
| TV-HRCORE-03 | CI Art. 14.x decimal sub-numbering | Legal research citations use decimal sub-numbering (Art. 14.1, 14.2, 14.4, etc.) for the Code du Travail 2015. | This numbering format has not been verified against a physical/digital copy of the law. Could be a Perplexity artifact. | One-time verification: check the actual CI Code du Travail 2015 to confirm article numbering format. If confirmed, all citations are trustworthy. |
PART B — Functional Specifications (FSD)¶
B.1 Data Model — Employee Enrichment (Layer 2)¶
Employee Enrichment Fields (Core HR adds to CP baseline)¶
| Field | Type | Mandatory? | Editable by Employee? | Notes |
|---|---|---|---|---|
last_name |
VARCHAR(100) | YES | NO | CP correction: replaces full_name. |
first_name |
VARCHAR(150) | YES | NO | May contain multiple first names (common in CI: "Jean-Pierre Koffi") |
date_of_birth |
DATE | YES | NO | Format DD/MM/YYYY |
place_of_birth |
VARCHAR(200) | NO | NO | Lieu de naissance — common on CI administrative forms |
gender |
ENUM(MALE, FEMALE) | YES | NO | |
nationality |
VARCHAR(100) | YES | NO | Default: Ivoirienne |
national_id_number |
VARCHAR(50) | NO | NO | CNI or Passeport number |
national_id_type |
ENUM(CNI, PASSPORT, TITRE_SEJOUR, OTHER) | NO | NO | Type of identity document |
cnps_registration_number |
VARCHAR(30) | NO (with alert) | NO | Optional at creation, persistent alert if missing. See FR-HRCORE-020. |
tax_id |
VARCHAR(50) | NO | NO | Personal tax identifier (if applicable) |
marital_status |
ENUM(CELIBATAIRE, MARIE, DIVORCE, VEUF, UNION_LIBRE) | NO | NO | Affects tax deductions |
blood_type |
ENUM(A_POS, A_NEG, B_POS, B_NEG, AB_POS, AB_NEG, O_POS, O_NEG, UNKNOWN) | NO | NO | Emergency medical information |
father_name |
VARCHAR(200) | NO | NO | Common on CI administrative documents |
mother_name |
VARCHAR(200) | NO | NO | Common on CI administrative documents |
professional_qualifications |
TEXT | NO | NO | Diplomas, certifications (free text for V1) |
previous_employer |
VARCHAR(200) | NO | NO | For transfer/seniority calculations |
previous_employer_exit_date |
DATE | NO | NO | For seniority continuity calculations |
Address Fields (Semi-Structured)¶
| Field | Type | Mandatory? | Editable by Employee? | Notes |
|---|---|---|---|---|
address_city |
VARCHAR(100) | NO | YES | Dropdown with major CI cities + free text option |
address_commune |
VARCHAR(150) | NO | YES | Commune / Quartier (free text) |
address_details |
VARCHAR(500) | NO | YES | Street, landmark, building (free text) |
Bank Info Fields¶
| Field | Type | Mandatory? | Editable by Employee? | Notes |
|---|---|---|---|---|
bank_name |
VARCHAR(100) | NO | NO | HR-only management |
bank_account_number |
VARCHAR(50) | NO | NO | Masked display for employee (last 4 digits) |
bank_iban |
VARCHAR(50) | NO | NO | International Bank Account Number (if applicable) |
bank_rib_key |
VARCHAR(10) | NO | NO | RIB key (specific to UEMOA banking) |
bank_branch_code |
VARCHAR(20) | NO | NO | Code agence |
Contact Fields (Employee Self-Editable)¶
| Field | Type | Mandatory? | Editable by Employee? | Notes |
|---|---|---|---|---|
personal_email |
VARCHAR(255) | NO | YES | Distinct from work email (in CP) |
personal_phone |
VARCHAR(20) | NO | YES | Distinct from work phone (in CP) |
Photo¶
| Field | Type | Notes |
|---|---|---|
photo_original_key |
VARCHAR(500) | MinIO object key for original photo |
photo_medium_key |
VARCHAR(500) | 150px version |
photo_thumbnail_key |
VARCHAR(500) | 48px version |
B.2 Sub-Entities¶
Emergency Contact¶
| Field | Type | Mandatory? | Notes |
|---|---|---|---|
id |
UUID | — | |
employee_id |
FK | YES | |
tenant_id |
FK | YES | Multi-tenant scoping |
full_name |
VARCHAR(200) | YES | |
relationship |
ENUM(CONJOINT, PERE, MERE, FRERE_SOEUR, ENFANT, AUTRE) | YES | Dropdown |
phone_number |
VARCHAR(20) | YES | Primary phone |
phone_number_2 |
VARCHAR(20) | NO | Secondary phone |
priority_order |
SMALLINT | YES | 1 or 2 |
Constraint: Minimum 0, maximum 2 emergency contacts per employee.
Dependent¶
| Field | Type | Mandatory? | Notes |
|---|---|---|---|
id |
UUID | — | |
employee_id |
FK | YES | |
tenant_id |
FK | YES | Multi-tenant scoping |
full_name |
VARCHAR(200) | YES | |
date_of_birth |
DATE | YES | Used for age-based benefit calculations |
relationship |
ENUM(CONJOINT, ENFANT, AUTRE_PERSONNE_A_CHARGE) | YES | |
gender |
ENUM(MALE, FEMALE) | NO | |
is_school_enrolled |
BOOLEAN | NO | Default: false. For children — affects allocations familiales |
school_attestation_attached |
BOOLEAN | NO | Default: false. Document tracked via document attachment |
Computed fields (from dependents list):
- dependents_count = COUNT(dependents)
- number_of_children = COUNT(dependents WHERE relationship = ENFANT)
Document Attachment¶
| Field | Type | Mandatory? | Notes |
|---|---|---|---|
id |
UUID | — | |
employee_id |
FK | YES | |
tenant_id |
FK | YES | Multi-tenant scoping |
category_code |
VARCHAR(50) | YES | FK to document category reference table |
file_name |
VARCHAR(255) | YES | Original file name |
minio_object_key |
VARCHAR(500) | YES | MinIO storage key |
file_size_bytes |
BIGINT | YES | For storage quota tracking |
mime_type |
VARCHAR(100) | YES | |
uploaded_by |
FK (User) | YES | |
uploaded_at |
TIMESTAMP | YES | |
description |
VARCHAR(500) | NO | Optional note about the document |
Document Category (Reference Table)¶
| Field | Type | Notes |
|---|---|---|
code |
VARCHAR(50) PK | e.g., CONTRAT, MEDICAL_CERT, IDENTITY, CNPS_ATTESTATION |
tenant_id |
FK (nullable) | NULL = system-seeded (shared). Non-null = tenant-custom. |
display_name_fr |
VARCHAR(100) | French label |
sort_order |
SMALLINT | Display ordering |
is_system |
BOOLEAN | true = cannot be deleted/modified by tenant |
System-seeded categories (CI):
| Code | Display Name (FR) | Notes |
|---|---|---|
CONTRAT_TRAVAIL |
Contrat de travail | |
AVENANT |
Avenant au contrat | |
CERTIFICAT_MEDICAL |
Certificat médical d'aptitude | |
PIECE_IDENTITE |
Pièce d'identité (CNI/Passeport) | |
ATTESTATION_CNPS |
Attestation CNPS | |
CERTIFICAT_TRAVAIL |
Certificat de travail | Issued at departure |
DIPLOMES |
Diplômes et qualifications | |
RIB |
Relevé d'Identité Bancaire | |
BULLETIN_PAIE |
Bulletin de paie | Payroll will auto-attach if HRCORE active |
ATTESTATION_SCOLAIRE |
Attestation de scolarité (enfant) | For dependent school enrollment |
PHOTO_IDENTITE |
Photo d'identité | |
AUTRE |
Autre document | Catch-all |
Search Configuration¶
| Field | Type | Notes |
|---|---|---|
id |
UUID | |
tenant_id |
FK | One configuration per tenant |
search_fields |
VARCHAR[] (array) | List of column names included in fulltext index. Default: ['last_name', 'first_name', 'department_name'] |
updated_by |
FK (User) | |
updated_at |
TIMESTAMP |
Employee Number Configuration¶
| Field | Type | Notes |
|---|---|---|
tenant_id |
FK PK | One configuration per tenant |
prefix |
VARCHAR(10) | Auto-generated from company name (trigram/4-6 letters). Editable by admin. |
next_sequence |
INTEGER | Auto-incremented per employee creation. Never decremented. |
Format: {prefix}-{YEAR}-{MM}-{SEQ} → Example: ALT-2026-03-001
B.3 Functional Rules¶
Employee Profile Management¶
| Rule | Description |
|---|---|
| FR-HRCORE-001 | IF HR Core module is ACTIVE for a tenant THEN employees in that tenant have access to Layer 2 enrichment fields in addition to the Layer 1 (CP) baseline fields. |
| FR-HRCORE-002 | IF HR Core module is INACTIVE for a tenant THEN only Layer 1 (CP) baseline fields are visible and editable. Layer 2 data, if previously entered, is hidden in the UI (module deactivation sets status to INACTIVE immediately; enriched fields are hidden). MVP behavior — no grace period, no read-only state (those are V2 per FR-PV-040 through FR-PV-044). |
| FR-HRCORE-003 | The employee last_name and first_name fields are separate. The display value full_name is computed as UPPER(last_name) || ' ' || first_name for formal display (e.g., "KOUASSI Jean-Pierre"). This convention follows CI administrative naming standards. |
| FR-HRCORE-004 | All Layer 2 fields are optional at employee creation EXCEPT: date_of_birth, gender, nationality. These are mandatory when HR Core is active because they are required by the registre du personnel. |
| FR-HRCORE-005 | IF an employee record is saved with optional fields left empty THEN the system tracks completeness as a percentage (number of filled fields / total fields). This percentage is displayed on the employee profile and used for missing data alerts (FR-HRCORE-020). |
Employee Self-Service¶
| Rule | Description |
|---|---|
| FR-HRCORE-010 | Employees can EDIT the following fields on their own profile (self-service): personal_phone, personal_email, address_city, address_commune, address_details, emergency contacts, and photo. |
| FR-HRCORE-011 | Employees CANNOT edit: last_name, first_name, date_of_birth, national_id_number, cnps_registration_number, marital_status, dependents, bank_* fields, gender, nationality, blood_type, father_name, mother_name, professional_qualifications, previous_employer. These require HR Manager or DG action. |
| FR-HRCORE-012 | Employee self-service edits (FR-HRCORE-010 fields) take effect immediately — no approval workflow for V1. |
| FR-HRCORE-013 | Employee self-service edits are available OFFLINE. Changes are queued in IndexedDB and synced within 30s of reconnection. Since each employee can only edit their own profile, there is no conflict risk. |
| FR-HRCORE-014 | HR Manager edits to any employee field require ONLINE connectivity. Offline HR Manager edits are not supported in V1 to prevent concurrent edit conflicts. |
Bank Info Security¶
| Rule | Description |
|---|---|
| FR-HRCORE-015 | Bank info fields (bank_name, bank_account_number, bank_iban, bank_rib_key, bank_branch_code) can only be CREATED or UPDATED by users with role DG or RH Manager. |
| FR-HRCORE-016 | When an employee views their own bank info, bank_account_number and bank_iban are MASKED: only the last 4 characters are displayed (e.g., "●●●●●●●●4523"). bank_name is displayed in full. |
| FR-HRCORE-017 | Users with role Comptable can view full (unmasked) bank info in READ-ONLY mode. This is necessary for payroll/accounting reconciliation. |
| FR-HRCORE-018 | Every bank info change triggers an EmployeeBankInfoChanged event. This event carries a security_flag: true attribute to enable downstream security monitoring (e.g., detect if someone changes multiple employees' bank info rapidly — potential fraud pattern). |
| FR-HRCORE-019 | Bank info change history is preserved: the system stores previous bank info values in the audit trail. The current bank info is the latest. There is no separate bank info history table — the platform audit trail (AuditEntry with before/after JSON) serves this purpose. |
CNPS Number and Alerts¶
| Rule | Description |
|---|---|
| FR-HRCORE-020 | IF an employee's cnps_registration_number is NULL or empty THEN the system creates a persistent alert visible to DG and RH Manager users. The alert message: "Numéro CNPS manquant pour {last_name} {first_name} — veuillez procéder à l'immatriculation CNPS et mettre à jour le dossier." |
| FR-HRCORE-021 | The CNPS alert reappears on the HR dashboard MONTHLY until the field is filled. After 30 days without resolution, the alert is escalated (displayed in red/urgent style). |
| FR-HRCORE-022 | IF the cnps_registration_number field is populated THEN the alert is automatically dismissed. |
| FR-HRCORE-023 | The CNPS number alert applies only to employees with status ACTIVE. Terminated employees with missing CNPS numbers do not generate alerts. |
Dependents Management¶
| Rule | Description |
|---|---|
| FR-HRCORE-025 | Each employee can have 0 or more dependents. There is no upper limit on the number of dependents. |
| FR-HRCORE-026 | When a dependent is added, updated, or removed, the system automatically recomputes: dependents_count = total count of dependents, number_of_children = count of dependents where relationship = ENFANT. |
| FR-HRCORE-027 | IF dependents_count or number_of_children changes THEN the system publishes an EmployeeUpdated event with changedFields: ['dependents_count', 'number_of_children']. Payroll consumes this to recalculate tax deductions. |
| FR-HRCORE-028 | The date_of_birth of a child dependent is used to determine age-based eligibility for allocations familiales. Age calculation rules belong to the Payroll module — Core HR only stores the data. |
| FR-HRCORE-029 | Dependents are managed exclusively by DG or RH Manager. Employees cannot add/edit/remove their own dependents (these have payroll implications). |
Document Attachment¶
| Rule | Description |
|---|---|
| FR-HRCORE-030 | Every document attached to an employee must have a category_code from the document category reference table. The system provides seeded categories (see §B.2) and tenants can add custom categories via admin configuration. |
| FR-HRCORE-031 | File upload constraints: maximum file size 10 MB, accepted MIME types: application/pdf, image/jpeg, image/png, image/webp, application/vnd.openxmlformats-officedocument.wordprocessingml.document (DOCX). |
| FR-HRCORE-032 | Each uploaded document counts against the tenant's storage quota (per Platform Vision §A.8). IF uploading a document would exceed the tenant's storage quota THEN the upload is blocked with message: "Quota de stockage atteint. Veuillez supprimer des documents ou acheter de l'espace supplémentaire." |
| FR-HRCORE-033 | Documents can be uploaded by DG, RH Manager, or the employee themselves (self-service — e.g., uploading a new identity document copy). |
| FR-HRCORE-034 | Documents can only be DELETED by DG or RH Manager. Employees cannot delete their own documents. Deletion is a soft-delete (marked as deleted, not physically removed from MinIO — retained per OHADA 10-year rule for relevant document types). |
| FR-HRCORE-035 | IF ADVDOC (Advanced Document Management) module is ACTIVE THEN document uploads automatically gain versioning, retention policies, and lifecycle management per FR-PV-036. Core HR's document attachment UI seamlessly delegates to ADVDOC when active. |
Employee Photo¶
| Rule | Description |
|---|---|
| FR-HRCORE-040 | Photo upload accepted formats: JPEG, PNG, WebP. Maximum file size: 2 MB. |
| FR-HRCORE-041 | After upload, the system presents a client-side crop tool enforcing a 3:4 portrait aspect ratio. The user must confirm the crop before the photo is saved. |
| FR-HRCORE-042 | On crop confirmation, the system generates 3 versions stored in MinIO: original (as cropped), medium (150px width, proportional height), thumbnail (48px width, proportional height). |
| FR-HRCORE-043 | Photos can be uploaded by: the employee themselves (self-service) OR the HR Manager/DG. |
| FR-HRCORE-044 | Uploading a new photo replaces the previous one. The previous photo is NOT retained (no versioning in V1 — ADVDOC would add this). |
Employee Number Generation¶
| Rule | Description |
|---|---|
| FR-HRCORE-050 | Employee numbers are auto-generated using the format: {PREFIX}-{YEAR}-{MM}-{SEQ}. Example: ALT-2026-03-001. |
| FR-HRCORE-051 | {PREFIX} is auto-derived from the tenant's company name at tenant creation: the system extracts a 3-6 letter trigram/abbreviation. Example: "ALTARYS ENTERPRISE" → "ALT", "Boulangerie Mama Kadi" → "BMK". |
| FR-HRCORE-052 | The PREFIX is stored in the employee number configuration (per tenant) and is editable by tenant admin (DG or RH Manager). The system displays a notification during onboarding: "Le préfixe de numérotation de vos employés est {PREFIX}. Vous pouvez le modifier dans les paramètres." |
| FR-HRCORE-053 | {YEAR} is the 4-digit year of employee creation. {MM} is the 2-digit month. {SEQ} is a 3-digit zero-padded sequential number that auto-increments per tenant. Example: the 15th employee created in March 2026 → ALT-2026-03-015. |
| FR-HRCORE-054 | Employee numbers are NEVER reused. IF an employee is terminated, their number is NOT recycled. The sequence only increments. |
| FR-HRCORE-055 | During bulk import, IF the imported Excel contains employee numbers THEN the system uses those (for migration). IF the employee number column is empty THEN the system auto-generates per the above rules. Imported numbers are validated for uniqueness within the tenant. |
Fulltext Search¶
| Rule | Description |
|---|---|
| FR-HRCORE-060 | Core HR provides a single search field using PostgreSQL fulltext search (tsvector/tsquery). The search input accepts free text and searches across configured fields. |
| FR-HRCORE-061 | Default search fields: last_name, first_name, department_name (denormalized or joined from org unit). These defaults apply to all new tenants. |
| FR-HRCORE-062 | DG or RH Manager can CONFIGURE which fields are included in the fulltext search index via a settings screen. Available fields for inclusion: last_name, first_name, department_name, position_title, employee_number, cnps_registration_number, national_id_number, personal_phone, email, address_city, address_commune. |
| FR-HRCORE-063 | When the search configuration changes, the system rebuilds the fulltext search index for that tenant. For tenants with up to 350 employees, this should complete in < 5 seconds. |
| FR-HRCORE-064 | Search results are scoped by the user's access level: DG/RH Manager see all employees; Manager sees only employees in their org unit; Comptable sees all employees (financial data); Employé sees only their own record. |
| FR-HRCORE-065 | Search supports partial matches and accent-insensitive search (important for French: "Koné" matches "kone"). PostgreSQL unaccent extension must be used. |
Bulk Import¶
| Rule | Description |
|---|---|
| FR-HRCORE-070 | IF HR Core is ACTIVE for the tenant THEN the employee import Excel template includes both Layer 1 (CP) and Layer 2 (HR Core) columns. IF HR Core is INACTIVE THEN only Layer 1 columns are included. (Layer 1 import is a Control Plane feature; HR Core extends the template.) |
| FR-HRCORE-071 | All Layer 2 (HR Core) fields in the import template are OPTIONAL. The import succeeds even if all HR Core columns are empty — employees are created with Layer 1 data, and HR Core enrichment can be done later. |
| FR-HRCORE-072 | After Excel upload, the system displays an editable confirmation table (per FR-PV-051). Validation errors are highlighted per row per field: duplicate employee numbers, invalid date formats, invalid enum values (gender, marital status, etc.). |
| FR-HRCORE-073 | The import is processed as a background job with a progress indicator. For 500 employees, the import should complete in < 30 seconds. |
| FR-HRCORE-074 | Each successfully imported employee triggers an EmployeeCreated event (from CP) and, if HR Core fields are populated, an EmployeeUpdated event (from HR Core). |
| FR-HRCORE-075 | The import must validate uniqueness of employee_number within the tenant. IF a duplicate is found THEN the row is rejected with error: "Numéro matricule en doublon: {number}." |
Registre du Personnel (Fascicule 1)¶
| Rule | Description |
|---|---|
| FR-HRCORE-080 | Core HR generates the Fascicule 1 (Registre du Personnel) containing employee data. Fascicule 2 (Salaires) belongs to Payroll. Fascicule 3 (Visas d'inspection) belongs to Employee Management or HSE. |
| FR-HRCORE-081 | The Fascicule 1 export includes the following columns per employee: numéro d'ordre (sequential), last_name, first_name, date_of_birth, place_of_birth, gender, nationality, national_id_number, cnps_registration_number, position_title, employee_category, hire_date, contract_type, address, termination_date (if applicable), termination_reason (if applicable). |
| FR-HRCORE-082 | The export includes ALL employees: ACTIVE, ON_LEAVE, SUSPENDED, and TERMINATED. Terminated employees are listed with their termination date and reason. |
| FR-HRCORE-083 | The export is available in two formats: PDF (formatted for printing, landscape A4) and Excel (for digital archival and inspection submission). |
| FR-HRCORE-084 | IF any employee in the export has missing mandatory fields (e.g., CNPS number) THEN the export includes a warning summary at the end listing employees with incomplete records. The export is NOT blocked — it generates with "Non renseigné" in the missing fields. |
| FR-HRCORE-085 | The export is generated as a background job. A download link is provided when complete. For 350 employees, generation should take < 10 seconds. |
Change History View¶
| Rule | Description |
|---|---|
| FR-HRCORE-090 | Core HR provides a "Historique des modifications" tab on each employee's profile. This tab displays a human-readable, chronological timeline of changes sourced from the platform audit trail (AuditEntry). |
| FR-HRCORE-091 | The change history view translates raw AuditEntry data into French labels. Example: { field: "address_city", old: "Cocody", new: "Plateau" } → "Ville de résidence : Cocody → Plateau". |
| FR-HRCORE-092 | The change history shows: date of change, user who made the change (display name + role), field name (French label), old value, new value. |
| FR-HRCORE-093 | The change history is visible to DG and RH Manager. Employees see a simplified version on their own profile showing only: date of change and which field was changed (not the old/new values — to prevent information leakage about who made the change). |
| FR-HRCORE-094 | No separate storage is maintained. The formatted view is a UI presentation layer querying the AuditEntry table filtered by entity_type = 'Employee' and entity_id = {employeeId}. |
B.4 State Machines¶
Core HR does not introduce new lifecycle states. The employee lifecycle (ACTIVE → ON_LEAVE → SUSPENDED → TERMINATED) is managed by the Control Plane / Employee Management, not Core HR.
However, Core HR introduces a profile completeness state concept:
stateDiagram-v2
[*] --> INCOMPLETE : Employee created (HR Core fields mostly empty)
INCOMPLETE --> PARTIAL : Some HR Core fields filled
INCOMPLETE --> COMPLETE : All mandatory + key optional fields filled
PARTIAL --> COMPLETE : Remaining fields filled
PARTIAL --> INCOMPLETE : Fields cleared/removed
COMPLETE --> PARTIAL : Mandatory field cleared (e.g., data correction)
note right of INCOMPLETE : Triggers missing data alerts (FR-HRCORE-020)
note right of COMPLETE : No alerts. Registre export clean.
Profile completeness levels: - INCOMPLETE (0-40%): Missing mandatory fields (date_of_birth, gender, nationality) or critical data (CNPS number). Red indicator. - PARTIAL (41-80%): Mandatory fields filled but optional fields (bank info, emergency contacts, documents) missing. Yellow indicator. - COMPLETE (81-100%): All mandatory fields + key optional fields (CNPS, at least 1 emergency contact, photo, 1 identity document) filled. Green indicator.
These are COMPUTED states (not stored) — derived from field population at display time.
B.5 Decision Tables¶
Permission Matrix¶
| Action | DG | RH Manager | Manager | Comptable | Employé |
|---|---|---|---|---|---|
| View any employee profile (Layer 2) | ✅ | ✅ | ⚠️ Team only | ⚠️ Financial fields only | ❌ (own only) |
| Edit any employee profile (Layer 2) | ✅ | ✅ | ❌ | ❌ | ❌ |
| Edit own profile (self-service fields) | ✅ | ✅ | ✅ | ✅ | ✅ |
| View bank info (full) | ✅ | ✅ | ❌ | ✅ (read-only) | ❌ (masked) |
| Edit bank info | ✅ | ✅ | ❌ | ❌ | ❌ |
| Manage dependents | ✅ | ✅ | ❌ | ❌ | ❌ |
| Upload documents | ✅ | ✅ | ❌ | ❌ | ✅ (own docs) |
| Delete documents | ✅ | ✅ | ❌ | ❌ | ❌ |
| Configure search fields | ✅ | ✅ | ❌ | ❌ | ❌ |
| Configure employee number prefix | ✅ | ✅ | ❌ | ❌ | ❌ |
| Manage document categories | ✅ | ❌ | ❌ | ❌ | ❌ |
| Export registre du personnel | ✅ | ✅ | ❌ | ❌ | ❌ |
| Bulk import employees | ✅ | ✅ | ❌ | ❌ | ❌ |
| View change history (full) | ✅ | ✅ | ❌ | ❌ | ❌ |
| View change history (simplified, own) | — | — | — | — | ✅ |
Offline Capability Matrix¶
| Operation | Offline? | User | Sync Behavior |
|---|---|---|---|
| View employee profile | ✅ Yes | All roles | Read from IndexedDB cache |
| Edit self-service fields | ✅ Yes | Employé | Queue in IndexedDB, sync on reconnect |
| Upload photo (self-service) | ✅ Yes | Employé | Queue locally, upload on reconnect |
| Edit employee profile (HR) | ❌ No | DG/RH | Requires connectivity |
| Edit bank info | ❌ No | DG/RH | Requires connectivity |
| Manage dependents | ❌ No | DG/RH | Requires connectivity |
| Upload documents | ❌ No | DG/RH/Employé | Requires connectivity (MinIO upload) |
| Search employees | ⚠️ Partial | All roles | Searches cached data (may be stale) |
| Export registre | ❌ No | DG/RH | Requires connectivity (server-side generation) |
| Bulk import | ❌ No | DG/RH | Requires connectivity |
Document Category Visibility¶
| Category Code | Auto-attached by | Visible to Employee? | Deletable? |
|---|---|---|---|
CONTRAT_TRAVAIL |
Employee Mgmt (V2) | ✅ | ❌ (legal retention) |
BULLETIN_PAIE |
Payroll (auto-attach) | ✅ | ❌ (legal retention) |
CERTIFICAT_MEDICAL |
HR Manager | ❌ (medical privacy) | ❌ (legal retention) |
PIECE_IDENTITE |
HR Manager / Employee | ✅ | Soft-delete only |
ATTESTATION_CNPS |
HR Manager | ✅ | Soft-delete only |
DIPLOMES |
HR Manager / Employee | ✅ | Soft-delete only |
RIB |
HR Manager | ❌ (financial privacy) | Soft-delete only |
AUTRE |
HR Manager / Employee | ✅ | Soft-delete only |
B.6 Cross-Module Dependencies¶
Events Published by Core HR¶
| Event | Trigger | Payload | Consumed By |
|---|---|---|---|
EmployeeUpdated |
Any Layer 2 field change (low-risk: address, phone, photo, emergency contacts, qualifications) | { employeeId, tenantId, changedFields[], timestamp, changedBy } |
Modules caching employee data |
EmployeeBankInfoChanged |
Any bank_* field change | { employeeId, tenantId, bankName, maskedAccountNumber, changedBy, timestamp, security_flag: true } |
Payroll (recache payment info), Audit/Security monitoring |
EmployeeCategoryChanged |
Employee category change (via CP, but HR Core may display/trigger) | { employeeId, tenantId, oldCategoryId, newCategoryId, effectiveDate } |
Payroll (contribution rate recalculation) |
EmployeeProfileCompleted |
Profile completeness reaches COMPLETE state | { employeeId, tenantId, completenessPercent, timestamp } |
Employee Mgmt (onboarding checklist), Dashboard |
EmployeeDocumentAttached |
Document uploaded to employee | { employeeId, tenantId, documentId, categoryCode, fileName } |
ADVDOC (if active — for versioning/retention), Dashboard |
Events Consumed by Core HR¶
| Event | Published By | Core HR Reaction |
|---|---|---|
EmployeeCreated |
Control Plane | Creates empty Layer 2 record for the new employee. Triggers CNPS alert if CNPS number not provided. |
EmployeeTerminated |
Employee Mgmt / CP | Dismisses active CNPS alerts for terminated employee (FR-HRCORE-023). Marks profile as historical. |
EmployeeReassigned |
Employee Mgmt | Updates cached department name for fulltext search index (if department is a search field). |
PayslipGenerated |
Payroll | IF HRCORE active THEN auto-attaches payslip as document (category: BULLETIN_PAIE) to employee. |
API Dependencies (Synchronous)¶
| Caller | Calls | Endpoint | Purpose |
|---|---|---|---|
| Core HR | Control Plane | GET /api/v1/cp/employees/{id} | Read Layer 1 baseline data (live read for contract snapshot display) |
| Core HR | Control Plane | GET /api/v1/cp/org-units/{id} | Read org unit details (department name for search, manager for display) |
| Core HR | Control Plane | GET /api/v1/cp/positions/{id} | Read position title for display |
| Core HR | MinIO (Storage) | PUT /upload, GET /download, DELETE | Document and photo storage |
| Payroll | Core HR | GET /api/v1/hrcore/employees/{id}/bank-info | Read bank info for payment processing (post-MVP) |
| Payroll | Core HR | GET /api/v1/hrcore/employees/{id}/dependents/summary | Read dependents_count + number_of_children for tax calculations |
| Employee Mgmt | Core HR | GET /api/v1/hrcore/employees/{id}/profile | Read enriched profile for administrative event creation |
| Any module | Core HR | GET /api/v1/hrcore/employees/{id}/photo/thumbnail | Read employee thumbnail for display in lists |
API Exposed by Core HR¶
| Endpoint | Method | Purpose | Consumers |
|---|---|---|---|
/api/v1/hrcore/employees/{id} |
GET | Full enriched employee profile (Layer 1 + 2) | Frontend, Employee Mgmt |
/api/v1/hrcore/employees/{id} |
PATCH | Update Layer 2 fields | Frontend (HR Manager) |
/api/v1/hrcore/employees/{id}/self-service |
PATCH | Update self-service fields (FR-HRCORE-010) | Frontend (Employee) |
/api/v1/hrcore/employees/{id}/bank-info |
GET | Bank info (masked or full based on role) | Frontend, Payroll |
/api/v1/hrcore/employees/{id}/bank-info |
PUT | Update bank info (DG/RH only) | Frontend |
/api/v1/hrcore/employees/{id}/dependents |
GET/POST/PUT/DELETE | CRUD dependents | Frontend |
/api/v1/hrcore/employees/{id}/dependents/summary |
GET | Computed counts (dependents_count, number_of_children) | Payroll |
/api/v1/hrcore/employees/{id}/emergency-contacts |
GET/POST/PUT/DELETE | CRUD emergency contacts (max 2) | Frontend |
/api/v1/hrcore/employees/{id}/documents |
GET/POST/DELETE | Document CRUD with category | Frontend, ADVDOC |
/api/v1/hrcore/employees/{id}/photo |
GET/POST | Photo upload/retrieve (3 sizes) | Frontend, any module |
/api/v1/hrcore/employees/{id}/change-history |
GET | Formatted change history (from AuditEntry) | Frontend |
/api/v1/hrcore/employees/search |
GET | Fulltext search (query param: q) |
Frontend |
/api/v1/hrcore/employees/import |
POST | Bulk import (multipart Excel upload) | Frontend |
/api/v1/hrcore/registre/fascicule-1 |
POST | Generate registre export (returns job ID) | Frontend |
/api/v1/hrcore/registre/fascicule-1/{jobId} |
GET | Download generated registre | Frontend |
/api/v1/hrcore/config/search-fields |
GET/PUT | Search configuration | Frontend (Admin) |
/api/v1/hrcore/config/employee-number |
GET/PUT | Employee number prefix configuration | Frontend (Admin) |
/api/v1/hrcore/config/document-categories |
GET/POST/PUT/DELETE | Document category management | Frontend (Admin) |
/api/v1/hrcore/dashboard/alerts |
GET | Missing data alerts (CNPS, incomplete profiles) | Frontend (Dashboard) |
B.7 Multi-Tenant Implications¶
| Concern | Shared DB | Schema-per-Tenant | DB-per-Tenant | BYO-DB |
|---|---|---|---|---|
| Employee enrichment data | tenant_id column on employee_enrichment table. Every query includes WHERE tenant_id = ?. |
Per-schema table. No tenant_id filter needed. | Per-DB table. | Per-DB table. |
| Document storage | Tenant-scoped MinIO bucket: tenant-{tenantId}/employees/{employeeId}/docs/ |
Same MinIO path structure. | Same. | Tenant provides storage or uses platform MinIO. |
| Photo storage | tenant-{tenantId}/employees/{employeeId}/photos/ |
Same. | Same. | Same. |
| Fulltext search index | Per-tenant tsvector column, filtered by tenant_id. Search config stored per tenant. | Per-schema index. More efficient (no tenant filtering). | Per-DB index. | Per-DB index. |
| Document categories | System-seeded categories (tenant_id = NULL) + tenant-custom (tenant_id = X). | System categories in shared schema. Tenant customs in tenant schema. | Per-DB. | Per-DB. |
| Employee number sequence | Sequence per tenant (stored in config table, not a DB sequence — for portability). | Same — application-level sequence. | Same. | Same. |
| Storage quotas | Tracked in platform DB (Control Plane). Checked before every upload. | Same. | Same. | Same. |
Design principle: All multi-tenant patterns follow the Platform Vision (§B.5). Design for BYO-DB first. Employee number sequences are application-level (not PostgreSQL SEQUENCE objects) to ensure portability across all 4 DB profiles.
PART C — Constraints & Boundaries¶
C.1 Regulatory Compliance — CI (Côte d'Ivoire)¶
CI Registre d'Employeur (Code du Travail 2015)¶
The CI Code du Travail (Loi n°2015-532) requires every employer to maintain a registre d'employeur in 3 fascicules:
- Fascicule 1 — Personnel: Sequential employee listing with personal and professional data. Core HR generates this.
- Fascicule 2 — Salaires: Salary register. Payroll module scope.
- Fascicule 3 — Visas d'inspection: Inspection visits register. Employee Mgmt / HSE scope.
The register must be: - Kept at the workplace - Available for inspection by the Labor Inspector (Inspecteur du Travail) at any time - Maintained in French
Core HR's registre export (FR-HRCORE-080-085) generates Fascicule 1 in compliant format.
CI Employee File Requirements (Loi 2013-546, Décret 2016-851)¶
CI law permits electronic employee records (Loi n°2013-546 on electronic transactions + Décret n°2016-851 on electronic signatures and archives). Core HR's digital dossier du personnel is legally valid provided: - Documents are stored with integrity guarantees (MinIO checksums) - Audit trail tracks all modifications (platform AuditEntry) - Electronic copies of signed documents are acceptable
CI CNPS Registration¶
Every employee must be registered with CNPS (Caisse Nationale de Prévoyance Sociale) on the first day of employment (Part 3.1 of legal research). Core HR: - Stores the CNPS registration number (FR-HRCORE-020) - Generates alerts when the number is missing - Does NOT handle the actual CNPS declaration (that's Employee Management's scope)
Compliance Gap: Tenants Without HR Core¶
Acknowledged gap: Tenants who do not purchase the HR Core module cannot maintain a compliant registre du personnel within the platform. They must manage the registre externally (paper or Excel). This is acceptable because: 1. The Control Plane baseline provides sufficient data for operational modules (Absence, Attendance, Payroll). 2. HR Core is marketed as a compliance and organizational module — tenants who care about compliance will purchase it. 3. The module upsell prompt in the Papillon UI can highlight the registre compliance benefit.
C.2 Localization Requirements — CI¶
| Aspect | Requirement |
|---|---|
| Language | French (all UI labels, validation messages, export headers, document category names) |
| Name display | Formal: UPPER(last_name) first_name (e.g., "KOUASSI Jean-Pierre"). Informal: first_name last_name. |
| Currency | N/A — Core HR does not handle currency fields directly. Bank info is identifier-based (account numbers), not amounts. |
| Date format | DD/MM/YYYY for all date fields |
| Phone format | CI mobile: +225 XX XX XX XX XX (10 digits after country code). Input validation with this format. |
| Address | Semi-structured: city (dropdown with CI cities), commune/quartier (free text), details (free text). No postal codes. |
| Public holidays | N/A — Core HR does not manage holidays (Absence module). |
| Cities dropdown | Seeded with major CI cities: Abidjan, Bouaké, Daloa, Yamoussoukro, San-Pédro, Korhogo, Man, Divo, Gagnoa, Abengourou + "Autre" for free text |
C.3 Security Requirements¶
| Requirement | Implementation |
|---|---|
| Sensitive data classification | Bank info and national ID number are classified as SENSITIVE. Medical documents (category: CERTIFICAT_MEDICAL) are classified as MEDICAL_SENSITIVE. |
| Bank info masking | Employee self-service displays only last 4 characters. API endpoint returns masked data unless caller has COMPTABLE or RH_MANAGER/DG role. |
| Medical document access | Documents with category CERTIFICAT_MEDICAL are visible only to DG and RH Manager. Employees can see that a medical certificate exists but cannot view its content (document metadata visible, download blocked). |
| Financial document access | Documents with category RIB are visible only to DG, RH Manager, and Comptable. |
| Audit trail | Every mutation on employee enrichment data, dependents, emergency contacts, bank info, documents, and photos produces an immutable AuditEntry. Bank info changes are flagged as security-sensitive (FR-HRCORE-018). |
| Photo storage | Photos stored in tenant-scoped MinIO bucket. Access controlled via signed URLs with expiration (no public URLs). |
| Document storage | Documents stored in tenant-scoped MinIO bucket with signed URLs. Download requires valid JWT with appropriate role. |
| Bulk import security | Import Excel file is scanned for macro content (reject .xlsm). File is deleted from server after processing. Import audit log records: who imported, when, how many records, any validation errors. |
| CNPS number sensitivity | CNPS registration number is a national identifier — treated as sensitive. Not displayed in search results or employee lists. Visible only on the full employee profile view (DG, RH Manager, the employee themselves). |
C.4 Out of Scope¶
| Item | Reason | Owner |
|---|---|---|
| Contract lifecycle management (creation, renewal, amendments, CDD tracking) | Process layer — belongs to Employee Management (EMPMGT) | EMPMGT PRD |
| Onboarding/offboarding workflows | Process layer — belongs to Employee Management | EMPMGT PRD |
| Trial period tracking and alerts | Process layer — belongs to Employee Management | EMPMGT PRD |
| Termination procedures and severance calculations | Process layer — belongs to Employee Management + Payroll | EMPMGT + PAYROL PRDs |
| CNPS declarations (hiring, departure, DISA) | Declaration management — belongs to Employee Management | EMPMGT PRD |
| Working hours rules, overtime, night work | Time management — belongs to Time & Activities (TIMACT) | TIMACT PRD |
| Salary information (current salary, salary history, grade) | Financial data — owned by Payroll. Core HR displays contract snapshot via live read from CP/EMPMGT. | PAYROL + EMPMGT PRDs |
| Registre du Personnel Fascicule 2 (Salaires) | Salary data — belongs to Payroll | PAYROL PRD |
| Registre du Personnel Fascicule 3 (Visas d'inspection) | Inspection data — belongs to Employee Management or HSE | EMPMGT/HSE PRD |
| Custom employee fields (tenant-defined) | V2 enhancement | Core HR V2 |
| Employee organigramme (visual org chart) | V2 enhancement | Core HR V2 |
| Employee directory (company-wide) | V2 enhancement | Core HR V2 |
| Document versioning, retention policies, lifecycle management | Requires Advanced Document Management (ADVDOC) module | ADVDOC PRD |
| Document generation (contracts, certificates, attestations from templates) | Requires ADVDOC V2 | ADVDOC V2 PRD |
| Multi-country support (BJ, CM fields and registers) | Country expansion planned for Month 9 | Core HR country expansion PRD |
| SSO/SAML authentication for employee self-service | Enterprise V2 feature | Platform V2 |
| Employee self-service: request changes with approval workflow | V2 — requires approval engine | Core HR V2 |
| Medical fitness certificate tracking (renewal dates, periodic exams) | HSE module scope | HSE PRD |
| Conventions collectives sector-specific rules | V2 — platform supports only CCI interprofessionnelle for MVP | Platform V2 |
Glossary (Module-Specific Terms)¶
| Term (FR) | Term (EN) | Definition |
|---|---|---|
| Dossier du personnel | Employee file | Complete record of an employee's personal, professional, and administrative data. Core HR is the data layer for this. |
| Registre d'employeur | Employer register | Legal document required by CI Code du Travail. 3 fascicules: personnel, salaries, inspection visas. Core HR generates Fascicule 1. |
| Immatriculation CNPS | CNPS registration | Registration of an employee with the Caisse Nationale de Prévoyance Sociale (CI social security). The registration number is stored in Core HR. |
| Certificat médical d'aptitude | Medical fitness certificate | Doctor's certificate confirming an employee is fit for work. Required in the employee file. Stored as a document attachment. |
| Certificat de travail | Employment certificate | Document issued by the employer at departure, confirming employment dates and position. Mandatory (Art. 16.14 CT 2015). |
| RIB | Bank details | Relevé d'Identité Bancaire — CI banking document identifying an account. Stored as document attachment + structured bank info fields. |
| Avenant | Contract amendment | Modification to an existing employment contract. Stored as a document attachment. Contract lifecycle management belongs to EMPMGT. |
| Personne à charge | Dependent | Person financially dependent on the employee (spouse, children, other). Affects tax (ITS) and social contributions (allocations familiales). |
| Numéro matricule | Employee number | Unique sequential identifier for an employee within a tenant. Format: {PREFIX}-{YEAR}-{MM}-{SEQ}. |
| Fascicule | Section/volume | One of the 3 volumes of the registre d'employeur. Fascicule 1 = personnel, 2 = salaries, 3 = inspection visas. |
This PRD+FSD was produced by the ANALYST personality based on exhaustive interview with the Business Analyst/Product Owner. It serves as the authoritative reference for Core HR module architecture, design, and implementation.
Cross-references: Platform Vision PRD (docs/prd/platform-vision-prd.md) for shared infrastructure, events, data model, and tenant segmentation. Legal research (docs/research/3_validated/core-hr-legal-validated.md) for CI regulatory details.