Properties¶
Contrôleur HTTP d'administration des propriétés (création-publication, édition, médias, finance, notes internes, resale royalty). Source : properties.controller.ts.
Tous les endpoints requièrent une session admin BetterAuth valide (AdminAuthGuard).
GET /administration/property¶
Liste toutes les properties d'investissement obligataire ou prêt (investorContractType IN ('obligation', 'loan')) avec les jointures projet, SPV, porteur, échéancier, séquestre intérêts, budget travaux.
Décorateur : L110.
Response¶
Tableau d'objets enrichis :
[
{
"project": { "...": "champs property + address + interestSequestreSummary + constructionBudgetSummary" },
"spv": { "...": "SpecialPurposeVehicule" },
"projectOwner": { "...": "ProjectOwner" },
"isReferralPaid": false,
"echeancierExists": true
}
]
GET /administration/property/royalty¶
Liste toutes les properties de type royalty triées createdAt DESC. Chaque entrée embarque un flag hasInternalNote.
Décorateur : L117.
Response¶
Tableau de Property étendu avec hasInternalNote: boolean.
GET /administration/property/properties-prices-history¶
Exporte l'historique des prix de bricks de toutes les properties au format Excel. Streame le fichier en réponse.
Décorateur : L221.
Response¶
Fichier .xlsx (Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet), nom : properties-brick-prices-history-YYYY-MM-DD.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
data-validation-error |
400 | Validation des données extraites échouée |
GET /administration/property/simulate-automatic-investment¶
Lance une simulation de financement automatique en arrière-plan. La requête répond immédiatement ('Simulation en cours...') ; les résultats sont postés sur Slack #financement-automatique-simulation.
Note : route exposée dans ce contrôleur mais le
@Controllerestadministration/property; en pratiquepropertyIdn'est pas un UUID réel ici, c'est une simulation.
Décorateur : L153 — voir aussi Property Funding.
GET /administration/property/:propertyId¶
Retourne une Property complète par ID.
Décorateur : L124.
Path param¶
propertyId— UUIDv4
Response¶
Entité Property (TypeORM) ou null.
POST /administration/property/:propertyId/resale/start¶
Démarre la phase de revente d'une property royalty. Une AdminAction PROPERTY_RESALE_START est créée via interceptor.
Décorateur : L134.
Path param + Request body (fusionnés et validés ensemble)¶
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
property.not-found |
404 | Property royalty introuvable |
property.not-purchased-yet |
400 | Property pas encore achetée |
property.resale-already-started |
400 | Resale déjà démarrée |
POST /administration/property/:propertyId/resale/offer-accepted¶
Enregistre l'acceptation d'une offre de revente (partial / total). Annule en cascade les deals marketplace en attente. Une AdminAction PROPERTY_RESALE_OFFER_ACCEPTED est créée via interceptor.
Décorateur : L156.
Path param + Request body¶
saleType : 'partial' | 'total' (propertyResaleType).
Response¶
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
property.not-found |
404 | Property royalty introuvable |
property.not-purchased-yet |
400 | Property pas encore achetée |
property.resale-not-started |
400 | Resale non démarrée |
property.offer-already-accepted |
400 | Offre déjà acceptée |
property.resale-completed |
400 | Resale déjà clôturée |
POST /administration/property/yearly-financial-update¶
Upload d'un fichier Excel (mime application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) déclenchant la mise à jour financière annuelle de toutes les properties listées. Une AdminAction UPLOAD_YEARLY_PROPERTIES_UPDATE est créée via interceptor.
Décorateur : L183.
Multipart body¶
file— fichier.xlsx(interceptorFileInterceptor)
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
missing-update-file |
400 | Aucun fichier dans la requête |
cannot-validate-excel-data |
400 | Données Excel invalides |
property-not-found |
404 | Au moins une property du fichier introuvable |
brick-price-not-found |
404 | Brick price introuvable pour la period concernée |
property-update-for-year-already-exist |
409 | Update annuelle déjà enregistrée pour cette year |
POST /administration/property/upload-image¶
Upload jusqu'à 20 images (jpeg / jpg / png / webp) pour la galerie photo d'une property.
Décorateur : L247.
Multipart body¶
files— N×fichiers image (max 20,FilesInterceptor)
Response¶
Tableau d'URLs publiques des images uploadées.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
Failed to upload images |
500 | Aucune image n'a pu être uploadée |
POST /administration/property/upload-property-document¶
Upload d'un document PDF lié à une property.
Décorateur : L267.
Multipart body¶
file— fichierapplication/pdf
Response¶
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
<error> |
500 | Toute erreur d'upload propage result.error en 500 |
PATCH /administration/property/:propertyId¶
Édite une property (sauf royalty). En DRAFT, l'édition est complète (montant à financer, opération, contract specs). Hors DRAFT, seules certaines colonnes sont mises à jour via ce endpoint générique.
Pour modifier le séquestre d'intérêts (totalFundEscrow) ou le budget travaux (totalConstructionBudget) sur une property publiée, utiliser le endpoint dédié PATCH …/contract-budget — règles métier distinctes (échéancier, virements PDP, solde Lemonway).
Décorateur : L290.
Path param¶
propertyId— UUIDv4
Request body¶
Validé via propertyEditPayload (cf. properties.dto.ts). Champs principaux : name, investmentCase, imageGallery, videoGallery, documents, address, localisationDescription, surface, fundingStartDate, fundingMaxEndDate, revenueStartDate, investmentHorizonInMonths, amountToFundCents, minAmountToFundCents, advantages, finances, attributes, returnOnInvestment, lotCount, totalConstructionBudget, totalFundEscrow, investorContractType, operation (patch obligV1 ou obligV2 selon __variant existant).
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
property.edit-does-not-support-royalty-operation |
400 | La property est de type royalty |
<validation errors> |
400 | operation patch invalide pour la version (V1/V2) |
min-amount-to-fund-should-be-less-than-amount-to-fund |
400 | Validation montant min/cible |
max-end-date-should-be-after-start-date |
400 | Date max ≤ date de début |
PATCH /administration/property/:propertyId/contract-budget¶
Édite le séquestre d'intérêts et/ou le budget travaux d'une property publiée (obligation V2 uniquement). Trace une AdminAction PROPERTY_EDIT_CONTRACT_BUDGET via interceptor.
Décorateur : L751.
Logique pure : published-contract-budget-edit.ts.
Path param¶
propertyId— UUIDv4
Request body¶
Validé via patchProjectContractBudgetPayload (@bricks-common/api-communication-bricksoffice). Champs optionnels (au moins un requis) :
Montants en centimes.
Règles métier¶
| Champ | Règle |
|---|---|
totalFundEscrow (séquestre d'intérêts) |
Gelé dès qu'un échéancier existe — toute modification renvoie project.edit-contract-budget-interest-sequestre-locked-with-schedule (pas de recompute de l'échéancier, choix conservateur) |
| Les deux champs | Baisse interdite après le premier virement au porteur (project.edit-contract-budget-decrease-after-transfer) |
| Les deux champs | Hausse autorisée seulement si le solde Lemonway du SPV couvre la somme des augmentations (project.edit-contract-budget-increase-requires-lw-funds) ; indisponibilité LW → project.lemonway-balance-unavailable (500) |
totalConstructionBudget |
Toujours éditable hors gel séquestre ci-dessus — valeur indicative côté ops |
Le budget travaux reste modifiable même après déblocage des fonds au porteur ; seul le séquestre est figé par l'existence de l'échéancier.
Response¶
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
project.not-found |
404 | Property introuvable |
project.edit-only-supports-obligationV2 |
400 | Property non obligation V2 |
project.edit-contract-budget-interest-sequestre-locked-with-schedule |
400 | Échéancier existant + tentative de modifier le séquestre |
project.edit-contract-budget-decrease-after-transfer |
400 | Baisse après virement PDP |
project.edit-contract-budget-increase-requires-lw-funds |
400 | Solde Lemonway insuffisant pour la hausse |
project.lemonway-balance-unavailable |
500 | Impossible de lire le solde Lemonway |
PATCH /administration/property/:propertyId/publish¶
Publie une property en DRAFT (passage à PUBLISHED). Effectue : insertion BrickPrice, création des bricks primaires, programmation des jobs auto-funding, annonce Slack et webhook Make.com (production uniquement).
Décorateur : L552.
Path param¶
propertyId— UUIDv4
Request body¶
displayDate optionnelle.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
property.not-found |
404 | Property introuvable |
property.publish.must-be-draft |
400 | Property déjà publiée ou autre statut |
property.publish.funding-start-date-cannot-be-before-display-date |
400 | displayDate > funding.startedAt |
property.spv.not-found |
500 | SPV introuvable |
spv.lemonway.wallet.not-found |
404 | SPV sans wallet Lemonway |
<lemonway error message> |
500 | Échec de récupération du compte Lemonway |
property.lemonway-account-not-validated |
400 | Compte Lemonway non validé |
property.publish.must-be-2h-before-funding-start |
400 | Funding démarre dans moins de minFundingStartDateDelayFromNowInHours |
property.publish.must-have-2-images |
400 | Moins de 2 images dans la galerie |
GET /administration/property/:propertyId/advantages¶
Récupère la liste des avantages d'une property (FR uniquement).
Décorateur : L658.
Path param¶
propertyId— UUIDv4
Response¶
POST /administration/property/:propertyId/draft-token¶
Génère un token Redis (TTL 7 jours) permettant de prévisualiser une property en draft via le front. Retourne l'URL préviewable.
Décorateur : L673.
Path param¶
propertyId— UUIDv4
Response¶
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
property.not-found |
404 | Property introuvable |
DELETE /administration/property/:propertyId¶
Supprime une property en statut DRAFT.
Décorateur : L699.
Path param¶
propertyId— UUIDv4
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
<deletion error> |
400 | Toute erreur métier propagée par PropertyDeletionService.deletePropertyInDraft |
GET /administration/property/:propertyId/internal-note¶
Récupère la note interne admin (markdown) d'une property.
Décorateur : L712.
Path param¶
propertyId— UUIDv4
Response¶
InternalNote (contenu + version).
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
Property not found |
404 | Property introuvable |
PATCH /administration/property/:propertyId/internal-note¶
Met à jour la note interne avec contrôle de version optimiste.
Décorateur : L728.
Path param¶
propertyId— UUIDv4
Request body¶
Validé via patchProjectInternalNotePayload.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
Property not found |
404 | Property introuvable |
NOTE_VERSION_CONFLICT |
409 | expectedVersion ne correspond pas à la version en base |
POST /administration/property/:propertyId/solde-de-tout-compte/done¶
Marque le solde de tout compte comme effectué (étape temporaire avant automatisation).
Décorateur : L760.
Path param¶
propertyId— UUIDv4
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
solde-de-tout-compte-already-done |
400 | Solde déjà marqué fait |
project-must-be-in-repayment-finished-status |
400 | financialStatus ≠ repayment-finished |
Liens¶
- Service :
properties.service.ts - DTO d'édition :
properties.dto.ts - Service de création :
property-creation.service.ts - Service de suppression :
property-deletion.service.ts - Service notes internes :
project-internal-note.service.ts