Story QR-008 :¶
Module d'affectation des employés aux sites : qr-attendance Tranche : QR-T2-002 Contexte de marque : [LES DEUX] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priorité : 8 Dépend de : QR-002 (les sites existent) Peut être développé en parallèle avec : QR-006, QR-007 Ordre de fusion : N'importe quel ordre par rapport à QR-006+ Complexité estimée : S PRD User Stories : N/A — prend en charge US-QR-001 (lecture flexible des sites), US-QR-010 (filtre de site du tableau de bord)
Objectif¶
Créer le modèle d'affectation des employés aux sites qui prend en charge les désignations de sites principaux et secondaires. Lorsqu'un employé scanne un code QR sur un site non principal, l'événement de pointage est enregistré normalement mais signalé comme un scan sur site non principal. Cela permet un filtrage par site sur le tableau de bord et prend en charge les futures fonctionnalités de géorepérage.
Portée du backend¶
Entités et enregistrements¶
EmployeeSiteAssignment :
- id (UUID)
- tenantId (UUID)
- employeeId (UUID)
- siteId (UUID)
- isPrimary (booléen, valeur par défaut true)
- effectiveFrom (LocalDate)
- effectiveTo (LocalDate, nullable)
Migrations Flyway¶
V001_014__attendance_employee_site_assignment.sql :
CREATE TABLE attendance_employee_site_assignment (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
employee_id UUID NOT NULL,
site_id UUID NOT NULL,
is_primary BOOLEAN NOT NULL DEFAULT true,
effective_from DATE NOT NULL,
effective_to DATE,
UNIQUE(tenant_id, employee_id, site_id, effective_from)
);
CREATE INDEX idx_emp_site_tenant ON attendance_employee_site_assignment(tenant_id, employee_id, is_primary);
Couche de référentiel¶
SiteAssignmentRepository
:
- findByTenantIdAndEmployeeId(UUID tenantId, UUID employeeId) — toutes les affectations d'un employé
- findPrimaryByTenantIdAndEmployeeId(UUID tenantId, UUID employeeId) — site principal uniquement
- findBySiteId(UUID tenantId, UUID siteId) — tous les employés affectés à un site
Couche de service¶
SiteAssignmentService
:
- assignEmployeeToSite(AssignEmployeeToSiteRequest) — affecter un employé à un site, en veillant à ce qu'il n'y ait qu'un seul site principal par employé à la fois
- removeAssignment(UUID id) — supprimer une affectation
- listAssignments(UUID tenantId, UUID employeeId) — lister toutes les affectations d'un employé
- Signalement de scan sur un site non principal : lorsqu'un événement d'horloge se produit sur un site non principal, signaler dans DailyAttendance.anomalyDetails
Endpoints API¶
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| POST | /api/v1/qrcontr/site-assignments |
AssignEmployeeToSiteRequest |
ApiResponse<SiteAssignmentResponse> |
HR (P2) |
| GET | /api/v1/qrcontr/employees/{employeeId}/site-assignments |
— | ApiResponse<List<SiteAssignmentResponse>> |
HR, Manager, Employee (own) |
| DELETE | /api/v1/qrcontr/site-assignments/{id} |
— | ApiResponse<Void> |
HR (P2) |
| ### DTOs |
AssignEmployeeToSiteRequest
:
- employeeId (UUID)
- siteId (UUID)
- isPrimary (booléen)
- effectiveFrom (LocalDate)
- effectiveTo (LocalDate, peut être nul)
SiteAssignmentResponse
:
- Tous les champs de l'entité + siteName (chaîne de caractères)
Règles de validation¶
- Un seul site principal par employé à la fois
- Le site doit exister et être actif
effectiveFromne doit pas être nul- Si
effectiveToest fourni, il doit être postérieur àeffectiveFrom
Considérations multi-tenant¶
Toutes les requêtes filtrent par tenant_id.
Les affectations de site entre locataires sont impossibles par conception (les ID de site sont propres à chaque locataire).
Portée du frontend¶
Composants¶
SiteAssignmentPanel
:
- Sur la page de détails du site, lister les employés affectés avec un badge principal
- Ajouter un sélecteur d'employés pour affecter de nouveaux employés
EmployeeSiteList
:
- Sur la page de détails de l'employé, afficher les sites affectés avec un indicateur principal
États de l'interface utilisateur¶
| State | Behavior | French Copy |
|---|---|---|
| Loading | Skeleton rows | — |
| Empty | No assignments | "Aucun employe assigne a ce site." |
| Error | Inline error | "Une erreur est survenue. Reessayez." |
| Offline | Cached data, actions disabled | "Disponible en ligne uniquement" |
| Success | Row added with animation | "Employe assigne au site." |
Comportement adaptatif¶
- 360px : affichage sous forme de liste, fiches de tâches en pleine largeur
- 768px : même mise en page, avec ajout en ligne
- 1024px et plus : affichage sous forme de tableau avec attribution groupée (espace réservé pour Enterprise V2)
Critères d'acceptation¶
AC-001: Assign employee to primary site
Given I am HR
When I assign employee "KONE Aminata" to site "Siege Abidjan" as primary
Then the assignment is saved and the employee's primary site is "Siege Abidjan"
AC-002: Non-primary site scan flagging
Given employee "KONE Aminata" has primary site "Siege Abidjan"
When she scans the QR code at "Entrepot Yopougon" (a non-primary site)
Then the clock event is recorded normally but flagged as a non-primary site scan
OHADA et règles réglementaires¶
Aucune règle spécifique à l'affectation des sites.
Normes et conventions¶
docs/standards/java-Spring-guidelines.mddocs/standards/api-guidelines.mddocs/standards/database-guidelines.md
Exigences de test¶
Tests unitaires¶
- Application de l'unicité primaire : l'attribution d'un deuxième primaire remplace le premier
- Logique de marquage non primaire : un événement d'horloge sur un site non primaire active le drapeau d'anomalie
- Validation : « effectiveTo » avant « effectiveFrom » rejeté, « effectiveFrom » manquant rejeté
Tests d'intégration¶
- POST site-assignment — 201 avec réponse correcte
- GET employee site-assignments — renvoie toutes les affectations avec les noms des sites
- DELETE site-assignment — 200, affectation supprimée
- Contrainte de site principal : le deuxième site principal remplace le premier
- Isolation des tenants : les affectations du tenant A ne sont pas visibles pour le tenant B
Ce que le contrôle qualité va valider¶
- Affecter un employé à un site, vérifier l'affichage du badge principal
- Scanner sur un site non principal, vérifier le signalement dans les registres de présence
- Vérifier que la page de détails de l'employé affiche les sites affectés
Hors du périmètre¶
- Géorepérage (V2)
- Liaison d'appareils (V2)
- Affectation groupée (Enterprise V2)
Définition de « terminé »¶
- [ ] Tous les endpoints backend sont implémentés et renvoient des réponses correctes
- [ ] Tous les composants frontend s'affichent correctement à 360px, 768px et 1024px
- [ ] Les 5 états de l'interface utilisateur sont implémentés (chargement, vide, erreur, hors ligne, succès)
- [ ] Les micro-textes en français correspondent aux spécifications de conception
- [ ] Tous les critères d'acceptation sont satisfaits manuellement
- [ ] Les tests unitaires et les tests d'intégration sont réussis
- [ ] L'isolation multi-tenant est vérifiée
- [ ] Pas de
anyen TypeScript, pas de types bruts en Java - [ ] Les réponses API respectent le format d'enveloppe standard
- [ ] Entrées de piste d'audit pour les modifications d'affectation
- [ ]
./gradlew testest vert - [ ]
./gradlew spotlessApplyest réussi