12 KiB
12 KiB
PROJECT CONTEXT / SYSTEM BRIEF
This is a hotel-grade Property Management System (PMS) being rebuilt from scratch. This AGENTS file captures product rules + current codebase state.
Tech stack
- Spring Boot monolith
- Kotlin only
- JPA / Hibernate
- PostgreSQL
- Flyway deps present but disabled (no migrations during dev)
- Single API domain api.hoteltrisolaris.in Server specs (current)
- CPU: i5-8400
- RAM: 48 GB
- GPU: RTX 3060 (used for llama.cpp)
Core principles
- Server is source of truth; clients send intent.
- Ledger-based design: never store totals; append rows only.
- Occupancy = RoomStay. Billing = Charge. Payments = Payment. Invoices are derived.
- Room availability by room number; toAt=null means occupied.
- Room change = close old RoomStay + open new one.
- Multi-property: every domain object scoped to property_id.
- AppUser is global; access granted per property.
Immutable rules
- Use Kotlin only; no microservices.
- Flyway must remain disabled until schema stabilizes.
- Canonical staff roles: ADMIN, MANAGER, STAFF, HOUSEKEEPING, FINANCE.
- Booking does not own rooms or money.
- Realtime events must be derived, not raw DB changes.
- Ask before touching auth or payment logic.
=============================================================================== CURRENT CODEBASE UNDERSTANDING (TrisolarisServer)
Repository
- Root: /home/androidlover5842/IdeaProjects/TrisolarisServer
- Entry: src/main/kotlin/com/android/trisolarisserver/TrisolarisServerApplication.kt
- Scheduling enabled (@EnableScheduling)
- Package layout (domain subpackages; keep top-level grouping):
- controller/{auth,booking,guest,room,rate,property,payment,card,email,document,common,system,assets,transport,razorpay}
- controller/dto/{booking,guest,payment,property,rate,room,razorpay}
- repo/{booking,guest,room,rate,property,card,email,razorpay}
- component/{ai,auth,booking,document,geo,room,sse,storage,razorpay}
- config/{core,db,booking,room,rate,guest,payment,card,razorpay}
- service/email
Security/Auth
- Firebase Admin auth for every request; Firebase UID required.
- /auth/verify and /auth/me.
Domain entities
- Property: code, name, addressText, emailAddresses, otaAliases, allowedTransportModes.
- AppUser (global, superAdmin), PropertyUser (roles per property).
- RoomType: code/name/occupancy + otaAliases + defaultRate.
- Room: roomNumber, floor, hasNfc, active, maintenance, notes.
- Booking: status, expected check-in/out, emailAuditPdfUrl, transportMode.
- Guest (property-scoped).
- RoomStay (rate fields stored on stay).
- RoomStayChange (idempotent room move).
- IssuedCard (cardId, cardIndex, issuedAt, expiresAt, issuedBy, revokedAt).
- PropertyCardCounter (per-property cardIndex counter).
- RatePlan + RateCalendar.
- Payment (ledger).
- GuestDocument (files + AI-extracted json).
- GuestVehicle (property-scoped vehicle numbers).
- InboundEmail (audit PDF + raw EML, extracted json, status).
- RoomImage (original + thumbnail).
Key modules
Auth
- /auth/verify
- /auth/me
Properties / Users
- POST /properties (creator becomes ADMIN on that property)
- GET /properties (super admin gets all; others get memberships)
- PUT /properties/{propertyId}
- GET /properties/{propertyId}/users
- PUT /properties/{propertyId}/users/{userId}/roles
- DELETE /properties/{propertyId}/users/{userId} (ADMIN only)
Rooms / inventory
- /properties/{propertyId}/rooms
- /properties/{propertyId}/rooms/board
- /properties/{propertyId}/rooms/board/stream (SSE)
- /properties/{propertyId}/rooms/availability
- /properties/{propertyId}/rooms/availability-range?from=YYYY-MM-DD&to=YYYY-MM-DD
- Public availability:
- GET /properties/{propertyId}/rooms/available
- GET /properties/{propertyId}/rooms/by-type/{roomTypeCode}?availableOnly=true|false
Room types
- POST /properties/{propertyId}/room-types
- GET /properties/{propertyId}/room-types
- GET /properties/{propertyId}/room-types/{roomTypeCode}/rate?date=YYYY-MM-DD&ratePlanCode=optional
- PUT /properties/{propertyId}/room-types/{roomTypeId}
- DELETE /properties/{propertyId}/room-types/{roomTypeId}
Properties
- Property create/update accepts addressText, otaAliases, emailAddresses, allowedTransportModes.
Booking flow
- POST /properties/{propertyId}/bookings (create booking)
- /properties/{propertyId}/bookings/{bookingId}/check-in/bulk (creates RoomStay rows with per-stay rates)
- /properties/{propertyId}/bookings/{bookingId}/check-out (closes RoomStay)
- /properties/{propertyId}/bookings/{bookingId}/room-stays/{roomStayId}/check-out (closes specific stay; single-stay booking auto-closes booking)
- /properties/{propertyId}/bookings/{bookingId}/cancel
- /properties/{propertyId}/bookings/{bookingId}/no-show
- /properties/{propertyId}/bookings/{bookingId}/room-requests (room-type quantity reservation)
- /properties/{propertyId}/bookings/{bookingId}/room-requests/{requestId} (cancel reservation)
- /properties/{propertyId}/room-stays/{roomStayId}/void (soft-void active stay)
- /properties/{propertyId}/cancellation-policy (get/update policy)
Card issuing
- /properties/{propertyId}/room-stays/{roomStayId}/cards/prepare -> returns cardIndex + sector0 payload
- /properties/{propertyId}/room-stays/{roomStayId}/cards -> store issued card
- /properties/{propertyId}/room-stays/{roomStayId}/cards (list)
- /properties/{propertyId}/room-stays/cards/{cardIndex}/revoke (ADMIN; MANAGER allowed only for temp cards)
- Temp cards (room-only, 7 min expiry):
- POST /properties/{propertyId}/rooms/{roomId}/cards/prepare-temp
- POST /properties/{propertyId}/rooms/{roomId}/cards/temp
Guest APIs
- POST /properties/{propertyId}/guests
- /properties/{propertyId}/guests/search?phone=... or ?vehicleNumber=...
- /properties/{propertyId}/guests/{guestId}/vehicles (add vehicle)
- POST /properties/{propertyId}/guests/{guestId}/signature
- GET /properties/{propertyId}/guests/{guestId}/signature/file
Room stays
- POST /properties/{propertyId}/room-stays/{roomStayId}/change-rate
Rate plans
- POST /properties/{propertyId}/rate-plans
- GET /properties/{propertyId}/rate-plans
- PUT /properties/{propertyId}/rate-plans/{ratePlanId}
- DELETE /properties/{propertyId}/rate-plans/{ratePlanId}
- POST /properties/{propertyId}/rate-plans/{ratePlanId}/calendar
- GET /properties/{propertyId}/rate-plans/{ratePlanId}/calendar?from=YYYY-MM-DD&to=YYYY-MM-DD
- DELETE /properties/{propertyId}/rate-plans/{ratePlanId}/calendar/{rateDate}
Payments
- POST /properties/{propertyId}/bookings/{bookingId}/payments
- GET /properties/{propertyId}/bookings/{bookingId}/payments
- GET /properties/{propertyId}/bookings/{bookingId}/balance
- DELETE /properties/{propertyId}/bookings/{bookingId}/payments/{paymentId} (ADMIN/super admin; CASH only; booking OPEN or CHECKED_IN)
Guest documents
- /properties/{propertyId}/guests/{guestId}/documents (upload/list)
- /properties/{propertyId}/guests/{guestId}/documents/{documentId}/file
- AI extraction with strict system prompt.
- DELETE /properties/{propertyId}/guests/{guestId}/documents/{documentId} (ADMIN/MANAGER; booking OPEN or CHECKED_IN; deletes file + row)
- Document file endpoint accepts Firebase auth (ADMIN/MANAGER) or token query param.
- AI extraction is queued (single-thread) to limit concurrency.
- storage.documents.aiBaseUrl supported for llama fetch (defaults to publicBaseUrl; use http for llama).
Room images
- /properties/{propertyId}/rooms/{roomId}/images (upload/list)
- /properties/{propertyId}/rooms/{roomId}/images/{imageId}/file
- Thumbnails generated (320px).
Transport modes
- /properties/{propertyId}/transport-modes -> returns enabled list (property or default all).
Inbound email ingestion
- IMAP poller (1 min) with enable flag.
- Saves audit PDF + raw .eml under /home/androidlover5842/docs/emails.
- Property match: To/CC email first; fallback to name/code/address/otaAliases.
- AI extracts booking fields; creates/cancels Booking.
- /properties/{propertyId}/inbound-emails/{emailId}/file (audit PDF)
- POST /properties/{propertyId}/inbound-emails/manual (PDF upload)
Realtime
- SSE room board events with heartbeat, on room create/update, check-in/out, and room change.
AI integration
- Base URL per profile: dev=https://ai.hoteltrisolaris.in/v1/chat/completions, prod=http://localhost:8089/v1/chat/completions
- LlamaClient uses strict system prompt (no guessing).
- Read timeout 5 minutes.
Config
- storage.documents.root=/home/androidlover5842/docs
- storage.emails.root=/home/androidlover5842/docs/emails
- storage.rooms.root=/home/androidlover5842/docs/rooms
- publicBaseUrl entries for docs/emails/rooms
- mail.imap.enabled=false by default
Notes / constraints
- Users are created by app; API only manages roles.
- Super admin can create properties and assign users to properties.
- Admin can assign ADMIN/MANAGER/STAFF/AGENT; Manager can assign STAFF/AGENT.
- Agents can only see free rooms.
- Role hierarchy for visibility/management: SUPER_ADMIN > ADMIN > MANAGER > STAFF/HOUSEKEEPING/FINANCE/SUPERVISOR/GUIDE > AGENT. Users cannot see anyone above their rank in property user lists. Access code invites cannot assign ADMIN.
- Property code is auto-generated (7-char random, no fixed prefix). Property create no longer accepts
codein request. Join-by-code uses property code, not propertyId. - Property access codes: 6-digit PIN, 1-minute expiry, single-use. Admin generates; staff joins with property code + PIN.
- Property user disable is property-scoped (not global); hierarchy applies for who can disable.
- Room stay lifecycle:
RoomStaynow supports soft void (is_voided), and room-stay audit events are written toroom_stay_audit_log. - Checkout supports both booking-level and specific room-stay checkout; specific checkout endpoint:
POST /properties/{propertyId}/bookings/{bookingId}/room-stays/{roomStayId}/check-out. - Staff can change/void stays only before first payment on booking; manager/admin can act after payments.
- Checkout validation: nightly rate must be within +/-20% of room type default rate (when default rate exists), and minimum stay duration must be at least 1 hour.
- Room-type reservations: use booking room requests (
booking_room_request) for quantity holds without room numbers; availability checks include active requests + occupied stays. - Cancellation policy engine (advance bookings): policy per property with
freeDaysBeforeCheckin+penaltyMode(NO_CHARGE,ONE_NIGHT,FULL_STAY). On cancel/no-show, penalty charge ledger rows are auto-created (CANCELLATION_PENALTY/NO_SHOW_PENALTY) when within penalty window.
Operational notes
- Payment provider migrated: PayU removed; Razorpay now used for settings, QR, payment links, and webhooks.
- Server access: SSH host alias
hotelis available for server operations (e.g.,ssh hotel). Use carefully; DB changes were done viasudo -u postgres psqlon the server when needed. - Schema changes: schema fix classes have been removed. If a new column/table is required, apply it manually on the server using
ssh hotelandsudo -u postgres psql -d trisolaris, e.g.alter table ... add column .... Keep a note of the exact SQL applied. - Agent workflow expectation: when schema/runtime issues require server-side SQL or service checks, execute the required
ssh hoteloperations directly and report what was changed; do not block on asking for confirmation in normal flow.
Access / ops notes (prod)
- Service:
TrisolarisServer.service(systemd).systemctl cat TrisolarisServer.service. - Deploy path:
/opt/deploy/TrisolarisServer(runsbuild/libs/*.jar). - Active profile:
prod(see service Environment=SPRING_PROFILES_ACTIVE=prod). - DB (prod): PostgreSQL
trisolarisonlocalhost:5432(see/opt/deploy/TrisolarisServer/src/main/resources/application-prod.propertieson the server). - DB (dev): PostgreSQL
trisolarison192.168.1.53:5432(seeapplication-dev.propertiesin the repo). - DB access (server):
sudo -u postgres psql -d trisolaris. - Workflow: Always run build, commit, and push for changes unless explicitly told otherwise.
- API docs policy (mandatory):
- For every API change (
add,update,delete, path change, request/response change, role change, validation/error change), updatedocs/API_REFERENCE.txtin the same endpoint-by-endpoint text format already used there. - Keep each API block in this style:
"<Name> API is this one:"->METHOD /path->What it does->Request body->Allowed roles->Error Codes. - Script-generated API docs are forbidden. Documentation updates must be manual edits only.
- For every API change (
- Android workflow note: user always runs Shift+F10 in Android Studio to deploy updates.