docs: initialize project documentation with context glossary, PRD, and core ADRs

This commit is contained in:
nessar committed 2026-08-17 14:18:14 +02:00
1 parent 134a2da599
commit 447529a8a4
9 files changed
+272

No files matched your search

@@ -0,0 +1,5 @@
# Preparedness for Future Multi-Tenancy
**Status**: accepted
The application will initially be deployed as a single-portfolio (single-tenant) system where all users share a common property portfolio. However, to prevent schema lock-in and enable an easy transition to a multi-landlord SaaS platform in the future, we have decided to introduce a `Bailleur` (Landlord) entity. All assets, leases, and loans will be partitioned by `BailleurId`, with a single default `Bailleur` instance created at setup.
+5
View File
@@ -0,0 +1,5 @@
# CI/CD Pipeline Scope and Deployment Boundary
**Status**: accepted
The GitLab CI/CD pipeline will be scoped to automate tests, backend/frontend compilation, Docker image builds, and publishing to the GitLab Container Registry. Automated CD (Continuous Deployment) to a target server is excluded from the initial scope to keep deployment credentials out of the CI environment for now. Deployment will be done manually by pulling the published images from the registry onto the host server.
@@ -0,0 +1,5 @@
# Attachment Storage Strategy
**Status**: accepted
The application needs to store files such as invoices, signed lease contracts, and check-in/check-out photos. We have decided to store the actual binary files on the server's local file system (mounted as a persistent Docker volume) rather than storing them directly in MongoDB (e.g. via GridFS) or utilizing external cloud object storage. MongoDB will only store file metadata (local file path, file name, MIME type, size). This ensures optimal performance for serving files while keeping the configuration simple.
@@ -0,0 +1,5 @@
# Pluggable OIDC Authentication
**Status**: accepted
The application will use standard OpenID Connect (OIDC) protocols for authentication and role-based access control. Both the frontend (Angular) and backend (Spring Security) will be configured dynamically via environment variables (e.g., Issuer URI, Client ID, Client Secret). This allows the application to adapt to different identity providers seamlessly, with `voidAuth` serving as the primary identity provider in both development and production.
@@ -0,0 +1,5 @@
# Localization and Naming Strategy
**Status**: accepted
The application target market is French real estate landlords under the LMNP (Location Meublée Non Professionnelle) tax regime. Therefore, the User Interface (Angular) will be in French. To adhere to standard engineering best practices, all source code (variables, class names, method names, comments) and backend API structures will be written in English. We have established a direct mapping between French domain concepts and English code terms in the `CONTEXT.md` glossary (e.g., `Bail` is coded as `Lease`, `Exercice fiscal` as `FiscalYear`).
@@ -0,0 +1,54 @@
# GDPR Compliance and Data Archiving Strategy
**Status**: accepted
The application manages sensitive tenant files (identity cards, tax notices, payslips) and property condition photos. To comply with GDPR requirements and maintain a sustainable disk storage footprint over time, we have established a strict retention and image optimization policy.
## Decisions
### 1. Automated Server-Side Image Optimization
All uploaded photos (for property condition reports) are compressed and resized on the backend before write:
- Target resolution: maximum 1920x1080 pixels.
- Format: converted to WebP.
- Compression quality factor: 75-80%.
This reduces average photo size from ~6.0 MB (raw smartphone camera) to ~250 KB (95.8% reduction).
### 2. GDPR Retention and Purging Cycle
- **Rejected Applicants**: Complete deletion of all submitted documents (payslips, identity documents) exactly 30 days after rejection.
- **Archived Leases**:
- Upon lease termination, the lease transitions to an `Archived` state.
- Personal identity documents and income proofs of the former tenants are permanently purged 3 years after lease termination (matching the 3-year French statute of limitations for residential tenancy disputes).
- General inspection photos are purged 5 years after lease termination.
- Basic accounting records (rent ledger, invoice amounts) are retained for 10 years to comply with commercial and tax record retention laws (Article L123-22 of the French Commercial Code).
---
## Storage Projections (3-Apartment Portfolio over 10 Years)
Assuming an average lease turnover rate of 2 years (i.e., 1.5 lease cycles per year across a 3-apartment portfolio).
### Unit Data Footprints
| Data Type | Unoptimized Size | Optimized Size | Purge Trigger |
| :--- | :--- | :--- | :--- |
| **MongoDB Text Records** | ~10 KB / year | ~10 KB / year | Never (10-year archive) |
| **Tenant Personal Dossier** | ~5.0 MB (PDF/Images) | ~5.0 MB | Purged 3 years after lease end |
| **Inspection Photos (In/Out)** | ~360 MB (60 raw photos) | ~15 MB (WebP 1080p) | Purged 5 years after lease end |
| **Invoices & Receipts / year** | ~20 MB (Raw scans) | ~5 MB (Compressed PDFs) | Never (10-year archive) |
### 10-Year Cumulative Footprint Comparison
#### Scenario A: Unoptimized & No Purge (Default Strategy)
- **Year 1**: 3 * (22 MB tenant docs + 360 MB photos) + 67 MB operational files = **1,213 MB (~1.2 GB)**.
- **Yearly Growth**: 67 MB (ops) + 1.5 * (22 MB tenant docs + 720 MB in/out photos) = **1,180 MB / year**.
- **Year 10 Cumulative Footprint**: **~11.8 GB** (Continuous, compounding growth).
#### Scenario B: Optimized & Purged (Our Design)
- **Year 1**: 3 * (5 MB tenant docs + 15 MB photos) + 15 MB operational files = **75 MB**.
- **Yearly Growth (Before Purges)**: 15 MB (ops) + 1.5 * (5 MB tenant docs + 30 MB in/out photos) = **67.5 MB / year**.
- **Purging Offsets**:
- *From Year 4 onwards*: Purge of tenant dossiers of expired leases saves **7.5 MB / year** (1.5 leases * 5 MB).
- *From Year 6 onwards*: Purge of inspection photos of expired leases saves **45.0 MB / year** (1.5 leases * 30 MB).
- **Year 10 Cumulative Footprint**: **~345 MB** (Stabilizes and plates out around 350 MB due to continuous purges).
This architecture saves over **97% of server disk space** over a 10-year lifecycle compared to a naive storage strategy, while strictly respecting French GDPR constraints.
@@ -0,0 +1,5 @@
# Frontend Charting Library Integration
**Status**: accepted
The dashboard needs to display key-metrics and financial trends to the landlord. We have decided to use the `ngx-echarts` library (an Angular wrapper for Apache ECharts) to render these charts. To optimize application bundle size and initial page load times, we will import a custom bundle of ECharts containing only the necessary chart types (Line, Bar, Pie) and components (Grid, Legend, Tooltip) rather than importing the entire ECharts package.
+85
View File
@@ -0,0 +1,85 @@
# Cahier des charges & Spécifications – LMNP Organizer
## Problem Statement
Self-managing buy-to-let properties under the French LMNP (Location Meublée Non Professionnelle) tax status involves complex administrative, financial, and tax obligations. Landlords must track leases, generate rent receipts, document property conditions and furniture inventories, monitor mortgage schedules, classify expenses for tax optimization, compute complex component-based depreciation, and carry forward tax deficits. Doing this manually or via standard spreadsheets is highly error-prone, risks tax non-compliance, and fails to optimize tax savings.
## Solution
A containerized web application comprising a Java 25 / Spring Boot 4 backend and an Angular 22 frontend that centralizes the management of properties, tenants, leases, and mortgage loans. The application provides guided property inspection checklists with photo sequences, automates expense classification, calculates component-based depreciation schedules, simulates French tax forms (Form 2033 & 2042-C-PRO), and automatically tracks tax loss carry-forwards and deferred depreciations. The system is designed to maintain a low storage footprint through image compression and adheres to GDPR regulations by auto-purging sensitive files.
## User Stories
1. As a Landlord (`Bailleur`), I want to manage apartments in my portfolio, so that I can centralize their descriptions, locations, and asset values.
2. As a Landlord (`Bailleur`), I want to add tenant records with contact information and dossier status, so that I can easily reach them and check their application completeness.
3. As a Landlord (`Bailleur`), I want to create a Lease (`Bail`) linking an apartment to one or more Tenants (`Locataires`), so that the legal relationship and rental parameters (start date, end date, rent, charges) are documented.
4. As a Landlord (`Bailleur`), I want to generate a lease contract document based on a template, so that I can print it or send it by email to the tenants.
5. As a Landlord (`Bailleur`), I want to record a Security Deposit (`Dépôt de garantie`) paid by the tenants at the beginning of the lease, so that I can track the balance to be returned later.
6. As a Landlord (`Bailleur`), I want to associate one or more Guarantors (`Garants`) to a Lease (`Bail`), so that I can contact them in case the tenants default.
7. As a Landlord (`Bailleur`), I want to generate monthly Rent Receipts (`Quittances de loyer`) for active leases, so that I can send them as PDFs to tenants who paid their rent.
8. As a Landlord (`Bailleur`), I want to track rent payments month by month, marking them as Paid, Late, or Upcoming, so that I can monitor my rental income flow.
9. As a Landlord (`Bailleur`), I want to record and view a Furniture Inventory (`Inventaire du mobilier`) for each apartment, so that I can meet LMNP legal requirements.
10. As a Landlord (`Bailleur`), I want to establish a Property Condition Report (`État des lieux`) at check-in or check-out, so that I can record the state of each room and furniture item.
11. As a Landlord (`Bailleur`), I want to be guided by a Photo Sequence (`Parcours de photos`) during the property inspection, so that I don't forget to take crucial pictures (kitchen, bathroom, air conditioner) to use as proof.
12. As a Landlord (`Bailleur`), I want to compare the check-in and check-out Property Condition Reports, so that the system automatically calculates deductions for damages to subtract from the Security Deposit (`Dépôt de garantie`).
13. As a Landlord (`Bailleur`), I want to record property-related expenses and upload their corresponding invoices as Attachments (`Pièces jointes`), so that I can keep records of all expenses.
14. As a Landlord (`Bailleur`), I want the system to automatically categorize my expenses as either a Deductible Expense (`Charge déductible`) or a Capitalized Asset (`Immobilisation`) based on a 500 € HT threshold and category, so that I make fewer tax mistakes.
15. As a Landlord (`Bailleur`), I want to create a Mortgage (`Prêt immobilier`) with its principal, interest rate, duration, and insurance rate, so that the system automatically generates my Mortgage Amortization Schedule (`Tableau d'amortissement`).
16. As a Landlord (`Bailleur`), I want to manually adjust details on my Mortgage Amortization Schedule, so that I can fix minor rounding differences compared to the bank's schedule.
17. As a Landlord (`Bailleur`), I want to configure the Component Amortization (`Amortissement par composants`) of my apartment, including a non-depreciable Land Share (`Quote-part de terrain`), so that I can establish a compliant LMNP tax depreciation plan.
18. As a Landlord (`Bailleur`), I want the application to suggest a default component breakdown grid for my apartment, so that I can set it up in one click without being an accountant.
19. As a Landlord (`Bailleur`), I want to see a pre-filled simulation of my LMNP Tax Declaration Pack (`Liasse fiscale` Form 2033 & 2042-C-PRO) at the end of the Fiscal Year (`Exercice fiscal`), so that I can easily copy-paste the values to the official tax website.
20. As a Landlord (`Bailleur`), I want the system to automatically compute and carry forward my Tax Loss Carryforward (`Déficit reportable`) and Deferred Amortization (`Amortissement différé`) to the next Fiscal Year (`Exercice fiscal`), so that I can optimize my tax savings indefinitely.
21. As a Landlord (`Bailleur`), I want to view a central Calendar (`Calendrier`) aggregating all Events (`Événements`) like rent collections, tenant arrivals/departures, loan deadlines, and insurance renewals, so that I have a clear schedule.
22. As a Landlord (`Bailleur`), I want to add manual custom Events (`Événements`) like plumber appointments or general assemblies to the Calendar, so that I can manage all tasks in one place.
23. As a Landlord (`Bailleur`), I want my uploaded files (PDFs, photos) to be compressed and saved as Attachments (`Pièces jointes`) in the server file system and referenced in the database, so that the application maintains a low storage footprint.
24. As a Landlord (`Bailleur`), I want the system to automatically delete sensitive tenant files (payslips, IDs) 30 days after rejecting a candidate or 3 years after a Lease (`Bail`) is archived, so that I comply with GDPR requirements.
25. As a Landlord (`Bailleur`), I want to log in securely using OIDC (OpenID Connect) configured dynamically, so that I can authenticate using `voidAuth` in both development and production environments.
26. As an Administrator, I want an administration panel to manage global parameters, system configurations, and users, so that I can control access to the application.
27. As a Landlord (`Bailleur`), I want to view a Dashboard (`Tableau de bord`) displaying key metrics (revenus, occupancy rate, cash-flow, outstanding unpaid rent) at a glance, so that I can monitor my portfolio's status.
28. As a Landlord (`Bailleur`), I want to view interactive charts (monthly cash flow trend and expense breakdown by category), so that I can analyze my financial performance visually.
## Implementation Decisions
### Technical Stack
- **Backend**: Java 25 LTS, Spring Boot 4, Spring Security OAuth2. Exposes REST APIs documented using OpenAPI/Swagger.
- **Frontend**: Angular 22, SPA built using modern vanilla CSS stylesheets. Interactive charts implemented via `ngx-echarts` (optimized custom bundle).
- **Database**: MongoDB (latest stable version).
- **Authentication**: OpenID Connect (OIDC) dynamically configured to plug into `voidAuth` for both development and production.
### Data Model & Multi-Tenancy preparedness (ADR-0001)
- The database schema binds all core entities (apartments, leases, loans, events) to a `BailleurId`. Initially, the app is deployed in single-portfolio mode with a single default `Bailleur` record, but the schema remains ready for future SaaS/multi-tenant partitioning.
### Attachment Storage & Optimization (ADR-0003, ADR-0006)
- Binary files (PDFs, photos) are stored on the server's local file system (mounted via persistent Docker volumes). The MongoDB database holds file metadata (`Attachment`).
- Uploaded photos are compressed backend-side: resized to a maximum of 1920x1080 and converted to WebP with 75-80% quality (reducing size to ~250 KB per photo).
### GDPR & Archiving Automated Schedules (ADR-0006)
- Candidates' documents are permanently deleted 30 days after application rejection/selection.
- Terminated leases transition to an `Archived` state. Identity documents and payslips of former tenants are purged 3 years after lease end. Property condition photos are purged 5 years after lease end. Financial/rent ledgers are archived and kept for 10 years to comply with commercial tax auditing codes.
### Tax Calculations & Automation
- **Expense Classification**: Expenses under 500 € HT or belonging to operations categories (insurance, tax) are categorized as Deductible Expenses (`Charge déductible`). Renovation or furniture expenses over 500 € HT are categorized as Capitalized Assets (`CapitalizedAsset`) and trigger an amortization line.
- **Component Amortization**: Pre-filled template configurations for property components (Terrain, Gros œuvre, Toiture, Équipements). Land Share (`Quote-part de terrain`) is excluded from depreciation.
- **Carry-Forwards**: Automatically calculates and rolls over Tax Loss Carryforwards (`Déficit reportable`) and Deferred Amortizations (`Amortissement différé`) at fiscal year closure.
## Testing Decisions
### Code Coverage Rule
- A minimum code coverage threshold of **80%** will be strictly enforced on both the backend (JUnit/JaCoCo) and frontend (Karma/Jest/Istanbul) testing pipelines. Builds with coverage under 80% must fail the GitLab CI test stage.
### Testing Seams
- **Backend Seam (API Layer)**: Integration tests using `@SpringBootTest` and `MockMvc` to hit REST endpoints, verify controller behaviors, model validations, and security configurations. A test MongoDB profile (using Testcontainers) will be used. OIDC token validation will be mocked.
- **Frontend Seam (Component/Service Layer)**: Angular component and service testing via `TestBed` and `HttpTestingController` to mock HTTP interactions and verify form inputs, component state updates, and calendar/tax rendering.
- **End-to-End Seam (Playwright)**: Full browser automated testing covering OIDC login flows, guided Property Condition photo captures, and Tax Declaration Form simulations.
## Out of Scope
- **CD (Continuous Deployment) Stage in CI/CD (ADR-0002)**: The GitLab CI/CD pipeline compiles, tests, builds Docker containers, and pushes them to the GitLab registry. Deploying the new versions onto the production server is done manually (via ssh/pull/compose restart) and is excluded from the pipeline's automated steps.
- **Live Bank Sync/Imports**: Users enter bank loans and operational expenses manually or adjust pre-computed mortgage lines. Direct parsing of Excel/CSV statements or API bank integrations is out of scope.
- **Multi-Tenant UI Isolation**: The interface will only expose the default active landlord's portfolio. Designing role-based multi-landlord separation in the Angular client is out of scope for Phase 1.
## Further Notes
- Localization: All backend logs, codes, fields, and internal database keys use English (`Lease`, `SecurityDeposit`, `Landlord`). The UI labels, PDFs, and categories shown to the landlord are purely in French.
- Documentation: Coding agents should reference the project glossary in [CONTEXT.md](file:///home/nessar/lmnp-organizer/lmnp-organizer/CONTEXT.md) and respect active architectural decisions in `docs/adr/`.