Spring Boot + Thymeleaf app: fleet, drivers, vendors, bookings, billing/ settlements, payments, maintenance, inspections, reviews, telematics, audit log, staff/user management, and separate admin/vendor/driver portals. Includes Docker Compose deployment (app + Postgres). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
233 lines
11 KiB
Markdown
233 lines
11 KiB
Markdown
# Car Rental Management System — Implementation Plan
|
||
|
||
> Status: **DRAFT for review** · Date: 2026-06-26
|
||
> Baseline: Spring Boot 3.3.4 · Java 17 · Thymeleaf · PostgreSQL · Spring Security (admin + customer chains, Google OAuth2)
|
||
> Purpose: turn the current customer-booking + admin-CRUD app into the full multi-party platform described in the feature spec.
|
||
|
||
---
|
||
|
||
## 1. Scope summary
|
||
|
||
The current app covers ~25–30% of the spec (customer-facing booking + basic admin car/booking CRUD).
|
||
This plan adds the four missing pillars — **Driver, Vendor, Billing/Settlement, Reporting** — plus the
|
||
**Organization/config** foundation and enrichment of Fleet, Customer, and Booking.
|
||
|
||
Current coverage vs target:
|
||
|
||
| Area | Now | Target |
|
||
|---|---|---|
|
||
| Organization / Config | ~20% | Org profile, staff users + permissions, tax/currency/commission config, category masters |
|
||
| Fleet & Car | ~45% | + year, colour, ownership, feature tags, hourly/monthly rates, documents+expiry, maintenance |
|
||
| Driver | 0% | full module |
|
||
| Vendor | 0% | full module + vendor login + settlement |
|
||
| Customer | ~50% | + categories (Individual/Company/Corporate), GST/billing |
|
||
| Trip Booking | ~40% | + with-driver, hours/months, tax & driver charges, invoice |
|
||
| Billing/Settlement | ~5% | invoices, commission, settlements, profit split |
|
||
| Reporting | 0% | filtered reports + Excel/PDF export, dashboards |
|
||
| Customer page | ~55% | richer filters + driver option |
|
||
|
||
---
|
||
|
||
## 2. Target architecture
|
||
|
||
- **Single Spring Boot modular-monolith** (no microservices). Package-by-feature:
|
||
`org`, `fleet`, `driver`, `vendor`, `customer`, `booking`, `billing`, `reporting`, `web`, `security`, `config`.
|
||
- **Three security filter chains** (extends today's pattern):
|
||
1. `/admin/**` → staff (ROLE_ADMIN, ROLE_STAFF) — existing admin chain, expanded
|
||
2. `/vendor/**` → ROLE_VENDOR — **new** vendor portal chain
|
||
3. everything else → customers + Google OAuth (existing customer chain)
|
||
- **Persistence**: PostgreSQL + JPA. Move `ddl-auto=update` → **Flyway migrations** (versioned schema; required once money/settlement tables exist).
|
||
- **Money**: always `BigDecimal`, scale 2, currency from config. Never `double`.
|
||
- **Exports**: Apache POI (Excel), OpenPDF or Flying Saucer (HTML→PDF) for invoices/statements/reports.
|
||
- **Server-side rendering** stays Thymeleaf; add small JS for dynamic price calc on the customer page.
|
||
|
||
---
|
||
|
||
## 3. Role & permission model
|
||
|
||
Replace the 2-value `Role` enum with a richer model:
|
||
|
||
```
|
||
Role (enum): ADMIN, STAFF, VENDOR, CUSTOMER
|
||
Permission (enum): MANAGE_FLEET, MANAGE_DRIVERS, MANAGE_VENDORS, MANAGE_BOOKINGS,
|
||
MANAGE_BILLING, VIEW_REPORTS, MANAGE_CONFIG, MANAGE_USERS
|
||
```
|
||
|
||
- `ADMIN` = all permissions. `STAFF` = a configurable subset (stored per-user).
|
||
- `VENDOR` = scoped to own data only (own cars, own trips, own settlements).
|
||
- Authorization: method-level `@PreAuthorize("hasAuthority('MANAGE_FLEET')")` on services/controllers.
|
||
|
||
---
|
||
|
||
## 4. Domain model (entities & key fields)
|
||
|
||
New entities in **bold**; modified existing in _italics_.
|
||
|
||
### 4.1 Organization / Config
|
||
- **Organization** — name, legalName, logoUrl, address, gstNumber, contactEmail, phone, currencyCode
|
||
- **SystemConfig** (singleton) — currencyCode, defaultTaxPercent, defaultCommissionPercent,
|
||
defaultDriverDailyCharge, invoicePrefix, settlementCycle (WEEKLY/MONTHLY)
|
||
- **Category** (generic master) — `type` (VEHICLE / DRIVER / CUSTOMER), name, description, active
|
||
→ replaces hard-coded enums so categories are admin-configurable
|
||
- _User_ — add `permissions` (set), `vendor` (nullable FK for vendor-portal users)
|
||
|
||
### 4.2 Fleet
|
||
- _Car_ — add: `yearOfRegistration`, `colour`, `ownership` (OWNED / VENDOR), `vendor` (nullable FK),
|
||
`hourlyRate`, `dailyRate` (rename pricePerDay), `monthlyRate`, `unitsTotal`,
|
||
`featureTags` (AC, GPS, … as a set/element-collection), `status` (ACTIVE / MAINTENANCE / RETIRED)
|
||
- **CarDocument** — car FK, docType (RC / INSURANCE / PERMIT / POLLUTION), fileUrl, issuedDate, expiryDate
|
||
- **CarPhoto** — car FK, url, sortOrder (gallery instead of single imageUrl)
|
||
|
||
### 4.3 Driver
|
||
- **Driver** — name, phone, licenceNumber, licenceExpiry, yearsExperience, category (FK Category),
|
||
employmentType (EMPLOYED / VENDOR), vendor (nullable FK), hourlyCharge, dailyCharge, monthlyCharge,
|
||
status (AVAILABLE / ON_TRIP / OFF), photoUrl
|
||
- **DriverDocument** — driver FK, docType, fileUrl, expiryDate
|
||
- Trip history derived from `Booking` where `driver = X`
|
||
|
||
### 4.4 Vendor
|
||
- **Vendor** — name, contactPerson, phone, email, address, gstNumber,
|
||
bankAccount/settlementDetails, commissionPercent (nullable → overrides global), active
|
||
- Vendor login = a `User` with ROLE_VENDOR linked to the Vendor
|
||
- **VendorSettlement** — vendor FK, periodStart, periodEnd, grossRevenue, commissionAmount,
|
||
driverCharges, netPayable, status (DRAFT / FINALISED / PAID), generatedAt
|
||
|
||
### 4.5 Customer
|
||
- _User_ (customer) — add: `customerCategory` (INDIVIDUAL / COMPANY / CORPORATE),
|
||
`companyName`, `gstNumber`, `billingAddress`, `contactPersons` (for company/corporate)
|
||
|
||
### 4.6 Booking & Billing
|
||
- _Booking_ — add: `driver` (nullable FK), `withDriver` (bool), `rentalUnit` (HOUR / DAY / MONTH),
|
||
`quantity` (units of the period), `vehicleCharge`, `driverCharge`, `taxPercent`, `taxAmount`,
|
||
`commissionPercent`, `commissionAmount`, `revenueOwner` (OWNED / VENDOR), `vendor` (nullable FK)
|
||
- **Invoice** — booking FK, invoiceNumber, issuedAt, lineItems, subtotal, tax, total, pdfUrl
|
||
- **CommissionRule** — scope (GLOBAL / VENDOR / VEHICLE), refId, percent
|
||
(resolution order: vehicle → vendor → global)
|
||
|
||
### 4.7 ER overview (relationships)
|
||
```
|
||
Organization 1─* User
|
||
User *─1 Vendor (vendor-portal users) Vendor 1─* Car
|
||
Vendor 1─* Driver Car 1─* CarDocument / CarPhoto
|
||
Category 1─* Car / Driver / User(customer) Driver 1─* DriverDocument
|
||
Customer(User) 1─* Booking Car 1─* Booking
|
||
Driver 1─* Booking (optional) Booking 1─1 Invoice
|
||
Vendor 1─* Booking (revenue attribution) Vendor 1─* VendorSettlement
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Calculation rules (single source of truth)
|
||
|
||
```
|
||
periodCount = ceil(duration in chosen unit) // HOUR / DAY / MONTH
|
||
vehicleCharge = rate(unit) × periodCount × units
|
||
driverCharge = withDriver ? driverRate(unit) × periodCount : 0
|
||
subtotal = vehicleCharge + driverCharge
|
||
taxAmount = subtotal × taxPercent/100
|
||
total = subtotal + taxAmount
|
||
|
||
// Vendor settlement (per vendor trip)
|
||
commissionPercent = resolve(vehicle → vendor → global)
|
||
commissionAmount = vehicleCharge × commissionPercent/100
|
||
netVendorPayable = vehicleCharge − commissionAmount + (vendorDriverCharge − orgDriverMargin)
|
||
|
||
// Owned vs vendor profit split tracked via Booking.revenueOwner
|
||
```
|
||
All money `BigDecimal`, `RoundingMode.HALF_UP`, scale 2, currency from `SystemConfig`.
|
||
|
||
---
|
||
|
||
## 6. Screen inventory
|
||
|
||
**Admin / Staff (`/admin`)**
|
||
- Dashboard (KPIs + owned-vs-vendor split), Fleet (list/form + docs/photos/maintenance),
|
||
Drivers (list/form/profile + trip history), Vendors (list/form + settlements),
|
||
Customers (list/detail), Bookings (list/detail/assign-driver/invoice),
|
||
Billing & Settlements, Reports (filter + export), Settings (org, config, categories, staff & permissions)
|
||
|
||
**Vendor portal (`/vendor`)** — new
|
||
- Login, Dashboard (own trips/revenue), My Cars, My Drivers, Trips (period filter),
|
||
Settlements (view + export PDF/Excel)
|
||
|
||
**Customer page (public)**
|
||
- Home, Car listing **with filters** (category, date, seating, transmission, price, driver option) + live price,
|
||
Car detail, Booking (with/without driver + category), Register/Login, My Bookings + invoices
|
||
|
||
---
|
||
|
||
## 7. Phased delivery plan
|
||
|
||
Each phase is independently shippable and ends with a working app + tests.
|
||
|
||
### Phase 0 — Foundations (enablers)
|
||
- Add Flyway; convert current schema to `V1__baseline.sql`; turn off `ddl-auto`
|
||
- Expand `Role` + add `Permission`; method security
|
||
- `Organization` + `SystemConfig` + `Category` master; Settings screens
|
||
- Replace hard-coded category enums with `Category` lookups (keep enums as seed data)
|
||
|
||
### Phase 1 — Fleet enrichment
|
||
- Car: year, colour, ownership, feature tags, hourly/daily/monthly rates, units, status(maintenance)
|
||
- CarDocument + CarPhoto with expiry tracking + expiry warnings on dashboard
|
||
- Maintenance blocking in availability logic
|
||
|
||
### Phase 2 — Driver module
|
||
- Driver entity + documents + categories + charges + availability
|
||
- Driver list/form/profile + trip history; driver-availability check
|
||
|
||
### Phase 3 — Vendor module
|
||
- Vendor onboarding + ROLE_VENDOR login + vendor filter chain (`/vendor/**`)
|
||
- Vendor dashboard (own cars/drivers/trips); commission config (global/vendor/vehicle)
|
||
|
||
### Phase 4 — Booking upgrades
|
||
- With/without driver + driver category assignment
|
||
- Hourly/daily/monthly periods; tax + driver-charge calc; revenue attribution
|
||
- Driver double-booking prevention; invoice generation (PDF)
|
||
|
||
### Phase 5 — Billing & settlement
|
||
- Invoices/receipts for customers
|
||
- Vendor settlement aggregation per cycle + statement (Excel + PDF) + profit split
|
||
|
||
### Phase 6 — Reporting
|
||
- Filtered reports (date, vehicle, category, driver, vendor, customer category, ownership, status)
|
||
- Excel + PDF export; summary dashboard (owned vs vendor); vendor-wise & driver-wise reports
|
||
|
||
### Phase 7 — Customer page polish
|
||
- Full filter set + live cost-by-duration; with-driver booking flow; responsive QA
|
||
|
||
---
|
||
|
||
## 8. Dependencies to add
|
||
- `flyway-core` + `flyway-database-postgresql`
|
||
- `org.apache.poi:poi-ooxml` (Excel)
|
||
- `com.github.librepdf:openpdf` **or** `org.xhtmlrenderer:flying-saucer-pdf` (PDF from Thymeleaf)
|
||
- (already present: web, security, oauth2-client, data-jpa, validation, thymeleaf, postgresql, lombok)
|
||
|
||
---
|
||
|
||
## 9. Cross-cutting concerns
|
||
- **Migrations**: every schema change via Flyway; never edit a shipped migration.
|
||
- **Validation**: bean validation + show `th:errors` on all admin/vendor forms (current admin forms lack this).
|
||
- **Auditing**: `createdAt/updatedAt/createdBy` via JPA auditing on money-bearing entities.
|
||
- **Performance**: fix N+1 in booking/report queries with fetch-joins; add pagination to all admin tables.
|
||
- **Files**: documents/photos need storage — decide local disk vs S3-compatible (config-driven path).
|
||
- **Testing**: service-layer unit tests for all calc rules; `@WebMvcTest` for access control per chain.
|
||
- **Seed data**: keep `DataInitializer` for org/config/admin + demo vendor/driver/cars.
|
||
|
||
---
|
||
|
||
## 10. Decisions (LOCKED — 2026-06-26, recommended defaults accepted)
|
||
1. **File storage** → **local filesystem** (config-driven path) for v1.
|
||
2. **PDF library** → **Flying Saucer** (Thymeleaf HTML/CSS → PDF).
|
||
3. **Tenancy** → **single organization** per install.
|
||
4. **Staff permissions** → **per-user permission checkboxes** (granular `Permission` set).
|
||
5. **Settlement cycle** → **monthly** default.
|
||
6. **Bookings** → **day/month** for v1 (hourly *rate fields* stored, hourly *booking flow* deferred).
|
||
|
||
### Deviation from §7
|
||
- **Flyway is deferred** to a later hardening phase. During active development the app keeps
|
||
`spring.jpa.hibernate.ddl-auto=update`, which additively creates the new tables/columns without
|
||
disrupting the running PostgreSQL database. Flyway baseline will be introduced before production.
|
||
|
||
> Plan locked. Implementation started with Phase 0 — Foundations.
|