248 lines
7.8 KiB
Markdown
248 lines
7.8 KiB
Markdown
PROJECT CONTEXT / SYSTEM BRIEF
|
|
|
|
This is a hotel-grade Property Management System (PMS) being rebuilt from scratch.
|
|
This AGENTS file captures both the product rules you gave and my current understanding of
|
|
the TrisolarisServer codebase as of the last read, so future sessions can resume accurately.
|
|
|
|
Tech stack
|
|
- Spring Boot monolith
|
|
- Kotlin only
|
|
- JPA / Hibernate
|
|
- PostgreSQL
|
|
- No Flyway for now, schema via JPA during development (Flyway is present in deps but disabled)
|
|
- Single API domain api.hoteltrisolaris.in
|
|
- Android app and future website consume the same APIs
|
|
|
|
This replaces a very old Firestore-based Android app. Old code exists only to understand behaviour. Do not reuse or mirror old models.
|
|
|
|
CORE DESIGN PRINCIPLES
|
|
|
|
Server is the only source of truth
|
|
Clients never calculate state
|
|
Clients send intent, server derives facts
|
|
|
|
Ledger-based design
|
|
Never store totals
|
|
Never overwrite money
|
|
Append rows and derive views
|
|
|
|
Three independent concerns
|
|
Occupancy handled by RoomStay
|
|
Charges handled by Charge
|
|
Payments handled by Payment
|
|
Invoices are derived views, not stored state
|
|
|
|
Room availability is by room number
|
|
Availability is derived from RoomStay
|
|
toAt = null means occupied
|
|
Category counts are only summaries
|
|
|
|
Room changes must never break billing
|
|
Changing rooms means closing one RoomStay and opening another
|
|
Charges are time-bound and linked to booking, optionally to room_stay
|
|
|
|
Multi-property from day one
|
|
Every domain object is scoped to property_id
|
|
Users belong to organization
|
|
Access is granted per property
|
|
|
|
Auth and access
|
|
User exists once as AppUser
|
|
Property access via PropertyUser
|
|
Roles are per property
|
|
Every API call must enforce property membership
|
|
|
|
CURRENT DOMAIN MODEL ALREADY CREATED
|
|
|
|
Organization
|
|
Property
|
|
AppUser
|
|
PropertyUser with roles
|
|
RoomType
|
|
Room
|
|
Booking
|
|
Guest
|
|
RoomStay
|
|
|
|
These entities already exist in Kotlin. Do not redesign unless explicitly asked.
|
|
|
|
WHAT THE SYSTEM MUST SUPPORT
|
|
|
|
Operational behaviour
|
|
- Staff sees exact room numbers free, occupied, checkout today
|
|
- Different rates for same room type
|
|
- Multiple rooms today and fewer tomorrow under the same booking
|
|
- Room changes without data loss
|
|
|
|
Financial behaviour
|
|
- Advance payments, partial payments, refunds
|
|
- PayU integration for QR and payment links
|
|
- Payment status via webhooks
|
|
- Clear source and destination of money
|
|
- Staff-wise collection tracking
|
|
|
|
Website integration
|
|
- Website reads live availability from PMS
|
|
- Website creates booking intents
|
|
- No inventory sync jobs
|
|
- Rate plans like DIRECT, WALKIN, OTA are snapshotted at booking time
|
|
|
|
Realtime
|
|
- Firestore-like realtime behaviour
|
|
- WebSocket or SSE for room board and payment updates
|
|
- Push notifications later via FCM
|
|
|
|
Infrastructure
|
|
- Nginx reverse proxy
|
|
- Single domain with multiple paths
|
|
- Database is never exposed publicly
|
|
|
|
IMPORTANT RULES FOR YOU
|
|
|
|
- Use Kotlin only
|
|
- Follow existing package structure
|
|
- No speculative features
|
|
- No premature microservices
|
|
- Flyway must remain disabled during development. Do not introduce or modify Flyway migrations unless explicitly instructed after schema stabilization.
|
|
- Propose schema or API changes before coding if unsure
|
|
- Money logic must be explicit and auditable
|
|
- Canonical staff roles for now are ADMIN, MANAGER, STAFF, HOUSEKEEPING, FINANCE. Other roles may exist later but must not be depended on unless asked.
|
|
- Booking is a lifecycle container only. Booking does not own rooms or money. Occupancy is only via RoomStay. Billing is only via Charge and Payment ledgers.
|
|
- Realtime features must emit derived domain events only. Clients must never subscribe to raw entity state or database changes.
|
|
|
|
HOW YOU SHOULD WORK
|
|
|
|
- Read the entire repository before making changes
|
|
- Work file by file
|
|
- Prefer small focused changes
|
|
- Ask before touching auth or payment logic
|
|
- Assume this will run in real production hotels
|
|
|
|
FIRST TASK
|
|
|
|
Do nothing until asked.
|
|
Likely upcoming tasks include room board API, charge ledger, payment and PayU webhook flow, booking check-in transaction.
|
|
|
|
===============================================================================
|
|
CURRENT CODEBASE UNDERSTANDING (TrisolarisServer)
|
|
===============================================================================
|
|
|
|
Repository
|
|
- Root: /home/androidlover5842/IdeaProjects/TrisolarisServer
|
|
- Language: Kotlin only (Spring Boot 4, JPA)
|
|
- Entry point: src/main/kotlin/com/android/trisolarisserver/TrisolarisServerApplication.kt
|
|
- Active controller layer is minimal (Rooms.kt is stubbed/commented)
|
|
|
|
Gradle
|
|
- build.gradle.kts uses:
|
|
- Spring Boot 4.0.1
|
|
- Kotlin 2.2.21 (kotlin("jvm"), kotlin("plugin.spring"), kotlin("plugin.jpa"))
|
|
- Java toolchain 19
|
|
- JPA, WebMVC, Validation, Security, WebSocket, Flyway (dep), Postgres
|
|
- Flyway is disabled in application.properties
|
|
|
|
Configuration
|
|
- src/main/resources/application.properties
|
|
- spring.jpa.hibernate.ddl-auto=update
|
|
- spring.jpa.open-in-view=false
|
|
- flyway.enabled=false
|
|
- application-dev.properties -> jdbc:postgresql://192.168.1.53:5432/trisolaris
|
|
- application-prod.properties -> jdbc:postgresql://localhost:5432/trisolaris
|
|
- DB password via env: DB_PASSWORD
|
|
|
|
Current packages and code
|
|
|
|
com.android.trisolarisserver.component
|
|
- PropertyAccess
|
|
- requireMember(propertyId, userId) -> checks PropertyUserRepo
|
|
- requireAnyRole(propertyId, userId, roles) -> checks roles
|
|
|
|
com.android.trisolarisserver.db.repo
|
|
- PropertyUserRepo
|
|
- existsByIdPropertyIdAndIdUserId(...)
|
|
- hasAnyRole(...) via JPQL joining property_user_role
|
|
- RoomRepo
|
|
- findFreeRooms(propertyId): active, not maintenance, no open RoomStay
|
|
- findOccupiedRooms(propertyId): rooms with active RoomStay
|
|
|
|
com.android.trisolarisserver.controller
|
|
- Rooms.kt: placeholder, no active endpoints yet
|
|
|
|
Entity model (current Kotlin entities)
|
|
- Organization
|
|
- id (uuid), name, createdAt
|
|
- Property
|
|
- id (uuid)
|
|
- org (Organization)
|
|
- code, name, timezone, currency
|
|
- active, createdAt
|
|
- AppUser
|
|
- id (uuid)
|
|
- org (Organization)
|
|
- firebaseUid, phoneE164, name
|
|
- disabled, createdAt
|
|
- PropertyUser
|
|
- composite key PropertyUserId (propertyId, userId)
|
|
- property (Property), user (AppUser)
|
|
- roles (ElementCollection of Role)
|
|
- Role enum
|
|
- ADMIN, MANAGER, STAFF, HOUSEKEEPING, FINANCE, GUIDE, SUPERVISOR, AGENT
|
|
- RoomType
|
|
- id (uuid)
|
|
- property (Property)
|
|
- code, name, baseOccupancy, maxOccupancy, createdAt
|
|
- Room
|
|
- id (uuid)
|
|
- property (Property)
|
|
- roomType (RoomType)
|
|
- roomNumber, floor
|
|
- hasNfc, active, maintenance, notes
|
|
- Booking
|
|
- id (uuid)
|
|
- property (Property)
|
|
- primaryGuest (Guest)
|
|
- status (BookingStatus)
|
|
- source, sourceBookingId
|
|
- checkinAt, checkoutAt
|
|
- expectedCheckinAt, expectedCheckoutAt
|
|
- notes
|
|
- createdBy (AppUser)
|
|
- createdAt, updatedAt
|
|
- BookingStatus enum
|
|
- OPEN, CHECKED_IN, CHECKED_OUT, CANCELLED, NO_SHOW
|
|
- Guest
|
|
- id (uuid)
|
|
- org (Organization)
|
|
- phoneE164, name, nationality
|
|
- addressText
|
|
- createdAt, updatedAt
|
|
- RoomStay
|
|
- id (uuid)
|
|
- property (Property)
|
|
- booking (Booking)
|
|
- room (Room)
|
|
- fromAt, toAt (null = active occupancy)
|
|
- createdBy (AppUser)
|
|
- createdAt
|
|
|
|
Notes on schema vs migration file
|
|
- There is a Flyway migration file at src/main/resources/db/migration/V1__core.sql,
|
|
but Flyway is disabled. The SQL file does NOT match current Kotlin entities in
|
|
multiple places (columns and tables differ). For now, JPA schema generation is
|
|
authoritative during development.
|
|
|
|
Gaps relative to target design (do not implement unless asked)
|
|
- No Charge entity yet
|
|
- No Payment entity yet
|
|
- No ledger/derived views
|
|
- No API controllers/services for bookings, rooms, payments
|
|
- No auth filter or principal model wired (PropertyAccess expects userId)
|
|
- No WebSocket/SSE endpoints yet
|
|
|
|
Behavioral requirements to keep in mind when coding
|
|
- Every domain object must include property scope
|
|
- Room availability derived from RoomStay toAt == null
|
|
- Room changes are new RoomStay + closing old
|
|
- Charges and payments are append-only (never overwrite totals)
|
|
- Clients send intent; server derives facts
|