Cross-service BDD scenario catalog (EN/FR)
AI-generated content
This document was generated by an AI assistant. Verify accuracy before relying on the details.
The 140 client-readable scenarios run by the @adb/e2e-api harness against the services' real Hono apps, in English (canonical) and French. The English text is exactly what the .feature files execute; the French column is the translation maintained per service in scenarios/<svc>.json.
Generated by
node tools/scenario-catalog.mjsfrom the@i18n:tags intests/e2e-api/features/*.featureand the per-service EN/FR seeds inadb-doc/docs/concepts/testing/scenarios/<svc>.json. Do not edit by hand — re-run the generator. The@adb/e2e-apitestscenario-i18n.test.mjsfails if a node is untagged, a translation is missing, the English seed drifts from a title, or this page is stale.
Aggregates API — read-side person, contract and part projections for an organization
FR — API Agrégats — projections en lecture des personnes, contrats et lots pour une organisation
Key: @i18n:aggregates · Source: tests/e2e-api/features/aggregates.feature
A person aggregate gathers the bank contracts received by the person
FR — Un agrégat de personne rassemble les contrats bancaires reçus par la personne
Key: @i18n:aggregates.person_with_bank_contracts
- Given a natural person "p1" named "Alice Martin"
- And a "BANK" contract "bank1" from supplier "x" to receiver "p1"
- And a "BANK" contract "bank2" from supplier "x" to receiver "other"
- When they fetch the person aggregate for "p1"
- Then the aggregate request succeeds
- And the aggregate has id "p1"
- And the aggregate bank contracts are "bank1"
The supplier route computes the same person aggregate
FR — La route fournisseur calcule le même agrégat de personne
Key: @i18n:aggregates.supplier_person_route
- Given a natural person "s1" named "Supplier SARL"
- When they fetch the supplier aggregate for "s1"
- Then the aggregate request succeeds
- And the aggregate has id "s1"
A missing person's aggregate is not found, as on the JVM
FR — L'agrégat d'une personne introuvable renvoie une erreur introuvable, comme sur la JVM
Key: @i18n:aggregates.missing_person_is_null
- When they fetch the person aggregate for "ghost"
- Then the JVM's not-found error names "ghost"
A rental contract aggregate resolves its parties, parts and tenant bank accounts
FR — Un agrégat de contrat de location résout ses parties, ses lots et les comptes bancaires du locataire
Key: @i18n:aggregates.contract_resolves_parties_and_parts
- Given a natural person "owner1" named "Owner"
- And a natural person "tenant1" named "Tenant"
- And a building "b1" named "Block A"
- And building "b1" has the primary postal address "12 rue des Lilas", "75001", "Paris"
- And a unit "u1" under building "b1"
- And a "RENTAL" contract "rc1" from supplier "owner1" to receiver "tenant1" on part "u1"
- And a "BANK" contract "bank-t" from supplier "x" to receiver "tenant1"
- When they fetch the contract aggregate for "rc1"
- Then the aggregate request succeeds
- And the aggregate supplier is named "Owner"
- And the aggregate receiver is named "Tenant"
- And the aggregate first related part carries the address "12 rue des Lilas , 75001 Paris"
- And the aggregate tenant bank contracts are "bank-t"
- And the aggregate contract type is "RentalContract"
- And the aggregate concrete type is "RENTAL"
A rental contract aggregate ships JVM-shaped dates, a current date and filtered rent amounts
FR — Un agrégat de contrat de location renvoie des dates au format JVM, une date du jour et des loyers filtrés
Key: @i18n:aggregates.contract_dates_and_rent_amounts
- Given a natural person "ownerz" named "Owner Z"
- And a natural person "tenantz" named "Tenant Z"
- And a "RENTAL" contract "rcz" from supplier "ownerz" to receiver "tenantz" beginning "2021-09-30T22:00:00.000Z" and ending "2024-11-20T23:00:00.000Z"
- When they fetch the contract aggregate for "rcz"
- Then the aggregate request succeeds
- And the aggregate date "begin" is "01/10/2021"
- And the aggregate date "end" is "21/11/2024"
- And the aggregate date "initialCallForRentDate" is "2021-10-01"
- And the aggregate carries a current date
- And the aggregate rent amount event types are "CFR_RENT"
- And the first aggregate rent amount is effective "2021-10-01" and priced in "QUANTITY.EURO"
A rental contract aggregate computes its payment total and its fees with VAT from the stored amounts
FR — Un agrégat de contrat de location calcule son total à payer et ses honoraires TTC à partir des montants enregistrés
Key: @i18n:aggregates.lease_money_members
- Given a natural person "ownerm" named "Owner M"
- And a natural person "tenantm" named "Tenant M"
- And a "RENTAL" contract "rcfee" from supplier "ownerm" to receiver "tenantm" with a rent of "800" and charges of "50.5" euros
- And contract "rcfee" charges a landlord mediation fee of "33.33" euros
- When they fetch the contract aggregate for "rcfee"
- Then the aggregate request succeeds
- And the aggregate amount "paymentTotal" is "850.5" euros
- And the aggregate amount "rentalMediationLandlordFeesWithVatCalc" is "40" euros
- And the aggregate amount "rentalLandlordFeesTotalWithoutVatCalc" is "33.33" euros
- And the aggregate amount "rentalLandlordFeesTotalWithVatCalc" is "40" euros
An unknown contract id is reported as not found
FR — Un identifiant de contrat inconnu est signalé comme introuvable
Key: @i18n:aggregates.missing_contract_is_404
- When they fetch the contract aggregate for "missing"
- Then the aggregate request is not found
A unit aggregate resolves its parent building, related contracts and people
FR — Un agrégat de lot résout son bâtiment parent, ses contrats liés et les personnes associées
Key: @i18n:aggregates.part_resolves_parent_and_contracts
- Given a building "b1" named "Block A"
- And a unit "u1" under building "b1"
- And a natural person "ten1" named "Tenant One"
- And a "RENTAL" contract "c1" from supplier "owner1" to receiver "ten1" on part "u1"
- When they fetch the part aggregate for "u1"
- Then the aggregate request succeeds
- And the aggregate has id "u1"
- And the aggregate parent has id "b1"
- And the aggregate related contracts are "c1"
- And the aggregate related persons include "Tenant One"
A person with no contracts still yields a fully shaped, empty aggregate
FR — Une personne sans contrat produit tout de même un agrégat complet mais vide
Key: @i18n:aggregates.person_without_contracts_is_empty
- Given a natural person "lone1" named "Lonely Lucie"
- When they fetch the person aggregate for "lone1"
- Then the aggregate request succeeds
- And the aggregate has id "lone1"
- And the aggregate has no bank contracts
- And the aggregate has no active rental allowance contract
A rental contract aggregate resolves every related unit and its parent building
FR — Un agrégat de contrat de location résout chaque lot lié et son bâtiment parent
Key: @i18n:aggregates.contract_resolves_multiple_parts
- Given a natural person "owner2" named "Owner Two"
- And a natural person "tenant2" named "Tenant Two"
- And a building "bm" named "Block M"
- And building "bm" has the primary postal address "3 avenue Foch", "69006", "Lyon"
- And a unit "um1" under building "bm"
- And a unit "um2" under building "bm"
- And a "RENTAL" contract "rcm" from supplier "owner2" to receiver "tenant2" on parts "um1,um2"
- When they fetch the contract aggregate for "rcm"
- Then the aggregate request succeeds
- And the aggregate related parts are "um1,um2"
- And every aggregate related part carries the address "3 avenue Foch , 69006 Lyon"
A rental-delegate contract files the receiver bank accounts under the owner side and resolves no parts
FR — Un contrat de délégation de gestion classe les comptes bancaires du receveur du côté propriétaire et ne résout aucun lot
Key: @i18n:aggregates.rental_delegate_resolves_owner_bank
- Given a natural person "deleg1" named "Delegate"
- And a natural person "ownerd" named "Owner D"
- And a building "bd" named "Block D"
- And a unit "ud" under building "bd"
- And a "RENTAL_DELEGATE" contract "rd1" from supplier "deleg1" to receiver "ownerd" on part "ud"
- And a "BANK" contract "bank-d" from supplier "x" to receiver "ownerd"
- When they fetch the contract aggregate for "rd1"
- Then the aggregate request succeeds
- And the aggregate owner bank contracts are "bank-d"
- And the aggregate has no tenant bank contracts
- And the aggregate has no related parts
- And the aggregate contract type is "RentalDelegateContract"
- And the aggregate concrete type is "RENTAL_DELEGATE"
A top-level building aggregate exposes no parent and an empty contract graph
FR — Un agrégat de bâtiment de premier niveau n'expose aucun parent et un graphe de contrats vide
Key: @i18n:aggregates.top_level_building_has_no_parent
- Given a building "btop" named "Standalone"
- When they fetch the part aggregate for "btop"
- Then the aggregate request succeeds
- And the aggregate has id "btop"
- And the aggregate has no parent
- And the aggregate related contracts are empty
- And the aggregate related persons are empty
An unknown part id is reported as not found
FR — Un identifiant de lot inconnu est signalé comme introuvable
Key: @i18n:aggregates.missing_part_is_404
- When they fetch the part aggregate for "no-such-part"
- Then the aggregate request is not found
Public API — what an external project may do through the one public door
FR — API publique — ce qu'un projet externe peut faire par l'unique porte publique
Key: @i18n:api · Source: tests/e2e-api/features/api.feature
A tenant reads their own tickets through the public API, while the organization's ticket search stays refused to them
FR — Un locataire consulte ses propres tickets via l'API publique, tandis que la recherche des tickets de l'organisation lui reste refusée
Key: @i18n:api.tenant_reads_tickets
- Given the caller is a signed-in tenant
- And a person record exists for the tenant's email
- And an incident ticket "Leaking tap in the bathroom" was declared for the tenant
- When they list their own tickets
- Then the request succeeds
- And the ticket results include "Leaking tap in the bathroom"
- And the ticket results do not include "Water leak in the kitchen"
- And the tickets service saw the tenant route under the gateway's service identity
- When they search the tickets for "leak"
- Then the tickets service refuses it for want of the scope "tickets.list"
A tenant reads their own person record through the public API
FR — Un locataire consulte sa propre fiche personne via l'API publique
Key: @i18n:api.tenant_reads_own_record
- Given the caller is a signed-in tenant
- And a person record exists for the tenant's email
- When they read their own record
- Then the request succeeds
- And the record carries the tenant's name
A tenant declares an incident on their own tickets through the public API, while a declaration on the organization's tickets stays refused to them
FR — Un locataire déclare un incident sur ses propres tickets via l'API publique, tandis qu'une déclaration sur les tickets de l'organisation lui reste refusée
Key: @i18n:api.tenant_creates_incident
- Given the caller is a signed-in tenant
- And a person record exists for the tenant's email
- When they declare an incident "Something filed on the organization"
- Then the tickets service refuses it for want of the scope "tickets.incidents.create"
- And no ticket "Something filed on the organization" was stored
- When they declare an incident "Broken boiler in flat 3" on their own tickets
- Then the ticket is created
- And the new ticket is open
- And the new ticket names the tenant
- And the tickets service saw the tenant route under the gateway's service identity
A technical client's ticket search for the organization it was granted passes the public door and is refused by the tickets service
FR — La recherche de tickets d'un client technique pour l'organisation qui lui a été accordée franchit la porte publique et est refusée par le service tickets
Key: @i18n:api.client_reads_tickets
- Given the caller is the technical client
- When they search the tickets for "leak"
- Then the tickets service refuses it for want of the scope "tickets.list"
A technical client cannot create a ticket
FR — Un client technique ne peut pas créer de ticket
Key: @i18n:api.client_cannot_create_ticket
- Given the caller is the technical client
- When they declare an incident "Something they should not file"
- Then the request is forbidden because the endpoint is reserved for end users
A technical client must name the organization it acts for
FR — Un client technique doit nommer l'organisation pour laquelle il agit
Key: @i18n:api.client_must_name_its_organization
- Given the caller is the technical client
- When they search the tickets for "leak" without naming an organization
- Then the request is forbidden because no organization was named
A technical client is refused an organization it was not granted
FR — Un client technique se voit refuser une organisation qui ne lui a pas été accordée
Key: @i18n:api.client_refused_other_organization
- Given the caller is the technical client
- When they search the tickets of organization "org-999"
- Then the request is forbidden because that organization was not granted
A tenant finds the ticket they declared, by its identifier, among their own tickets through the public API, while the read by identifier stays refused to them
FR — Un locataire retrouve le ticket qu'il a déclaré, par son identifiant, parmi ses propres tickets via l'API publique, tandis que la lecture par identifiant lui reste refusée
Key: @i18n:api.tenant_reads_one_ticket
- Given the caller is a signed-in tenant
- And a person record exists for the tenant's email
- When they declare an incident "Broken boiler in flat 3" on their own tickets
- And they list their own tickets
- Then the ticket they declared is among their own tickets, with the subject "Broken boiler in flat 3"
- When they read the ticket they declared by its identifier
- Then the tickets service refuses it for want of the scope "tickets.read"
A tenant cannot read another tenant's tickets through the public API
FR — Un locataire ne peut pas consulter les tickets d'un autre locataire via l'API publique
Key: @i18n:api.tenant_cannot_read_another_tenants_tickets
- Given the caller is a signed-in tenant
- And a person record exists for the tenant's email
- And an incident ticket "Noisy neighbour upstairs" was declared for another tenant
- When they list the tickets of that other tenant
- Then the request is forbidden because they may only reach their own tickets
- And the tickets service was not called
An identifier that is not a ticket identifier reaches nothing
FR — Un identifiant qui n'est pas un identifiant de ticket n'atteint rien
Key: @i18n:api.ticket_identifier_must_be_an_object_id
- Given the caller is a signed-in tenant
- When they call "/tickets/not-an-object-id"
- Then the route is not found
- When they call "/tickets/incidents/not-an-object-id"
- Then the route is not found
- When they call "/tickets/not-an-object-id/events"
- Then the route is not found
The tickets service's own literal routes are not part of the public surface
FR — Les routes littérales propres au service tickets ne font pas partie de la surface publique
Key: @i18n:api.tickets_service_literals_are_not_public
- Given the caller is a signed-in tenant
- When they call "/tickets/info"
- Then the route is not found
- When they call "/tickets/delegatees"
- Then the route is not found
- When they call "/tickets/incidents/common"
- Then the route is not found
A route that is not on the allowlist does not exist
FR — Une route absente de la liste d'autorisation n'existe pas
Key: @i18n:api.unlisted_route_is_not_found
- Given the caller is a signed-in tenant
- When they call "/files/some-document"
- Then the route is not found
- When they call "/persons/tenants"
- Then the route is not found
A caller with no token is refused at the door
FR — Un appelant sans jeton est refusé à la porte
Key: @i18n:api.anonymous_is_refused
- Given the caller has no token
- When they search the tickets for "leak"
- Then the request is unauthorized
An agency user reads any tenant's rented parts through the first-party tier
FR — Un utilisateur d'agence consulte les lots loués de n'importe quel locataire via le palier first-party
Key: @i18n:api.first_party_reads_any_tenants_parts
- Given the caller is an agency user in adb-ui
- When they call "/contracts/parts/tenants/someone-else"
- Then the request succeeds
- And the contracts service saw the path "/contracts/parts/tenants/someone-else"
- And no ownership lookup was made
An agency user reaches /parts, which the public tier does not have
FR — Un utilisateur d'agence atteint /parts, que le palier public ne possède pas
Key: @i18n:api.first_party_reaches_parts
- Given the caller is an agency user in adb-ui
- When they register a property named "Résidence du Port"
- Then the part is created
- When they search the parts for "Port"
- Then the part results include "Résidence du Port"
A tenant on the public tier still gets 404 on /parts
FR — Un locataire sur le palier public obtient toujours un 404 sur /parts
Key: @i18n:api.public_tier_has_no_parts
- Given the caller is a signed-in tenant
- When they call "/parts"
- Then the route is not found
Files API — storing document metadata and serving downloads for an organization
FR — API Fichiers — stocker les métadonnées de documents et servir les téléchargements pour une organisation
Key: @i18n:files · Source: tests/e2e-api/features/files.feature
An agency registers file metadata and finds it again
FR — Une agence enregistre les métadonnées d'un fichier et les retrouve
Key: @i18n:files.register_and_refetch_metadata
- When they register metadata for a "facture-2024-03.pdf" invoice on asset "asset-1"
- Then the file metadata is created
- And the saved metadata belongs to organization "org-88"
- When they fetch that file metadata by id
- Then the returned metadata is for file "facture-2024-03.pdf"
Uploaded files are searchable within the agency's organization
FR — Les fichiers téléversés sont recherchables au sein de l'organisation de l'agence
Key: @i18n:files.search_metadata_in_org
- Given an uploaded file "lease-A.pdf" on asset "asset-2"
- And an uploaded file "lease-B.pdf" on asset "asset-2"
- When they search the file metadata for asset "asset-2"
- Then the metadata results include "lease-A.pdf"
- And the metadata results include "lease-B.pdf"
- And the metadata result total is 2
An agency presigns a direct upload to storage
FR — Une agence présigne un téléversement direct vers le stockage
Key: @i18n:files.presign_upload
- When they ask for an upload link for a "application/pdf" file
- Then the request succeeds
- And the response carries a signed upload URL
Downloading a stored file returns the file itself
FR — Le téléchargement d'un fichier stocké renvoie le fichier lui-même
Key: @i18n:files.download_bytes
- Given an uploaded file "diagnostic-dpe.pdf" on asset "asset-3"
- When they download that file
- Then the download returns the stored file bytes
An agency replaces the tags on a file
FR — Une agence remplace les étiquettes d'un fichier
Key: @i18n:files.replace_tags
- Given an uploaded file "mandat-sepa.pdf" on asset "asset-4"
- When they replace the tags of that file with "SIGNED"
- Then the request succeeds
- And the file is tagged "SIGNED"
An agency cancels the files attached to an asset
FR — Une agence annule les fichiers rattachés à un bien
Key: @i18n:files.cancel_files_for_target
- Given an uploaded file "old-dpe.pdf" on asset "asset-5"
- When they cancel the files of asset "asset-5"
- Then the request succeeds
- And the cancelled file is tagged "CANCELED"
An agency attaches a file to an incident ticket and lists it back
FR — Une agence attache un fichier à un ticket d'incident et le liste
Key: @i18n:files.attach_and_list_ticket_files
- When they attach a "devis-travaux.pdf" file to incident ticket "ticket-9"
- Then the file metadata is created
- Given an uploaded file on incident ticket "ticket-9"
- When they list the files of incident ticket "ticket-9"
- Then the metadata results include "ticket-attachment.pdf"
Energy diagnostics are summarised per asset
FR — Les diagnostics énergétiques sont synthétisés par bien
Key: @i18n:files.diagnostics_per_target
- Given a DPE energy diagnostic of "120.5" on asset "asset-6"
- And a DPE greenhouse-gas diagnostic of "30" on asset "asset-6"
- When they read the diagnostics for asset "asset-6"
- Then the energy diagnostic for asset "asset-6" is 120.5
- And the greenhouse-gas diagnostic for asset "asset-6" is 30
Fetching metadata for an unknown file id returns not found
FR — La récupération des métadonnées d'un identifiant de fichier inconnu renvoie introuvable
Key: @i18n:files.fetch_unknown_metadata_404
- When they fetch the file metadata for unknown id "no-such-file"
- Then the metadata is reported as not found
Downloading a missing or not-yet-uploaded file fails without a redirect
FR — Le téléchargement d'un fichier absent ou non encore téléversé échoue sans redirection
Key: @i18n:files.download_unknown_or_unuploaded
- When they download the unknown file "no-such-file"
- Then the download is reported as not found
- Given a metadata-only file "lease-draft.pdf" on asset "asset-7" with no stored blob
- When they download that metadata-only file
- Then the download is rejected because the blob is not uploaded yet
An agency deletes a person's document, and deleting it again is a no-op
FR — Une agence supprime le document d'une personne, et le supprimer à nouveau est sans effet
Key: @i18n:files.delete_person_document
- Given an uploaded file "rc-augustine.xlsx" on person "person-1"
- When they delete that person document
- Then the document is deleted
- When they delete the unknown file "no-such-file"
- Then nothing is deleted
Reading file metadata without an active organization is rejected
FR — La lecture des métadonnées d'un fichier sans organisation active est rejetée
Key: @i18n:files.requires_active_organization
- Given the agency has no active organization
- When they fetch the file metadata for unknown id "any-file"
- Then the request is rejected for lack of an organization scope
Listing and downloading files for a ticket that has none returns nothing
FR — Lister et télécharger les fichiers d'un ticket qui n'en a aucun ne renvoie rien
Key: @i18n:files.ticket_files_not_found_paths
- When they list the files of damage ticket "ticket-empty"
- Then the metadata page is reported as empty
- When they download ticket "ticket-empty" file "no-such-file"
- Then the download is reported as not found
An agency builds a browser POST upload policy for a SEPA mandate
FR — Une agence construit une politique de téléversement POST navigateur pour un mandat SEPA
Key: @i18n:files.presign_browser_upload_policy
- When they ask for a browser upload policy for a "application/pdf" file on SEPA mandate "mandate-1"
- Then the request succeeds
- And the response carries a signed POST upload policy
Notifications API — the HTTP surface of the queue-consumer notifications Worker
FR — API Notifications — la surface HTTP du Worker notifications consommateur de files
Key: @i18n:notifications · Source: tests/e2e-api/features/notifications.feature
The notifications worker answers its liveness probe
FR — Le worker notifications répond à sa sonde de vivacité
Key: @i18n:notifications.liveness_probe
- When a monitor calls the health endpoint
- Then the request succeeds
- And the worker reports itself as "adb-notifications"
The notifications worker serves its OpenAPI contract
FR — Le worker notifications expose son contrat OpenAPI
Key: @i18n:notifications.openapi_served
- When a tool fetches the OpenAPI document
- Then the request succeeds
- And the document is an OpenAPI 3.x contract
- And the contract is titled for the "Notifications" service
- And the contract documents the "/healthz" endpoint
Every documented endpoint resolves to a real route
FR — Chaque point d'accès documenté correspond à une route réelle
Key: @i18n:notifications.documented_endpoints_resolve
- When a tool fetches the OpenAPI document
- Then every documented endpoint resolves to a real route
The notifications worker serves a browsable Swagger UI
FR — Le worker notifications expose une interface Swagger navigable
Key: @i18n:notifications.swagger_ui_served
- When a developer opens the API docs page
- Then the request succeeds
- And an HTML page mentioning "swagger-ui" is returned
There is no notification CRUD over HTTP — the worker consumes the message bus
FR — Il n'y a pas de CRUD de notification en HTTP — le worker consomme le bus de messages
Key: @i18n:notifications.no_http_crud_surface
- When a client requests "/notifications" over HTTP
- Then the request is not found
- And the response points to the message bus
Reading a single notification by id is not found — there is no read route
FR — La lecture d'une notification par identifiant est introuvable — il n'y a pas de route de lecture
Key: @i18n:notifications.unknown_notification_read_not_found
- When a client requests "/notifications/ntf-does-not-exist" over HTTP
- Then the request is not found
- And the response points to the message bus
A recorded notification definition has no HTTP read surface — the config is not served
FR — Une définition de notification enregistrée n'a pas de surface de lecture HTTP — la configuration n'est pas exposée
Key: @i18n:notifications.definition_config_has_no_http_read
- Given a notification definition is recorded for the certificate-expired kind
- Then the recorded definition is in the read model
- When a client requests "/notification-definitions/CERTIFICATE_EXPIRED" over HTTP
- Then the request is not found
- And the response points to the message bus
A non-GET call on the liveness probe falls through to the not-found catch-all
FR — Un appel non-GET sur la sonde de vivacité bascule vers le gestionnaire d'absence générique
Key: @i18n:notifications.liveness_probe_rejects_non_get
- When a client sends a "POST" to "/healthz" over HTTP
- Then the request is not found
- And the response points to the message bus
Posting a notification is not found — the worker has no write route, it consumes the bus
FR — L'envoi d'une notification est introuvable — le worker n'a pas de route d'écriture, il consomme le bus
Key: @i18n:notifications.creating_a_notification_is_not_found
- When a client sends a "POST" to "/notifications" over HTTP
- Then the request is not found
- And the response points to the message bus
Parts API — building the property → unit hierarchy for an organization
FR — API Lots — construire la hiérarchie propriété → lot pour une organisation
Key: @i18n:parts · Source: tests/e2e-api/features/parts.feature
An agency builds a property, a building and a unit
FR — Une agence crée une propriété, un bâtiment et un lot
Key: @i18n:parts.build_hierarchy
- When they create a property named "Résidence Les Lilas"
- Then the part is created
- And the saved part belongs to organization "org-77"
- When they add a building named "Bâtiment A" to that property
- Then the part is created
- When they add a unit named "Lot 12 — T3" to that building
- Then the part is created
- When they fetch that part by id
- Then the part named "Lot 12 — T3" is returned
A part's postal address is stored the way the JVM stores it
FR — L'adresse postale d'un lot est stockée telle que la JVM la stocke
Key: @i18n:parts.addresses_are_stored_in_the_entity_shape
- When they create a property named "Villa Aurélia" addressed "12 avenue des Pins" in "Nice"
- Then the part is created
- And the stored part holds one entity-shaped postal address in "Nice"
- And the stored part nature is the bare code "PART_NATURE.PROPERTY"
- When they fetch that part by id
- Then the returned part exposes the postal address in "Nice"
- When they add a unit named "Lot 7" sharing that property's address
- Then the part is created
- And the stored unit holds only the parent's primary address id
The units of a building are listed back
FR — Les lots d'un bâtiment sont listés
Key: @i18n:parts.list_units_of_building
- When they create a property named "Le Clos Fleuri"
- And they add a building named "Bâtiment B" to that property
- And they add a unit named "Lot 1" to that building
- And they add a unit named "Lot 2" to that building
- When they list the units of that building
- Then the part list includes "Lot 1"
- And the part list includes "Lot 2"
- And the part list count is 2
Parts are searchable within the agency's organization
FR — Les lots sont recherchables au sein de l'organisation de l'agence
Key: @i18n:parts.search_in_org
- When they create a property named "Villa Marius"
- And they create a property named "Villa Doria"
- And they search parts for "Doria"
- Then the part results include "Villa Doria"
- And the part results are SearchResult projections
- And the part result total is 1
An agency edits a part's common information
FR — Une agence modifie les informations communes d'un lot
Key: @i18n:parts.patch_common_section
- When they create a property named "Maison Bleue"
- And they patch the "common" section of that part to name "Maison Repeinte"
- Then the request succeeds
- And the returned section has name "Maison Repeinte"
An agency opens a sale, finds it again and refines its basic information
FR — Une agence ouvre une vente, la retrouve et affine ses informations de base
Key: @i18n:parts.register_search_and_refine_sale
- When they open a sale titled "Vente Villa Rose"
- Then the sale is created
- And the saved sale belongs to organization "org-77"
- When they fetch that sale by id
- Then the sale titled "Vente Villa Rose" is returned
- When they search sales for "Villa Rose"
- Then the sale results include "Vente Villa Rose"
- And the sale result total is 1
- When they patch the "basic-information" section of that sale to title "Vente Villa Rose — révisée"
- Then the request succeeds
- And the returned sale section has title "Vente Villa Rose — révisée"
An agency records, lists and removes a charge on a unit
FR — Une agence enregistre, liste et supprime une charge sur un lot
Key: @i18n:parts.charges_lifecycle_for_a_part
- When they create a property named "Le Patio"
- And they record a charge titled "Électricité parties communes" on that part
- Then the charge is created
- When they list the charges of that part
- Then the charge list includes "Électricité parties communes"
- And the charge list count is 1
- When they delete that charge
- Then the request succeeds
- When they list the charges of that part
- And the charge list count is 0
An agency stores an asset record on a part and reads it back by type
FR — Une agence enregistre un équipement sur un lot et le relit par type
Key: @i18n:parts.asset_upsert_and_read_by_type
- When they create a property named "Le Belvédère"
- And they upsert a "VALUATION.PURCHASE_VALUATION" asset on that part
- Then the request succeeds
- When they fetch the "VALUATION.PURCHASE_VALUATION" asset of that part
- Then the asset of category "VALUATION.PURCHASE_VALUATION" is returned
- When they list the assets of that part
- Then the asset list includes the "VALUATION.PURCHASE_VALUATION" category
- And the asset list renders the valuation grid
An agency adds a budget line and sees the version surface for the year
FR — Une agence ajoute une ligne de budget et voit les versions de l'année
Key: @i18n:parts.budget_line_create_and_versions
- When they create a property named "Le Hameau"
- And they add a budget line to budget "budget-2026" of that part for year 2026 version 1
- Then the budget line is created
- When they fetch that budget line
- Then the current budget line is returned
- When they list the budget versions of that part
- Then the budget versions include year 2026
A local part search returns a page without a total
FR — Une recherche locale de lots renvoie une page sans total
Key: @i18n:parts.search_local_returns_a_page
- When they create a property named "Villa Aurore"
- And they create a property named "Villa Aurélie"
- And they run a local parts search for "Aurore"
- Then the local part results include "Villa Aurore"
- And the local part results exclude "Villa Aurélie"
- And the local part page metadata is present
GET parts info answers the module info, not a part read
FR — GET parts info renvoie les informations du module, et non la lecture d'un lot
Key: @i18n:parts.module_info_is_shadowed_by_part_id_lookup
- When they fetch the module info
- Then the request succeeds
- And the module info names "adb-parts"
Creating a part without an active organization currently surfaces a server error
FR — Créer un lot sans organisation active provoque actuellement une erreur serveur
Key: @i18n:parts.create_without_org_currently_surfaces_500
- Given an agency with no active organization
- When they create a property named "Lot Orphelin"
- Then the request fails with a server error
Fetching a part that does not exist is not found, as on the JVM
FR — Récupérer un lot inexistant renvoie une erreur introuvable, comme sur la JVM
Key: @i18n:parts.fetch_unknown_part_returns_an_empty_envelope
- When they fetch the part with id "part-does-not-exist"
- Then the JVM's not-found error names "part-does-not-exist"
Fetching a sale that does not exist is not found, as on the JVM
FR — Récupérer une vente inexistante renvoie une erreur introuvable, comme sur la JVM
Key: @i18n:parts.fetch_unknown_sale_returns_an_empty_envelope
- When they fetch the sale with id "sale-does-not-exist"
- Then the JVM's not-found error names "sale-does-not-exist"
Deleting a charge that was never recorded is idempotent
FR — Supprimer une charge jamais enregistrée est idempotent
Key: @i18n:parts.deleting_an_unrecorded_charge_is_idempotent
- When they create a property named "Le Square"
- And they delete the charge with id "000000000000000000000000" from that part
- Then the request succeeds
- And an empty charge envelope is returned
- When they list the charges of that part
- Then the charge list count is 0
An agency fills in every sale sub-section and reads each one back
FR — Une agence renseigne chaque sous-section de vente et relit chacune d'elles
Key: @i18n:parts.sale_sub_sections_round_trip
- When they open a sale titled "Vente Le Domaine"
- And they patch the "financing-information" section of that sale to "commissionAmount" "12500"
- Then the request succeeds
- When they fetch the "financing-information" section of that sale
- Then the returned sale section has "commissionAmount" "12500"
- When they patch the "agency-details" section of that sale to "name" "Agence Centrale"
- And they fetch the "agency-details" section of that sale
- Then the returned sale section has "name" "Agence Centrale"
- When they patch the "buyer-details" section of that sale to "name" "Jean Dupont"
- And they fetch the "buyer-details" section of that sale
- Then the returned sale section has "name" "Jean Dupont"
- When they patch the "notarial-office-details" section of that sale to "name" "Étude Martin"
- And they fetch the "notarial-office-details" section of that sale
- Then the returned sale section has "name" "Étude Martin"
- When they patch the "dates" section of that sale to "sellingDecisionDate" "2026-01-15"
- And they fetch the "dates" section of that sale
- Then the returned sale section has "sellingDecisionDate" "2026-01-15"
An agency sells a unit and the sale information is persisted on the part
FR — Une agence vend un lot et les informations de vente sont enregistrées sur le lot
Key: @i18n:parts.sell_a_unit_records_sale_information
- When they create a property named "Le Manoir"
- And they sell that part with selling date "2026-03-31"
- Then the request succeeds
- And the returned part carries the selling date "2026-03-31"
- When they fetch that part by id
- Then the part carries the selling date "2026-03-31"
An agency builds a co-property building and lists its child units back
FR — Une agence crée un immeuble en copropriété et liste ses lots enfants
Key: @i18n:parts.co_building_children_listing
- When they create a property named "Copropriété Le Parc"
- And they add a building named "Bâtiment Central" to that property
- And they add a unit named "Lot A" to that building
- And they add a unit named "Lot B" to that building
- When they list the children of that building
- Then the part list includes "Lot A"
- And the part list includes "Lot B"
- And the part list count is 2
Persons API — managing owners and tenants for an organization
FR — API Personnes — gérer les propriétaires et locataires d'une organisation
Key: @i18n:persons · Source: tests/e2e-api/features/persons.feature
A representative registers an owner and finds it again
FR — Un représentant enregistre un propriétaire et le retrouve
Key: @i18n:persons.register_and_refetch_owner
- When they create an owner named "Compagnie Dupont"
- Then the request succeeds
- And the saved person belongs to organization "org-42"
- When they fetch that person by id
- Then the person named "Compagnie Dupont" is returned
Owners are searchable within the representative's organization
FR — Les propriétaires sont recherchables au sein de l'organisation du représentant
Key: @i18n:persons.search_owners_in_org
- When they create an owner named "Alice Martin"
- And they create an owner named "Bob Durant"
- And they search persons for "Alice"
- Then the results include "Alice Martin"
- And the result count is 1
A tenant is created and scoped to the organization
FR — Un locataire est créé et rattaché à l'organisation
Key: @i18n:persons.create_tenant_scoped
- When they create a tenant named "Tom Tenant"
- Then the request succeeds
- And the saved person belongs to organization "org-42"
Creating a person without an active organization is refused
FR — La création d'une personne sans organisation active est refusée
Key: @i18n:persons.refuse_create_without_org
- Given a representative without an active organization
- When they create an owner named "Orphan Owner"
- Then the request is rejected as a bad request
A supplier is created and scoped to the organization
FR — Un fournisseur est créé et rattaché à l'organisation
Key: @i18n:persons.create_supplier_scoped
- When they create a supplier named "ACME Plomberie"
- Then the request succeeds
- And the saved person belongs to organization "org-42"
- When they fetch that person by id
- Then the person named "ACME Plomberie" is returned
An owner registered with an alias is found again by that alias
FR — Un propriétaire enregistré avec un alias est retrouvé grâce à cet alias
Key: @i18n:persons.lookup_owner_by_alias
- When they create an owner named "Garry Lopez" with alias "garry-l"
- Then the request succeeds
- When they fetch the person with alias "garry-l"
- Then the person named "Garry Lopez" is returned
Fetching an unknown person is not found, as on the JVM
FR — La consultation d'une personne inconnue renvoie une erreur introuvable, comme sur la JVM
Key: @i18n:persons.unknown_person_returns_no_content
- When they fetch the person with id "does-not-exist"
- Then the JVM's not-found error names "does-not-exist"
A representative creates an organization and reads it back as the active one
FR — Un représentant crée une organisation et la relit en tant qu'organisation active
Key: @i18n:persons.create_and_read_active_organization
- When they create an organization named "Agence Centrale"
- Then the organization is created
- And they act as a representative of the new organization
- When they fetch the active organization
- Then the organization named "Agence Centrale" is returned
Company settings are created, listed and deleted for the organization
FR — Les paramètres d'entreprise sont créés, listés et supprimés pour l'organisation
Key: @i18n:persons.manage_company_settings
- When they create a company setting of type "PROFESSIONNAL_ID" with value "RCS-12345"
- Then the request succeeds
- When they list the company settings of the organization
- Then the company settings include value "RCS-12345"
- And the company setting count is 1
- When they delete that company setting
- Then the request succeeds
- When they list the company settings of the organization
- And the company setting count is 0
Issuing the same invitation twice does not create a duplicate
FR — Émettre deux fois la même invitation ne crée pas de doublon
Key: @i18n:persons.deduplicate_invitation
- When they invite "tenant@home.fr" to person "p-7" as a "DELEGATION"
- Then the request succeeds
- When they invite "tenant@home.fr" to person "p-7" as a "DELEGATION"
- Then the request succeeds
- And the same invitation is returned as the first one
An owner is not visible to a representative of another organization
FR — Un propriétaire n'est pas visible pour un représentant d'une autre organisation
Key: @i18n:persons.owner_not_visible_to_other_organization
- When they create an owner named "Confidential Owner"
- Then the request succeeds
- Given a representative of organization "org-99"
- When they fetch that person by id
- Then the JVM's not-found error names that person
Listing invitations without an email claim is unauthorized
FR — Lister les invitations sans claim d'e-mail n'est pas autorisé
Key: @i18n:persons.invitations_require_email_claim
- Given a representative whose token carries no email
- When they list their invitations
- Then the request is rejected as unauthorized
Creating an owner with a malformed request body is refused
FR — La création d'un propriétaire avec un corps de requête malformé est refusée
Key: @i18n:persons.reject_owner_with_malformed_body
- When they post a malformed body to the owners endpoint
- Then the request is rejected as a bad request
Inviting the same person under two different types yields two invitations
FR — Inviter la même personne sous deux types différents produit deux invitations
Key: @i18n:persons.distinct_invitation_per_target_type
- When they invite "agent@home.fr" to person "p-7" as a "DELEGATION"
- Then the request succeeds
- When they invite "agent@home.fr" to person "p-7" as a "REGISTRATION"
- Then the request succeeds
- And a distinct invitation is returned from the first one
A contact category is added to an existing person and read back
FR — Une catégorie de contact est ajoutée à une personne existante puis relue
Key: @i18n:persons.promote_person_to_owner_via_category
- When they create a tenant named "Polyvalent Person"
- Then the request succeeds
- When they add the contact category "CONTACT_CATEGORY.OWNER" to that person
- Then the request succeeds
- And that person carries the contact category "CONTACT_CATEGORY.OWNER"
A reused alias is accepted and the lookup returns the first registrant
FR — Un alias réutilisé est accepté et la recherche renvoie le premier inscrit
Key: @i18n:persons.duplicate_alias_keeps_first_registrant
- When they create an owner named "Earliest Claimant" with alias "shared-alias"
- Then the request succeeds
- When they create an owner named "Latecomer" with alias "shared-alias"
- Then the request succeeds
- When they fetch the person with alias "shared-alias"
- Then the person named "Earliest Claimant" is returned
Reports API — report-template metadata and rendered report files for an organization
FR — API Rapports — métadonnées de modèles de rapport et fichiers de rapport rendus pour une organisation
Key: @i18n:reports · Source: tests/e2e-api/features/reports.feature
A back-office registers report-template metadata and finds it again
FR — Un back-office enregistre les métadonnées d'un modèle de rapport et les retrouve
Key: @i18n:reports.upsert_and_refetch_metadata
- When they save metadata for template "RC_COMMERCIAL" with title "Commercial lease report"
- Then the metadata is saved
- And the saved metadata belongs to organization "org-7"
- When they fetch the metadata for template "RC_COMMERCIAL"
- Then the request succeeds
- And the returned metadata is for template "RC_COMMERCIAL"
Saving metadata stamps the matching template file name
FR — L'enregistrement des métadonnées renseigne le nom du fichier de modèle correspondant
Key: @i18n:reports.stamp_template_file_on_upsert
- Given a stored template file "CIVIL_RC" named "civil-rc-pdf.ftlh"
- When they save metadata for template "CIVIL_RC" with title "Civil lease report"
- Then the metadata is saved
- And the saved metadata references template file "civil-rc-pdf.ftlh"
All report-template metadata is listed back
FR — Toutes les métadonnées de modèles de rapport sont listées
Key: @i18n:reports.list_metadata
- When they save metadata for template "RC_COMMERCIAL" with title "Commercial lease report"
- And they save metadata for template "CIVIL_RC" with title "Civil lease report"
- When they list the report metadata
- Then the metadata list includes template "RC_COMMERCIAL"
- And the metadata list includes template "CIVIL_RC"
- And the metadata list count is 2
Fetching metadata for an unknown template returns not found
FR — La récupération des métadonnées d'un modèle inconnu renvoie introuvable
Key: @i18n:reports.metadata_not_found
- When they fetch the metadata for template "CALL_FOR_RENT_SUMMARY"
- Then the request is rejected as not found
An unrecognized template easyId is rejected
FR — Un easyId de modèle non reconnu est rejeté
Key: @i18n:reports.reject_invalid_easy_id
- When they fetch the metadata for template "NOT_A_TEMPLATE"
- Then the request is rejected as a bad request
A resumption-of-lease report file is rendered as a PDF
FR — Un fichier de rapport de reprise de bail est rendu au format PDF
Key: @i18n:reports.render_resumption_of_lease_pdf
- When they request the resumption-of-lease report file for contract "c-123"
- Then the request succeeds
- And the report file is returned as a PDF
A caller without the reports scope is refused
FR — Un appelant sans le périmètre rapports est refusé
Key: @i18n:reports.refuse_without_scope
- Given a caller without the reports scope
- When they list the report metadata
- Then the request is forbidden
Listing metadata before anything is saved returns an empty list
FR — Lister les métadonnées avant tout enregistrement renvoie une liste vide
Key: @i18n:reports.list_metadata_empty
- When they list the report metadata
- Then the request succeeds
- And the metadata list count is 0
Re-saving metadata for the same template updates it in place
FR — Réenregistrer les métadonnées du même modèle les met à jour sur place
Key: @i18n:reports.upsert_metadata_updates_in_place
- When they save metadata for template "RC_COMMERCIAL" with title "Commercial lease report"
- Then the metadata is saved
- When they save metadata for template "RC_COMMERCIAL" with title "Commercial lease report v2"
- Then the metadata is saved
- When they fetch the metadata for template "RC_COMMERCIAL"
- Then the request succeeds
- And the returned metadata has title "Commercial lease report v2"
- When they list the report metadata
- Then the metadata list count is 1
Downloading a raw template file is not yet supported
FR — Le téléchargement d'un fichier de modèle brut n'est pas encore pris en charge
Key: @i18n:reports.template_file_download_blocked
- When they download the template file for template "CALL_FOR_RENT_SUMMARY"
- Then the request is rejected as not implemented
Reading a merged template without saved metadata returns not found
FR — Lire un modèle fusionné sans métadonnées enregistrées renvoie introuvable
Key: @i18n:reports.merged_template_not_found
- When they read the merged template for template "RC_COMMERCIAL"
- Then the request is rejected as not found
A caller without the reports scope cannot render a report file
FR — Un appelant sans le périmètre rapports ne peut pas générer un fichier de rapport
Key: @i18n:reports.refuse_render_without_scope
- Given a caller without the reports scope
- When they request the resumption-of-lease report file for contract "c-123"
- Then the request is forbidden
Tickets API — tracking incidents and their lifecycle for an organization
FR — API Tickets — suivre les incidents et leur cycle de vie pour une organisation
Key: @i18n:tickets · Source: tests/e2e-api/features/tickets.feature
An agent reads an existing incident ticket
FR — Un agent consulte un ticket d'incident existant
Key: @i18n:tickets.read_seeded_ticket
- Given an incident ticket "Water leak in the kitchen" exists
- When they fetch that ticket
- Then the ticket subject is "Water leak in the kitchen"
- And the ticket belongs to organization "org-55"
Tickets are searchable by subject within the organization
FR — Les tickets sont recherchables par objet au sein de l'organisation
Key: @i18n:tickets.search_by_subject
- Given an incident ticket "Broken boiler in flat 3" exists
- And an incident ticket "Leaking roof over the garage" exists
- When they search tickets for "boiler"
- Then the ticket results include "Broken boiler in flat 3"
- And the ticket result total is 1
An open ticket is taken into progress
FR — Un ticket ouvert est pris en charge
Key: @i18n:tickets.process_transition
- Given an incident ticket "Lift out of service" exists
- When they fetch that ticket
- Then the fetched ticket is in state "TICKET_STATE.OPEN"
- When they apply the "PROCESS" transition to that ticket
- Then the request succeeds
- And the ticket state is "TICKET_STATE.IN_PROGRESS"
An illegal transition is refused
FR — Une transition illégale est refusée
Key: @i18n:tickets.illegal_transition_refused
- Given an archived ticket "Old settled dispute" exists
- When they apply the "CLOSE" transition to that ticket
- Then the transition is rejected as illegal
An event is appended to a ticket and listed back
FR — Un événement est ajouté à un ticket puis listé
Key: @i18n:tickets.append_and_list_events
- Given an incident ticket "Window won't close" exists
- When they append an event "Called the tenant — leak confirmed" to that ticket
- Then the event is created
- When they list the events of that ticket
- Then the event list includes "Called the tenant — leak confirmed"
- And the event list count is 1
A note is attached to a ticket and listed back
FR — Une note est attachée à un ticket puis listée
Key: @i18n:tickets.attach_and_list_notes
- Given an incident ticket "Heating barely warm" exists
- When they add a note "Tenant prefers morning interventions" on that ticket
- Then the note is created
- When they list the notes of that ticket
- Then the note list includes "Tenant prefers morning interventions"
A ticket is delegated and the delegation is listed back
FR — Un ticket est délégué et la délégation est listée
Key: @i18n:tickets.delegate_ticket
- Given an agent handling tickets for organization "665f1f77bcf86cd7994390a1"
- And an incident ticket "Garage door jammed" exists
- And organization "665f1f77bcf86cd7994390c3" is an eligible ticket delegatee
- When they delegate that ticket to organization "665f1f77bcf86cd7994390c3"
- Then the delegation is created
- And the delegation grants the incident ticket scopes
- When they list the delegations of that ticket
- Then the delegation list count is 1
- And a delegation targets organization "665f1f77bcf86cd7994390c3"
A ticket delegated to another organization appears in that organization's list and global search while the delegation is valid
FR — Un ticket délégué à une autre organisation apparaît dans sa liste et sa recherche globale tant que la délégation est valide
Key: @i18n:tickets.delegated_ticket_in_delegate_lists
- Given an agent handling tickets for organization "665f1f77bcf86cd7994390a1"
- And an incident ticket "Garage door jammed" exists
- And organization "665f1f77bcf86cd7994390c3" is an eligible ticket delegatee
- When they delegate that ticket to organization "665f1f77bcf86cd7994390c3"
- Then the delegation is created
- Given an incident ticket "Gutter overflowing onto the terrace" exists
- And that ticket was delegated to organization "665f1f77bcf86cd7994390c3" until yesterday
- And an agent handling tickets for organization "665f1f77bcf86cd7994390c3"
- When they list the tickets
- Then the ticket results include "Garage door jammed"
- And the ticket results do not include "Gutter overflowing onto the terrace"
- When they search all tickets globally
- Then the global search results include "Garage door jammed"
- And the global search results do not include "Gutter overflowing onto the terrace"
Reading an unknown ticket is not found
FR — La lecture d'un ticket inconnu renvoie introuvable
Key: @i18n:tickets.unknown_ticket_not_found
- When they fetch the ticket with id "ticket-does-not-exist"
- Then the ticket is not found
A ticket belonging to another organization is not found
FR — Un ticket appartenant à une autre organisation est introuvable
Key: @i18n:tickets.ticket_of_another_org_hidden
- Given an incident ticket "Confidential dispute" exists
- Given an agent handling tickets for organization "org-99"
- When they fetch that ticket
- Then the ticket is not found
Re-closing a ticket after it was archived is refused
FR — Reclôturer un ticket après son archivage est refusé
Key: @i18n:tickets.reclose_after_archive_refused
- Given a closed ticket "Settled water damage" exists
- When they apply the "ARCHIVE" transition to that ticket
- Then the request succeeds
- And the ticket state is "TICKET_STATE.ARCHIVED"
- When they apply the "CLOSE" transition to that ticket
- Then the transition is rejected as illegal
Deleting an archived ticket is refused
FR — La suppression d'un ticket archivé est refusée
Key: @i18n:tickets.delete_archived_ticket_refused
- Given an archived ticket "Closed and filed dispute" exists
- When they soft-delete that ticket
- Then the transition is rejected as illegal
An unknown transition name is rejected as a bad request
FR — Un nom de transition inconnu est rejeté comme requête invalide
Key: @i18n:tickets.unknown_transition_name_rejected
- Given an incident ticket "Cracked window pane" exists
- When they apply the "REOPEN" transition to that ticket
- Then the request is rejected as a bad request
A ticket's events start empty and list back every appended event
FR — Les événements d'un ticket sont d'abord vides puis listent chaque événement ajouté
Key: @i18n:tickets.events_listed_empty_then_grow
- Given an incident ticket "Recurring damp patch" exists
- When they list the events of that ticket
- Then the event list count is 0
- When they append an event "First site visit booked" to that ticket
- Then the event is created
- When they append an event "Dehumidifier installed" to that ticket
- Then the event is created
- When they list the events of that ticket
- Then the event list includes "First site visit booked"
- And the event list includes "Dehumidifier installed"
- And the event list count is 2
Utilities API — serials, allocation keys, indexes, configurations and i18n for an organization
FR — API Utilitaires — numéros de série, clés de répartition, indices, configurations et i18n pour une organisation
Key: @i18n:utilities · Source: tests/e2e-api/features/utilities.feature
Serial numbers for a type are allocated sequentially within the organization
FR — Les numéros de série d'un type sont attribués séquentiellement au sein de l'organisation
Key: @i18n:utilities.allocate_sequential_serials
- When they allocate a serial number for type "INVOICE"
- Then the allocated serial number is 1
- When they allocate a serial number for type "INVOICE"
- Then the allocated serial number is 2
- When they allocate a serial number for type "CREDIT_NOTE"
- Then the allocated serial number is 1
An agency creates an allocation key and finds it again
FR — Une agence crée une clé de répartition et la retrouve
Key: @i18n:utilities.create_and_refetch_allocation_key
- When they create an allocation key "ak-roof" for target "building-1" totalling 100 with shares 60 and 40
- Then the request succeeds
- And the saved allocation key is in state "ACTIVE"
- When they fetch the allocation key "ak-roof"
- Then the returned allocation key is in state "ACTIVE"
An allocation key whose shares do not sum to the total starts as a draft
FR — Une clé de répartition dont les parts ne totalisent pas le montant démarre à l'état brouillon
Key: @i18n:utilities.draft_allocation_key_when_shares_incomplete
- When they create an allocation key "ak-wip" for target "building-2" totalling 100 with shares 60 and 30
- Then the request succeeds
- And the saved allocation key is in state "DRAFT"
An active allocation key can be archived through the state machine
FR — Une clé de répartition active peut être archivée via la machine à états
Key: @i18n:utilities.transition_allocation_key_to_archived
- When they create an allocation key "ak-old" for target "building-3" totalling 100 with shares 70 and 30
- And they apply the transition "SET_ARCHIVED" to allocation key "ak-old"
- Then the request succeeds
- When they fetch the allocation key "ak-old"
- Then the returned allocation key is in state "ARCHIVED"
INSEE rent-revision indexes are listed by their type
FR — Les indices INSEE de révision des loyers sont listés par type
Key: @i18n:utilities.list_insee_indexes_by_type
- Given an INSEE index "ILC" for quarter 2 of year 2026 with value "143.46"
- And an INSEE index "ILC" for quarter 1 of year 2026 with value "142.06"
- When they list indexes of type "ILC"
- Then the index list count is 2
- And the index list includes value "143.46"
The serial configuration for a type is read back
FR — La configuration de numérotation d'un type est relue
Key: @i18n:utilities.read_serial_configuration
- Given a serial configuration for type "INVOICE" with format "FAC-%05d"
- When they read the serial configuration for type "INVOICE"
- Then the returned configuration has format "FAC-%05d"
Catalog reference values are listed for a code
FR — Les valeurs de référence du catalogue sont listées pour un code
Key: @i18n:utilities.search_catalog_values_by_code
- Given a catalog value "TITLE" labelled "Monsieur"
- And a catalog value "TITLE" labelled "Madame"
- When they list catalog values for code "TITLE"
- Then the catalog list count is 2
A translation key is resolved from the bundled i18n resources
FR — Une clé de traduction est résolue depuis les ressources i18n embarquées
Key: @i18n:utilities.translate_i18n_key
- When they translate the key "GREETING" of bundle "JEDI" in "en"
- Then the translation contains "May the Force"
Configured dashboards are listed for the agency
FR — Les tableaux de bord configurés sont listés pour l'agence
Key: @i18n:utilities.list_dashboards
- Given a dashboard "Rents" at base url "https://bi.example/rents"
- And a dashboard "Arrears" at base url "https://bi.example/arrears"
- When they list the dashboards
- Then the dashboard list count is 2
- And the dashboard list includes name "Arrears"
Ticket natures are listed for a ticket type as a raw collection
FR — Les natures de ticket sont listées pour un type de ticket sous forme de collection brute
Key: @i18n:utilities.list_ticket_natures
- Given a ticket nature "Plumbing" for ticket type "TICKET_TYPE.INCIDENT"
- And a ticket nature "Roofing" for ticket type "TICKET_TYPE.INCIDENT"
- When they list the ticket natures for ticket type "TICKET_TYPE.INCIDENT"
- Then the ticket nature list count is 2
A well-formed IBAN passes validation and is echoed back
FR — Un IBAN bien formé passe la validation et est renvoyé tel quel
Key: @i18n:utilities.validate_well_formed_iban
- When they validate the IBAN "FR1420041010050500013M02606"
- Then the request succeeds
- And the validated IBAN is "FR1420041010050500013M02606"
An IBAN that fails the checksum is rejected
FR — Un IBAN dont la clé de contrôle est incorrecte est rejeté
Key: @i18n:utilities.reject_malformed_iban
- When they validate the IBAN "FR0000000000000000000000000"
- Then the request is rejected as a bad request
Fetching an unknown allocation key reports not found
FR — La récupération d'une clé de répartition inconnue renvoie introuvable
Key: @i18n:utilities.allocation_key_not_found
- When they fetch the allocation key "does-not-exist"
- Then the request is not found
Archiving a draft allocation key is rejected by the state machine
FR — L'archivage d'une clé de répartition brouillon est rejeté par la machine à états
Key: @i18n:utilities.reject_illegal_allocation_key_transition
- When they create an allocation key "ak-draft" for target "building-9" totalling 100 with shares 50 and 30
- Then the saved allocation key is in state "DRAFT"
- When they apply the transition "SET_ARCHIVED" to allocation key "ak-draft"
- Then the request is rejected as a conflict
Views API — read-model projections for an organization's properties and reports
FR — API Vues — projections du modèle de lecture pour les propriétés et rapports d'une organisation
Key: @i18n:views · Source: tests/e2e-api/features/views.feature
The distinct owners of an organization are listed as a filter source
FR — Les propriétaires distincts d'une organisation sont listés comme source de filtre
Key: @i18n:views.list_distinct_owners
- Given a property "Résidence Les Lilas" owned by owner "own-1" named "Compagnie Dupont"
- And a property "Le Clos Fleuri" owned by owner "own-2" named "Alice Martin"
- When they list the owner filter source
- Then the view collection includes an owner named "Compagnie Dupont"
- And the view collection includes an owner named "Alice Martin"
- And the view collection has 2 entries
The property filter source returns roots and excludes units
FR — La source de filtre des propriétés renvoie les racines et exclut les lots
Key: @i18n:views.list_property_filter
- Given a property "Villa Marius" with id "prop-10"
- And a unit "Lot 12 — T3" with id "unit-1" under property "prop-10"
- When they list the property filter source
- Then the view collection includes a part named "Villa Marius"
- And the view collection has 1 entries
Properties are searched by name within the organization
FR — Les propriétés sont recherchées par nom au sein de l'organisation
Key: @i18n:views.search_properties_by_name
- Given a property "Villa Doria" with id "prop-20"
- And a property "Maison Bleue" with id "prop-21"
- When they search properties for "Doria"
- Then the view page includes a part named "Villa Doria"
- And the view page total is 1
The units of a property are returned as a page
FR — Les lots d'une propriété sont renvoyés sous forme de page
Key: @i18n:views.paged_units_of_property
- Given a property "Le Grand Large" with id "prop-30"
- And a unit "Lot 1" with id "unit-10" under property "prop-30"
- And a unit "Lot 2" with id "unit-11" under property "prop-30"
- When they read the units page of property "prop-30"
- Then the view page includes a part named "Lot 1"
- And the view page includes a part named "Lot 2"
- And the view page total is 2
The parts held by an owner are returned
FR — Les lots détenus par un propriétaire sont renvoyés
Key: @i18n:views.parts_for_owner
- Given a property "Résidence du Parc" owned by owner "own-9" named "Bob Durant"
- When they read the parts for owner "own-9"
- Then the view collection includes a part named "Résidence du Parc"
- And the view collection has 1 entries
The buildings of a signed rental-delegate contract are returned
FR — Les bâtiments d'un mandat de gestion locative signé sont renvoyés
Key: @i18n:views.buildings_for_rdc
- Given a building "Bâtiment A" with id "bld-1" linked to rental-delegate contract "rdc-1"
- When they read the buildings for rental-delegate contract "rdc-1"
- Then the view collection includes a part named "Bâtiment A"
- And the view collection has 1 entries
The call-for-rent summary is rolled up for a period and state
FR — Le récapitulatif d'appel de loyer est agrégé pour une période et un état
Key: @i18n:views.call_for_rent_summary
- Given a call-for-rent event for period "2026-06" in state "PROCESSED"
- And a call-for-rent event for period "2026-05" in state "PROCESSED"
- When they request the call-for-rent summary for period "2026-06" and state "PROCESSED"
- Then the request succeeds
- And the view value list has 1 entries
The CRG report is rendered as a PDF when a PDF is requested
FR — Le rapport CRG est rendu en PDF lorsqu'un PDF est demandé
Key: @i18n:views.crg_report_as_pdf
- Given a CRG event for owner "own-5" in state "PROCESSED"
- When they request the CRG report for owner "own-5" in state "PROCESSED" as a PDF
- Then the request succeeds
- And the response content type is "application/pdf"
The distinct tenants of an organization are listed as a filter source
FR — Les locataires distincts d'une organisation sont listés comme source de filtre
Key: @i18n:views.list_distinct_tenants
- Given a property "Studio Gambetta" tenanted by tenant "ten-1" named "Claire Petit"
- And a property "Loft Belleville" tenanted by tenant "ten-2" named "Hugo Bernard"
- When they list the tenant filter source
- Then the view collection includes a tenant named "Claire Petit"
- And the view collection includes a tenant named "Hugo Bernard"
- And the view collection has 2 entries
The owner filter source is empty when the organization has no seeded parts
FR — La source de filtre des propriétaires est vide lorsque l'organisation n'a aucun bien enregistré
Key: @i18n:views.empty_owner_filter
- When they list the owner filter source
- Then the request succeeds
- And the view collection has 0 entries
A property search that matches nothing returns an empty page
FR — Une recherche de propriétés sans correspondance renvoie une page vide
Key: @i18n:views.search_no_match_is_empty_page
- Given a property "Villa Solaire" with id "prop-40"
- When they search properties for "Inexistante"
- Then the request succeeds
- And the view page total is 0
- And the view page has 0 entries
The units of a property are paginated by page and page size
FR — Les lots d'une propriété sont paginés par numéro de page et taille de page
Key: @i18n:views.units_page_second_page
- Given a property "Le Phare" with id "prop-50"
- And a unit "Lot A" with id "unit-50" under property "prop-50"
- And a unit "Lot B" with id "unit-51" under property "prop-50"
- When they read the units page of property "prop-50" at page 1 with size 1
- Then the request succeeds
- And the view page has 1 entries
- And the view page total is 2
- And the view page includes only the part named "Lot B"
- And the view page size is 1
The market performances of a known part are returned with its children
FR — Les performances de marché d'un bien connu sont renvoyées avec ses enfants
Key: @i18n:views.market_performances_for_part
- Given a property "Résidence Horizon" with id "prop-60"
- And a unit "Lot 60" with id "unit-60" under property "prop-60"
- When they read the market performances of part "prop-60"
- Then the request succeeds
- And the view value part is named "Résidence Horizon"
- And the view value part has 1 children
The market performances of an unknown part yield no content
FR — Les performances de marché d'un bien inconnu ne renvoient aucun contenu
Key: @i18n:views.market_performances_unknown_part_no_content
- When they read the market performances of part "prop-does-not-exist"
- Then the response is empty with no content