openapi: 3.1.0 info: title: Arcadia API description: | Arcadia API in order to abstract corporate metamodel to a proper and stable implemented API. Architecture Clean Architecture, Domain-Driven Design (DDD) & Ports & Adapters (Hexagonale). contact: name: Uwil Engineering Team email: digital@ldc.fr license: name: MIT url: https://opensource.org/licenses/MIT version: 1.0.0 servers: - url: http://127.0.0.1:8000/api/v1 description: Serveur de développement local v1 security: - HmacClientId: [] HmacTimestamp: [] HmacSignature: [] tags: - name: Employees description: Gestion et consultation du référentiel RH des employés. paths: /employees: get: tags: - Employees summary: Liste paginée des employés description: | Retourne la liste paginée des employés du système Arcadia. Prend en charge le filtrage par date de modification (`since`), code établissement (`establishment`), code site (`siteId`), code service (`serviceId`), ainsi que le tri et la pagination HATEOAS. operationId: listEmployees parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Since' - $ref: '#/components/parameters/Establishment' - $ref: '#/components/parameters/SiteId' - $ref: '#/components/parameters/ServiceId' - $ref: '#/components/parameters/SortBy' - $ref: '#/components/parameters/SortDirection' responses: '200': description: Page d'employés récupérée avec succès. content: application/json: schema: $ref: '#/components/schemas/EmployeeListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/UnprocessableEntity' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' /employees/{employeeId}: get: tags: - Employees summary: Détail d'un employé par son identifiant description: | Retourne la fiche détaillée d'un employé spécifié par son matricule public unique. operationId: getEmployee parameters: - $ref: '#/components/parameters/EmployeeIdPath' responses: '200': description: Fiche employé trouvée. content: application/json: schema: $ref: '#/components/schemas/EmployeeItemResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/UnprocessableEntity' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' components: securitySchemes: HmacClientId: type: apiKey in: header name: X-Client-Id description: Identifiant public du client API autorisé. HmacTimestamp: type: apiKey in: header name: X-Timestamp description: Horodatage au format ISO8601 / RFC3339 (tolérance anti-replay ±5 minutes). HmacSignature: type: apiKey in: header name: X-Signature description: Signature HMAC-SHA256 calculée avec la clé secrète partagée. parameters: EmployeeIdPath: name: employeeId in: path required: true description: Matricule public unique de l'employé (7 ou 8 chiffres). schema: type: string pattern: '^\d{7,8}$' example: '01155902' Page: name: page in: query required: false description: Numéro de page (1-based). schema: type: integer minimum: 1 default: 1 example: 1 PageSize: name: pageSize in: query required: false description: Nombre d'éléments par page (max 10000). schema: type: integer minimum: 1 maximum: 10000 default: 25 example: 25 Offset: name: offset in: query required: false description: Décalage d'index pour la pagination basée sur l'offset. schema: type: integer minimum: 0 example: 0 Limit: name: limit in: query required: false description: Nombre maximal d'enregistrements pour la pagination par offset. schema: type: integer minimum: 1 maximum: 10000 example: 25 Since: name: since in: query required: false description: Horodatage au format RFC3339 (borne inférieure sur updatedAt). schema: type: string format: date-time example: '2026-01-01T00:00:00Z' Establishment: name: establishment in: query required: false description: "Filtrer par code établissement (ex: 01, PA, LY)." schema: type: string pattern: '^[\dA-Z]{2,}$' example: '01' SiteId: name: siteId in: query required: false description: "Filtrer par code site (ex: LDCSER, SLELA)." schema: type: string pattern: '^[A-Z]{2,}$' example: 'LDCSER' ServiceId: name: serviceId in: query required: false description: "Filtrer par identifiant de service (ex: 097, 101)." schema: type: string pattern: '^\d{1,}$' example: '097' SortBy: name: sortBy in: query required: false description: Champ d'ordonnancement des employés. schema: type: string enum: - arcadiaId - startDate - endDate - plannedEndDate - createdAt - updatedAt default: arcadiaId example: arcadiaId SortDirection: name: sortDirection in: query required: false description: Sens du tri. schema: type: string enum: - Ascending - Descending default: Ascending example: Ascending responses: BadRequest: description: Erreurs de forme de la requête HTTP (validation FormRequest) (400 Bad Request). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' Unauthorized: description: Échec d'authentification HMAC ou signature invalide (401 Unauthorized). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' Forbidden: description: Client non autorisé à accéder à cette ressource (403 Forbidden). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' NotFound: description: Ressource introuvable (404 Not Found). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' UnprocessableEntity: description: Erreur sémantique ou violation des règles du domaine (422 Unprocessable Entity). content: application/problem+json: schema: $ref: '#/components/schemas/ValidationErrorProblemDetails' TooManyRequests: description: Trop de requêtes envoyées dans un laps de temps donné (429 Too Many Requests). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' headers: Retry-After: description: Le nombre de secondes avant de pouvoir réessayer. schema: type: integer X-RateLimit-Limit: description: La limite de requêtes par minute. schema: type: integer X-RateLimit-Remaining: description: Le nombre de requêtes restantes avant blocage. schema: type: integer InternalServerError: description: Erreur interne du serveur (500 Internal Server Error). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' ServiceUnavailable: description: Service temporairement indisponible (503 Service Unavailable). content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' schemas: Employee: type: object description: Représentation canonique d'un employé dans le métamodèle Arcadia. required: - id - firstName - lastName - establishment - site - service - startDate properties: id: type: string pattern: '^\d{7,8}$' description: Matricule public unique de l'employé. example: '01155902' firstName: type: string description: Prénom de l'employé. example: John lastName: type: string description: Nom de famille de l'employé. example: DOE establishment: type: string pattern: '^[\dA-Z]{2,}$' description: Code de l'établissement d'affectation. example: '01' site: type: string pattern: '^[A-Z]{2,}$' description: Code du site géographique. example: LDCSER service: type: string pattern: '^\d{1,}$' description: Identifiant du service interne. example: '097' startDate: type: string format: date description: Date de prise de poste (YYYY-MM-DD). example: '2024-01-15' endDate: type: - string - 'null' format: date description: Date de fin de contrat effective (optionnelle). example: null plannedEndDate: type: - string - 'null' format: date description: Date de fin de contrat prévue (optionnelle). example: null createdAt: type: - string - 'null' format: date-time description: Date d'enregistrement dans le système. example: '2026-08-11T14:00:00Z' updatedAt: type: - string - 'null' format: date-time description: Date de dernière mise à jour. example: '2026-08-11T14:00:00Z' PaginationLinks: type: object description: Liens de navigation HATEOAS pour la pagination. required: - self - first - last properties: self: type: string format: uri description: Lien vers la page courante. example: 'http://127.0.0.1:8000/api/v1/employees?page=1&pageSize=25' first: type: string format: uri description: Lien vers la première page. example: 'http://127.0.0.1:8000/api/v1/employees?page=1&pageSize=25' prev: type: - string - 'null' format: uri description: Lien vers la page précédente (null si première page). example: null next: type: - string - 'null' format: uri description: Lien vers la page suivante (null si dernière page). example: 'http://127.0.0.1:8000/api/v1/employees?page=2&pageSize=25' last: type: string format: uri description: Lien vers la dernière page. example: 'http://127.0.0.1:8000/api/v1/employees?page=2&pageSize=25' PaginationMeta: type: object description: Métadonnées de pagination. required: - page - pageSize - totalItems - totalPages - links properties: page: type: integer minimum: 1 description: Index de la page courante (1-based). example: 1 pageSize: type: integer minimum: 1 description: Nombre d'éléments par page. example: 25 totalItems: type: integer minimum: 0 description: Nombre total d'éléments correspondant aux filtres. example: 42 totalPages: type: integer minimum: 0 description: Nombre total de pages disponibles. example: 2 links: $ref: '#/components/schemas/PaginationLinks' EmployeeListResponse: type: object description: Enveloppe de réponse pour la liste paginée des employés. required: - employees - pagination properties: employees: type: array description: Collection des employés de la page. items: $ref: '#/components/schemas/Employee' pagination: $ref: '#/components/schemas/PaginationMeta' EmployeeItemResponse: type: object description: Enveloppe de réponse pour le détail d'un employé. required: - employee properties: employee: $ref: '#/components/schemas/Employee' ProblemDetails: type: object description: Format d'erreur standardisé RFC 7807 (Problem Details for HTTP APIs). required: - type - title - status - detail properties: type: type: string format: uri description: URI identifiant le type de problème. example: 'http://127.0.0.1:8000/errors/not-found' title: type: string description: Titre court lisible résumant le problème. example: 'Resource Not Found' status: type: integer description: Code statut HTTP. example: 404 detail: type: string description: Explication humaine détaillée de l'erreur. example: "Employee '9999999' not found." instance: type: - string - 'null' format: uri-reference description: URI de l'endpoint ayant généré l'erreur. example: '/api/v1/employees/9999999' InvalidParamItem: type: object description: Détail d'une erreur de validation sur un paramètre. required: - name - reason properties: name: type: string description: Nom du champ ou paramètre invalide. example: employeeId reason: type: string description: Raison du rejet de validation. example: 'The employeeId pattern must be 7 or 8 digits.' ValidationErrorProblemDetails: type: object description: Format RFC 7807 pour les erreurs de validation HTTP (422 Unprocessable Entity). required: - type - title - status - detail - invalidParams properties: type: type: string format: uri description: URI identifiant l'erreur de validation. example: 'http://127.0.0.1:8000/errors/validation-error' title: type: string description: Titre de l'erreur. example: 'Unprocessable Entity' status: type: integer description: Code HTTP (422). example: 422 detail: type: string description: Message d'ensemble. example: 'The given data was invalid.' invalidParams: type: array description: Liste des paramètres invalides et motifs. items: $ref: '#/components/schemas/InvalidParamItem'