7.8 KiB
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