Aller au contenu

Story QR-004: Module Configuration + Overtime Bands + Compliance Onboarding

@assignee: @angeisaac-ui

Module: qr-attendance Slice: QR-T1-003 + QR-T5-006 Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 4 Depends on: QR-001 Can develop concurrently with: QR-002, QR-003, QR-005 Merge order: Before QR-014 (teletravail needs config), QR-018 (overtime needs bands) Estimated complexity: M PRD User Stories: US-QR-013


Objective

Provide HR with a configuration interface for the QR Attendance module: general settings (late tolerance, overtime week start day, auto-close time, remote work limits), CI overtime band configuration (with legally-mandated defaults), per-department tolerance overrides, and a compliance onboarding wizard that records the "délégués du personnel" consultation requirement. The onboarding wizard is a 3-step activation flow: Compliance -> Create Site -> Create Schedule.


Backend Scope

Flyway Migrations

V001_006__attendance_overtime_config.sql:

CREATE TABLE attendance_overtime_config (
    id UUID PRIMARY KEY,
    tenant_id UUID NOT NULL,
    band_code VARCHAR(20) NOT NULL,
    weekly_threshold_start DECIMAL,
    weekly_threshold_end DECIMAL,
    night_start_time TIME,
    night_end_time TIME,
    country_code VARCHAR(3) NOT NULL DEFAULT 'CI',
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
    UNIQUE(tenant_id, band_code, country_code)
);

V001_007__attendance_department_config.sql:

CREATE TABLE attendance_department_config (
    id UUID PRIMARY KEY,
    tenant_id UUID NOT NULL,
    department_id UUID NOT NULL,
    late_tolerance_minutes INTEGER,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
    UNIQUE(tenant_id, department_id)
);

V001_008__attendance_overtime_ci_defaults.sql (seed data):

-- CI overtime defaults (temporarily validated -- TV-QR-002)
-- These are tenant-configurable; inserting as defaults for new tenants
-- Actual insertion happens in ConfigService when module is activated

Entities & Records

OvertimeConfig (tenant DB):

Field Type Constraints
id UUID PK
tenantId UUID NOT NULL
bandCode String NOT NULL (BAND_1, BAND_2, BAND_3, NIGHT, SUNDAY_HOLIDAY)
weeklyThresholdStart BigDecimal Nullable
weeklyThresholdEnd BigDecimal Nullable
nightStartTime LocalTime Nullable
nightEndTime LocalTime Nullable
countryCode String NOT NULL, default "CI"
createdAt OffsetDateTime NOT NULL
updatedAt OffsetDateTime NOT NULL

DepartmentAttendanceConfig (tenant DB):

Field Type Constraints
id UUID PK
tenantId UUID NOT NULL
departmentId UUID NOT NULL, UNIQUE with tenantId
lateToleranceMinutes Integer Nullable
createdAt OffsetDateTime NOT NULL
updatedAt OffsetDateTime NOT NULL

CI Default Overtime Bands:

Band Code weeklyThresholdStart weeklyThresholdEnd nightStartTime nightEndTime
BAND_1 40 46
BAND_2 46 48
BAND_3 48 null (unlimited)
NIGHT 21:00 05:00
SUNDAY_HOLIDAY

DTOs:

public record ModuleConfigResponse(
    UUID id,
    int defaultLateToleranceMinutes,
    short overtimeWeekStartDay,
    int minRemoteWorkAdvanceDays,
    Integer maxRemoteWorkPerWeek,
    Integer maxRemoteWorkPerMonth,
    LocalTime autoCloseTime,
    boolean deleguesConsultationDone,
    LocalDate deleguesConsultationDate,
    UUID deleguesPvDocumentId
) {}

public record UpdateModuleConfigRequest(
    Integer defaultLateToleranceMinutes,
    Short overtimeWeekStartDay,
    Integer minRemoteWorkAdvanceDays,
    Integer maxRemoteWorkPerWeek,
    Integer maxRemoteWorkPerMonth,
    LocalTime autoCloseTime
) {}

public record OvertimeConfigResponse(
    List<OvertimeBandResponse> bands
) {}

public record OvertimeBandResponse(
    String bandCode,
    BigDecimal weeklyThresholdStart,
    BigDecimal weeklyThresholdEnd,
    LocalTime nightStartTime,
    LocalTime nightEndTime,
    String countryCode
) {}

public record UpdateOvertimeConfigRequest(
    @NotEmpty List<OvertimeBandUpdate> bands
) {}

public record OvertimeBandUpdate(
    @NotBlank String bandCode,
    BigDecimal weeklyThresholdStart,
    BigDecimal weeklyThresholdEnd,
    LocalTime nightStartTime,
    LocalTime nightEndTime
) {}

public record DepartmentConfigResponse(
    UUID departmentId,
    Integer lateToleranceMinutes
) {}

public record UpdateDepartmentConfigRequest(
    Integer lateToleranceMinutes
) {}

public record ComplianceAcknowledgementRequest(
    @NotNull boolean consultationDone,
    LocalDate consultationDate,
    UUID pvDocumentId
) {}

public record ComplianceStatusResponse(
    boolean consultationDone,
    LocalDate consultationDate,
    UUID pvDocumentId,
    boolean reminderShown,
    int employeeCount
) {}

Repository Layer

  • OvertimeConfigRepository.java:
  • findByTenantIdAndCountryCode(UUID tenantId, String countryCode) -> List<OvertimeConfig>
  • findByTenantIdAndBandCodeAndCountryCode(UUID tenantId, String bandCode, String countryCode) -> Optional<OvertimeConfig>
  • DepartmentAttendanceConfigRepository.java:
  • findByTenantIdAndDepartmentId(UUID tenantId, UUID departmentId) -> Optional<DepartmentAttendanceConfig>

Service Layer

ConfigService.java: - getModuleConfig(UUID tenantId) -> ModuleConfigResponse — Returns module config. On first access, creates default config with auto-generated 256-bit hex HMAC secret and seeds CI overtime defaults. - updateModuleConfig(UUID tenantId, UpdateModuleConfigRequest) -> ModuleConfigResponse — Partial update of module settings - getOvertimeConfig(UUID tenantId) -> OvertimeConfigResponse — Returns all overtime bands for tenant - updateOvertimeConfig(UUID tenantId, UpdateOvertimeConfigRequest) -> OvertimeConfigResponse — Updates overtime band thresholds/times - getDepartmentConfig(UUID tenantId, UUID departmentId) -> DepartmentConfigResponse — Returns department-specific config - updateDepartmentConfig(UUID tenantId, UUID departmentId, UpdateDepartmentConfigRequest) -> DepartmentConfigResponse — Upserts department tolerance override

ComplianceService.java: - acknowledgeConsultation(UUID tenantId, ComplianceAcknowledgementRequest) -> ComplianceStatusResponse — Records delegues du personnel consultation acknowledgement. Sets delegues_consultation_done, optionally stores date and PV document reference. - getComplianceStatus(UUID tenantId) -> ComplianceStatusResponse — Returns current compliance status including employee count (for 11+ threshold notice).

API Endpoints

Method Path Request Body Response Auth
GET /api/v1/qrcontr/config ApiResponse HR (P2)
PUT /api/v1/qrcontr/config UpdateModuleConfigRequest ApiResponse HR (P2)
GET /api/v1/qrcontr/config/overtime ApiResponse HR (P2)
PUT /api/v1/qrcontr/config/overtime UpdateOvertimeConfigRequest ApiResponse HR (P2)
GET /api/v1/qrcontr/config/departments/{deptId} ApiResponse HR (P2)
PUT /api/v1/qrcontr/config/departments/{deptId} UpdateDepartmentConfigRequest ApiResponse HR (P2)
POST /api/v1/qrcontr/compliance/delegues ComplianceAcknowledgementRequest ApiResponse HR (P2)
GET /api/v1/qrcontr/compliance/delegues ApiResponse HR (P2)

Validation Rules

  • defaultLateToleranceMinutes must be >= 0
  • overtimeWeekStartDay must be 1-7
  • autoCloseTime must be a valid time
  • Overtime band thresholds: weeklyThresholdStart must be < weeklyThresholdEnd when both present
  • CI defaults: BAND_1 (40, 46), BAND_2 (46, 48), BAND_3 (48, null), NIGHT (21:00, 05:00)

Multi-Tenant Considerations

  • All tables include tenant_id column
  • All queries MUST filter by tenant_id
  • CI defaults are seeded per-tenant (not shared) so each tenant can customize independently
  • Department config is optional — if not set, module-level default applies

Frontend Scope

Pages & Routes

  • /qrcontr/config — Module configuration page (HR)
  • /qrcontr/onboarding — 3-step activation wizard

Components

Components follow design spec wireframe 3.12:

  • ModuleConfigPage.tsx — Tabs: General, Overtime, Departments
  • GeneralConfigPanel.tsx — Late tolerance, week start day, auto-close time, remote work limits
  • OvertimeConfigPanel.tsx — Band configuration with CI defaults note
  • DepartmentConfigPanel.tsx — Per-department tolerance override
  • OnboardingWizard.tsx — 3 steps: Compliance -> Create Site -> Create Schedule
  • ComplianceStep.tsx — Legal notice, checkbox "Oui, consultation effectuee", date field, PV upload placeholder

UI States (ALL REQUIRED)

State Behavior French Copy
Loading Skeleton for config panels
Empty Config with CI defaults pre-filled "Configuration par defaut (Cote d'Ivoire)"
Error Field-level validation "La valeur doit etre un nombre positif."
Offline View cached config, edit disabled "Disponible en ligne uniquement"
Success Toast confirmation "Configuration enregistree."

Responsive Behavior

  • 360px (mobile): Stacked config sections, bottom sheet for department config
  • 768px (tablet): Tabbed layout
  • 1024px+ (desktop): Sidebar tabs, inline editing

Interactions

  • Onboarding wizard: Step 1 (Compliance) shows legal notice referencing Art. 16.1. Checkbox + optional date + optional PV upload. Module activates regardless of acknowledgement (not a blocker). Step 2: "Creer votre premier site" (links to site creation). Step 3: "Definir un horaire" (links to schedule creation).
  • 11+ employee threshold: If tenant has fewer than 11 employees, show note: "Cette obligation concerne les entreprises de 11 salaries et plus."
  • Overtime bands: Read-only labels for band codes with editable threshold fields. Note below: "Valeurs par defaut basees sur le Code du Travail ivoirien."
  • Department config: Dropdown to select department, then tolerance field. If empty, displays "Tolerance par defaut du module : {n} minutes"

Acceptance Criteria

AC-001: Compliance notice on module activation
Given I am HR activating the QR Attendance module
When the activation screen loads
Then I see a compliance notice referencing Art. 16.1 Code du Travail and the delegues du personnel consultation requirement

AC-002: Compliance acknowledgement with optional details
Given I see the compliance notice
When I acknowledge it
Then I can check "Oui, consultation effectuee", optionally enter the consultation date, and optionally upload the PV (proces-verbal)

AC-003: Module activation without compliance acknowledgement
Given I do NOT check the consultation box
When I continue
Then the module activates anyway (not a blocker) but the system records that the reminder was shown and not acknowledged

OHADA & Regulatory Rules

  • Art. 16.1 Code du Travail CI: Reglement interieur must be submitted for opinion to delegues du personnel.
  • Delegues du personnel obligation: enterprises with 11+ employees in CI.
  • FR-QR-121: If tenant < 11 employees, show note "Cette obligation concerne les entreprises de 11 salaries et plus."
  • CI overtime defaults (TV-QR-002): BAND_1 40-46h, BAND_2 46-48h, BAND_3 >48h, NIGHT 21:00-05:00

Standards & Conventions

  • docs/standards/java-spring-guidelines.md — Entity records, service layer, validation
  • docs/standards/api-guidelines.md — ApiResponse envelope, PUT semantics
  • docs/standards/database-guidelines.md — Multi-tenant table design, BigDecimal for thresholds
  • docs/standards/react-typescript-guidelines.md — Component structure, form patterns, tabs

Testing Requirements

Unit Tests

  • CI default band creation: 5 bands seeded with correct thresholds
  • Compliance status tracking: acknowledged vs not acknowledged
  • Config validation: lateToleranceMinutes >= 0, overtimeWeekStartDay 1-7
  • Overtime band validation: thresholdStart < thresholdEnd

Integration Tests

  • GET /config -> returns module config (auto-created on first access)
  • PUT /config -> updates config fields
  • GET /config/overtime -> returns 5 CI default bands
  • PUT /config/overtime -> updates band thresholds
  • GET /config/departments/{deptId} -> returns department config
  • PUT /config/departments/{deptId} -> upserts department config
  • POST /compliance/delegues -> records acknowledgement
  • GET /compliance/delegues -> returns compliance status
  • Tenant isolation: tenant A cannot see tenant B's config

What QA Will Validate

  • Onboarding wizard 3-step flow works end-to-end
  • Compliance notice displays Art. 16.1 reference
  • Module activates regardless of compliance acknowledgement
  • 11+ employee threshold note displays when applicable
  • Config page tabs work (General, Overtime, Departments)
  • CI overtime defaults pre-filled
  • Department config override saves correctly
  • All breakpoints (360px, 768px, 1024px) render correctly

Out of Scope

  • Overtime calculation logic (QR-018)
  • Late detection using tolerance (QR-009)
  • Teletravail limits enforcement (QR-014)
  • File upload for PV document (use placeholder — depends on document management)

Definition of Done

  • [ ] All backend endpoints implemented and returning correct responses
  • [ ] All frontend pages render correctly at 360px, 768px, 1024px
  • [ ] All 5 UI states implemented (loading, empty, error, offline, success)
  • [ ] French micro-copy matches design spec exactly
  • [ ] All acceptance criteria pass manually
  • [ ] Unit tests written and passing
  • [ ] Integration tests written and passing
  • [ ] Multi-tenant isolation verified
  • [ ] Offline write+sync: N/A (config is online-only)
  • [ ] No TypeScript any, no Java raw types
  • [ ] API responses follow standard envelope format
  • [ ] Audit trail entries for config changes, compliance acknowledgement