# 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.