Aller au contenu

Story CP-019: Country Config: Holidays + Caching + Validation

Module: control-plane Slice: Slice 6b from architecture (split from CP-006) Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 6 (after CP-006) Depends on: CP-006 Estimated complexity: S


Objective

Extend the country configuration engine with public holidays, sector salary grids, Caffeine caching for all country config queries, and country code validation. This slice adds the PublicHoliday and CountrySectorSalaryGrid entities, their endpoints, caching across all CountryConfigService methods (including those from CP-006), and rejects invalid country codes.


Backend Scope

Entities & Records

PublicHoliday entity (platform DB):

Field Type Constraints
id UUID v7 PK
country_code String(2) NOT NULL
year int NOT NULL
date LocalDate NOT NULL
name String NOT NULL

CountrySectorSalaryGrid entity (platform DB):

Field Type Constraints
id UUID v7 PK
country_code String(2) NOT NULL
sector_code String(10) NOT NULL (COM, BTP, IND, SVC, AGR)
sector_name String NOT NULL
category_code String(10) NOT NULL
minimum_salary_monthly BigDecimal NOT NULL
effective_date LocalDate NOT NULL

Sectors: Commerce (COM), BTP, Industrie (IND), Services (SVC), Agriculture (AGR)

Repository Layer

  • PublicHolidayRepository.java — Platform-scoped:
  • findByCountryCodeAndYear(String, int) → List<PublicHoliday>
  • CountrySectorSalaryGridRepository.java — Platform-scoped:
  • findByCountryCodeAndSectorCode(String, String) → List<CountrySectorSalaryGrid>

Service Layer

CountryConfigService.java (extend from CP-006): - getPublicHolidays(String countryCode, int year) → List<PublicHoliday> — NEW method - getSalaryGrids(String countryCode, String sectorCode) → List<CountrySectorSalaryGrid> — NEW method - Add Caffeine caching to ALL methods (TTL: 1 hour, invalidated on update): - getTaxBrackets (from CP-006) — add @Cacheable - getSocialContributions (from CP-006) — add @Cacheable - getPublicHolidays — add @Cacheable - getSalaryGrids — add @Cacheable - Add country code validation: reject any code not in supported list (MVP: only "CI"). Return HTTP 400 with message "Country code not supported" (Code pays non pris en charge).

API Endpoints

Method Path Request Body Response Auth
GET /api/v1/country-config/{countryCode}/holidays/{year} List Any authenticated
GET /api/v1/country-config/{countryCode}/salary-grids?sectorCode={s} List Any authenticated

Admin CRUD endpoints (for platform admin — consumed by Admin Console CP-012):

Method Path Auth
PUT /api/v1/admin/country-config/{countryCode}/holidays/{year} PLATFORM_ADMIN

Validation Rules

  • country_code: valid ISO 3166-1 alpha-2 (MVP: only "CI" accepted). Invalid codes → HTTP 400.
  • year: >= 2020, <= current year + 2
  • sector_code: must be one of COM, BTP, IND, SVC, AGR
  • All monetary fields: BigDecimal, >= 0, zero decimal places (XOF)

Multi-Tenant Considerations

  • Country config is in the platform DB — shared across all tenants
  • NOT tenant-scoped (same CI holidays apply to all CI tenants)
  • Read endpoints accessible to any authenticated user
  • Write endpoints restricted to PLATFORM_ADMIN role
  • Cache is shared across all tenants (reference data is the same)

Flyway Migration

  • V004__create_country_config_holidays_grids.sql — Platform DB: PublicHoliday + CountrySectorSalaryGrid tables + seed CI holidays 2026-2027 + salary grid placeholders

Frontend Scope

No tenant-facing frontend in this slice. Country config is read-only reference data for tenants. The Admin Console (CP-012) provides the editor UI.

Pages & Routes

N/A for tenant frontend. Admin console editor is in CP-012.

UI States (ALL REQUIRED)

N/A — Backend-only slice for tenant side. Admin UI in CP-012.

Responsive Behavior

N/A

Interactions

N/A


Acceptance Criteria

AC-048: Get CI public holidays
Given CI holidays are seeded for 2026
When I call GET /api/v1/country-config/CI/holidays/2026
Then I receive all CI public holidays for 2026

AC-050: Country config caching
Given tax brackets have been fetched once
When the same request is made within 1 hour
Then the response is served from Caffeine cache (no DB query)

AC-051: Invalid country code rejected
Given country code "XX" does not exist
When I call GET /api/v1/country-config/XX/tax-brackets?fiscalYear=2026
Then I receive HTTP 400 with message "Country code not supported"

OHADA & Regulatory Rules

  • CI public holidays: Fixed holidays (Fete du Travail, Fete de l'Independance, etc.) plus variable Islamic holidays. Holiday list must be updatable annually without redeployment.
  • Sector salary grids: CCI defines minimum salaries per category per sector. Placeholder values seeded; final values needed before Payroll.
  • BigDecimal ONLY: All monetary values use BigDecimal. Never double/float for financial data.

Standards & Conventions

  • docs/standards/java-spring-guidelines.md — §Entities, §Caffeine caching, §BigDecimal for financials
  • docs/standards/database-guidelines.md — §Platform DB reference data, §Seed data in migrations
  • docs/standards/api-guidelines.md — §Read-only reference endpoints, §Admin-only write endpoints

Testing Requirements

Unit Tests

  • CountryConfigService: holiday lookup by country + year
  • CountryConfigService: salary grid lookup by country + sector
  • CountryConfigService: cache hit/miss/invalidation (all 4 methods)
  • Validation: invalid country code rejection

Integration Tests

  • GET endpoints for holidays and salary-grids
  • Seed data verification: CI holidays match expected values
  • Cache invalidation on admin update
  • Country code "XX" → 400 (on all endpoints including tax-brackets and social-contributions from CP-006)
  • Authorization: tenant user can read, cannot write (403)

What QA Will Validate

  • N/A for tenant UI (backend-only for tenants)
  • Admin console (CP-012) will validate the editor UI

Out of Scope

  • Admin console editor UI — CP-012
  • Countries other than CI — Post-MVP (architecture supports multi-country from day one)
  • Automatic holiday import API — Backlog OQ-CP-06
  • SYSCOHADA chart of accounts — Seed in migration, full accounting module consumes it later
  • Leave type reference data — Seeded here, detailed in Absence Management PRD

Definition of Done

  • [ ] All backend endpoints implemented and returning correct responses
  • [ ] All frontend pages render correctly at 360px, 768px, 1024px — N/A
  • [ ] All 5 UI states implemented — N/A (backend-only for tenant side)
  • [ ] French micro-copy matches design spec exactly — N/A
  • [ ] All acceptance criteria pass manually
  • [ ] Unit tests written and passing
  • [ ] Integration tests written and passing
  • [ ] Multi-tenant isolation verified — N/A (reference data is shared)
  • [ ] Offline write+sync works — N/A
  • [ ] No TypeScript any — N/A
  • [ ] No Java raw types — all generics explicit
  • [ ] API responses follow standard envelope format
  • [ ] Audit trail entries created for every data mutation — Admin updates to config generate audit entries