move card issuence server side

This commit is contained in:
androidlover5842
2026-01-24 23:53:03 +05:30
parent ab7f02ddc6
commit 094673b475
7 changed files with 553 additions and 95 deletions

181
AGENTS.md
View File

@@ -1,67 +1,36 @@
PROJECT CONTEXT / SYSTEM BRIEF
This is a hotel-grade Property Management System (PMS) being rebuilt from scratch.
This AGENTS file captures the product rules + current codebase state.
This AGENTS file captures product rules + current codebase state.
Tech stack
- Spring Boot monolith
- Kotlin only
- JPA / Hibernate
- PostgreSQL
- No Flyway for now, schema via JPA during development (Flyway deps present but disabled)
- Flyway deps present but disabled (no migrations during dev)
- Single API domain api.hoteltrisolaris.in
- Android app and future website consume the same APIs
Server specs (current)
- CPU: i5-8400
- RAM: 48 GB
- GPU: RTX 3060 (used for llama.cpp)
Legacy note
Old Firestore Android app exists only to understand behavior. Do not reuse old models.
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.
- Users belong to org; access granted per property.
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
IMMUTABLE RULES
- 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.
- Canonical staff roles: ADMIN, MANAGER, STAFF, HOUSEKEEPING, FINANCE (other roles may exist but must not be depended on)
- Booking is a lifecycle container only. Booking does not own rooms or money. Occupancy via RoomStay. Billing via Charge/Payment ledgers.
- Realtime must emit derived events only (no raw entity subscriptions)
- Ask before touching auth or payment logic
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)
@@ -73,72 +42,94 @@ Repository
- Scheduling enabled (@EnableScheduling)
Security/Auth
- Firebase Admin auth for every request, Firebase UID required.
- Security filter verifies token and maps to MyPrincipal(userId, firebaseUid).
- Endpoints: /auth/verify and /auth/me.
- Firebase Admin auth for every request; Firebase UID required.
- /auth/verify and /auth/me.
Domain entities
- Organization: id, name, emailAliases
- Property: org, code, name, addressText, timezone, currency, active, emailAddresses, otaAliases
- AppUser: org, firebaseUid, phoneE164, name, disabled
- PropertyUser: roles per property
- Role enum includes ADMIN, MANAGER, STAFF, HOUSEKEEPING, FINANCE, GUIDE, SUPERVISOR, AGENT (but only canonical roles should be used)
- RoomType: code/name/occupancy + otaAliases
- Room: roomNumber, floor, hasNfc, active, maintenance, notes
- Booking: status, source/sourceBookingId, expected check-in/out, emailAuditPdfUrl
- Guest
- RoomStay
- GuestDocument: files for guest/booking with AI-extracted data
- InboundEmail: inbound mail audit (PDF + raw eml), extractedData, status
Repos
- Repos are under com.android.trisolarisserver.repo (note: not db.repo).
- Added repos for Booking, Guest, GuestDocument, InboundEmail.
- Organization: name, emailAliases, allowedTransportModes.
- Property: code, name, addressText, emailAddresses, otaAliases, allowedTransportModes.
- AppUser, PropertyUser (roles per property).
- RoomType: code/name/occupancy + otaAliases.
- Room: roomNumber, floor, hasNfc, active, maintenance, notes.
- Booking: status, expected check-in/out, emailAuditPdfUrl, transportMode, transportVehicleNumber.
- Guest (org-scoped).
- RoomStay.
- RoomStayChange (idempotent room move).
- IssuedCard (cardId, cardIndex, issuedAt, expiresAt, issuedBy, revokedAt).
- PropertyCardCounter (per-property cardIndex counter).
- GuestDocument (files + AI-extracted json).
- GuestVehicle (org-scoped vehicle numbers).
- InboundEmail (audit PDF + raw EML, extracted json, status).
- RoomImage (original + thumbnail).
Key modules
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
Availability derived from RoomStay. Date range uses overlap [from, to).
Room types
- CRUD with otaAliases in DTOs.
- CRUD with otaAliases.
Properties/Orgs
- Property create/update accept addressText, otaAliases, emailAddresses.
- Org create/get returns emailAliases.
Properties / Orgs
- Property create/update accepts addressText, otaAliases, emailAddresses, allowedTransportModes.
- Org create/get returns emailAliases + allowedTransportModes.
Guest documents (files)
- POST /properties/{propertyId}/guests/{guestId}/documents (multipart + bookingId)
- GET list
- GET file (token or auth)
- Files stored under /home/androidlover5842/docs/{propertyId}/{guestId}/{bookingId}/
- AI extraction via llama.cpp with strict system prompt
Booking flow
- /bookings/{id}/check-in (creates RoomStay rows)
- /bookings/{id}/check-out (closes RoomStay)
- /bookings/{id}/cancel, /no-show
- /bookings/{id}/room-stays (pre-assign RoomStay with date range)
- /room-stays/{id}/change-room (idempotent via RoomStayChange)
Card issuing
- /room-stays/{id}/cards/prepare -> returns cardIndex + sector0 payload
- /room-stays/{id}/cards -> store issued card
- /room-stays/{id}/cards (list)
- /room-stays/cards/{id}/revoke (ADMIN only)
Guest APIs
- /properties/{propertyId}/guests/search?phone=... or ?vehicleNumber=...
- /properties/{propertyId}/guests/{guestId}/vehicles (add vehicle)
Guest documents
- /properties/{propertyId}/guests/{guestId}/documents (upload/list/file)
- AI extraction with strict system prompt.
Room images
- /properties/{propertyId}/rooms/{roomId}/images (upload/list/file)
- Thumbnails generated (320px).
Transport modes
- /properties/{propertyId}/transport-modes -> returns enabled list (property > org > default all).
Inbound email ingestion
- IMAP poller (1 min) with enable flag.
- Saves audit PDF + raw .eml to /home/androidlover5842/docs/emails
- Matches property via To/CC email first, then text aliases (name/code/address/otaAliases)
- AI extracts booking fields and creates/cancels Booking
- Booking gets emailAuditPdfUrl that points to /properties/{propertyId}/inbound-emails/{emailId}/file
- 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.
- Booking emailAuditPdfUrl -> /properties/{propertyId}/inbound-emails/{emailId}/file
- Manual upload: POST /properties/{propertyId}/inbound-emails/manual (PDF).
Realtime
- SSE room board events with heartbeat, on room create/update, check-in/out, and room change.
AI integration
- Base URL configured per profile:
- dev: https://ai.hoteltrisolaris.in/v1/chat/completions
- prod: http://localhost:8089/v1/chat/completions
- LlamaClient uses strict system prompt: only visible text, no guessing.
- 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
- application.properties: flyway disabled, storage paths, IMAP config, token secrets.
- storage.documents.publicBaseUrl + token secret/ttl.
- storage.emails.publicBaseUrl used for booking audit URL.
- mail.imap.enabled=false by default.
- 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
- API user creation removed; users are created by app; API only manages roles.
- Users are created by app; API only manages roles.
- Admin can assign ADMIN/MANAGER/STAFF/AGENT; Manager can assign STAFF/AGENT.
- Agents can only see free rooms.