Files
TrisolarisServer/AGENTS.md
androidlover5842 4c20cbd7ca
All checks were successful
build-and-deploy / build-deploy (push) Successful in 35s
Add advance-booking cancellation policy engine
2026-02-02 09:20:27 +05:30

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

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 code in 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: RoomStay now supports soft void (is_voided), and room-stay audit events are written to room_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 hotel is available for server operations (e.g., ssh hotel). Use carefully; DB changes were done via sudo -u postgres psql on 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 hotel and sudo -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 hotel operations 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 (runs build/libs/*.jar).
  • Active profile: prod (see service Environment=SPRING_PROFILES_ACTIVE=prod).
  • DB (prod): PostgreSQL trisolaris on localhost:5432 (see /opt/deploy/TrisolarisServer/src/main/resources/application-prod.properties on the server).
  • DB (dev): PostgreSQL trisolaris on 192.168.1.53:5432 (see application-dev.properties in the repo).
  • DB access (server): sudo -u postgres psql -d trisolaris.
  • Workflow: Always run build, commit, and push for changes unless explicitly told otherwise.
  • Android workflow note: user always runs Shift+F10 in Android Studio to deploy updates.