Add full API catalog doc and enforce API doc updates in AGENTS
All checks were successful
build-and-deploy / build-deploy (push) Successful in 20s

This commit is contained in:
androidlover5842
2026-02-04 11:57:32 +05:30
parent d94b9dc337
commit aa319401d2
2 changed files with 198 additions and 0 deletions

View File

@@ -205,6 +205,7 @@ Notes / constraints
- 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.
- API documentation source of truth: `docs/API_CATALOG.md`. Any API addition, removal, path change, method change, or behavior-impacting request/response change must update this doc in the same commit.
Operational notes
- Payment provider migrated: PayU removed; Razorpay now used for settings, QR, payment links, and webhooks.
@@ -220,4 +221,5 @@ Access / ops notes (prod)
- 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.
- Workflow rule for API changes: after code changes, update `docs/API_CATALOG.md`, then build, commit, and push.
- Android workflow note: user always runs Shift+F10 in Android Studio to deploy updates.

196
docs/API_CATALOG.md Normal file
View File

@@ -0,0 +1,196 @@
# API Catalog
Source of truth for implemented HTTP endpoints. Generated from controller annotations in `src/main/kotlin/com/android/trisolarisserver/controller`.
- Total endpoints: **125**
- Columns: method, path, handler (controller function).
## System
| Method | Path | Handler |
|---|---|---|
| `GET` | `/` | `src/main/kotlin/com/android/trisolarisserver/controller/system/Health.kt:13` (`root`) |
| `GET` | `/health` | `src/main/kotlin/com/android/trisolarisserver/controller/system/Health.kt:8` (`health`) |
## Auth
| Method | Path | Handler |
|---|---|---|
| `GET` | `/auth/me` | `src/main/kotlin/com/android/trisolarisserver/controller/auth/Auth.kt:43` (`me`) |
| `PUT` | `/auth/me` | `src/main/kotlin/com/android/trisolarisserver/controller/auth/Auth.kt:53` (`updateMe`) |
| `POST` | `/auth/verify` | `src/main/kotlin/com/android/trisolarisserver/controller/auth/Auth.kt:32` (`verify`) |
## Properties & Users
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:91` (`listProperties`) |
| `POST` | `/properties` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:51` (`createProperty`) |
| `POST` | `/properties/access-codes/join` | `src/main/kotlin/com/android/trisolarisserver/controller/property/PropertyAccessCodes.kt:89` (`joinWithAccessCode`) |
| `PUT` | `/properties/{propertyId}` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:305` (`updateProperty`) |
| `POST` | `/properties/{propertyId}/access-codes` | `src/main/kotlin/com/android/trisolarisserver/controller/property/PropertyAccessCodes.kt:43` (`createAccessCode`) |
| `GET` | `/properties/{propertyId}/billing-policy` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:117` (`getBillingPolicy`) |
| `PUT` | `/properties/{propertyId}/billing-policy` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:134` (`updateBillingPolicy`) |
| `GET` | `/properties/{propertyId}/bookings` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:186` (`listBookings`) |
| `POST` | `/properties/{propertyId}/bookings` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:96` (`createBooking`) |
| `GET` | `/properties/{propertyId}/code` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:104` (`getPropertyCode`) |
| `GET` | `/properties/{propertyId}/razorpay-settings` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpaySettingsController.kt:32` (`getSettings`) |
| `PUT` | `/properties/{propertyId}/razorpay-settings` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpaySettingsController.kt:56` (`upsertSettings`) |
| `POST` | `/properties/{propertyId}/razorpay/return/failure` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayReturnController.kt:20` (`failure`) |
| `POST` | `/properties/{propertyId}/razorpay/return/success` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayReturnController.kt:14` (`success`) |
| `POST` | `/properties/{propertyId}/razorpay/webhook` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayWebhookCapture.kt:50` (`capture`) |
| `GET` | `/properties/{propertyId}/users` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:164` (`listPropertyUsers`) |
| `GET` | `/properties/{propertyId}/users/search` | `src/main/kotlin/com/android/trisolarisserver/controller/property/UserDirectory.kt:49` (`searchPropertyUsers`) |
| `DELETE` | `/properties/{propertyId}/users/{userId}` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:288` (`deletePropertyUser`) |
| `PUT` | `/properties/{propertyId}/users/{userId}/disabled` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:239` (`updatePropertyUserDisabled`) |
| `PUT` | `/properties/{propertyId}/users/{userId}/roles` | `src/main/kotlin/com/android/trisolarisserver/controller/property/Properties.kt:188` (`upsertPropertyUserRoles`) |
| `GET` | `/users` | `src/main/kotlin/com/android/trisolarisserver/controller/property/UserDirectory.kt:26` (`listAppUsers`) |
## Bookings
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/bookings/{bookingId}` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:280` (`getBooking`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/balance` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingBalances.kt:31` (`getBalance`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/billing-policy` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:473` (`updateBillingPolicy`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/cancel` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:692` (`cancel`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/charges` | `src/main/kotlin/com/android/trisolarisserver/controller/payment/Charges.kt:79` (`list`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/charges` | `src/main/kotlin/com/android/trisolarisserver/controller/payment/Charges.kt:41` (`create`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/check-in/bulk` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:350` (`bulkCheckIn`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/check-out` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:524` (`checkOut`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/expected-dates` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:427` (`updateExpectedDates`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/link-guest` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:323` (`linkGuest`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/no-show` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:717` (`noShow`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/payments` | `src/main/kotlin/com/android/trisolarisserver/controller/payment/Payments.kt:85` (`list`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments` | `src/main/kotlin/com/android/trisolarisserver/controller/payment/Payments.kt:45` (`create`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/close` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayPaymentRequestsController.kt:92` (`closeRequest`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/payment-link` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayPaymentLinksController.kt:45` (`createPaymentLink`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:291` (`listQr`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:54` (`createQr`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/active` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:156` (`getActiveQr`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/close` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:178` (`closeActiveQr`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/{qrId}/close` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:210` (`closeQrById`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/{qrId}/events` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:243` (`qrEvents`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/{qrId}/events/stream` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayQrPayments.kt:272` (`streamQrEvents`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/refund` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayRefundsController.kt:41` (`refund`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/payments/razorpay/requests` | `src/main/kotlin/com/android/trisolarisserver/controller/razorpay/RazorpayPaymentRequestsController.kt:44` (`listRequests`) |
| `DELETE` | `/properties/{propertyId}/bookings/{bookingId}/payments/{paymentId}` | `src/main/kotlin/com/android/trisolarisserver/controller/payment/Payments.kt:101` (`delete`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/room-requests` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingRoomRequests.kt:102` (`list`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/room-requests` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingRoomRequests.kt:45` (`create`) |
| `DELETE` | `/properties/{propertyId}/bookings/{bookingId}/room-requests/{requestId}` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingRoomRequests.kt:118` (`cancel`) |
| `POST` | `/properties/{propertyId}/bookings/{bookingId}/room-stays/{roomStayId}/check-out` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:580` (`checkOutRoomStay`) |
| `GET` | `/properties/{propertyId}/bookings/{bookingId}/stream` | `src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt:301` (`streamBooking`) |
## Guests & Documents
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/guests/search` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:74` (`search`) |
| `GET` | `/properties/{propertyId}/guests/visit-count` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:112` (`getVisitCount`) |
| `GET` | `/properties/{propertyId}/guests/{guestId}` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:101` (`getGuest`) |
| `PUT` | `/properties/{propertyId}/guests/{guestId}` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:44` (`updateGuest`) |
| `GET` | `/properties/{propertyId}/guests/{guestId}/documents` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestDocuments.kt:124` (`listDocuments`) |
| `POST` | `/properties/{propertyId}/guests/{guestId}/documents` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestDocuments.kt:63` (`uploadDocument`) |
| `GET` | `/properties/{propertyId}/guests/{guestId}/documents/stream` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestDocuments.kt:137` (`streamDocuments`) |
| `DELETE` | `/properties/{propertyId}/guests/{guestId}/documents/{documentId}` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestDocuments.kt:181` (`deleteDocument`) |
| `GET` | `/properties/{propertyId}/guests/{guestId}/documents/{documentId}/file` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestDocuments.kt:151` (`downloadDocument`) |
| `GET` | `/properties/{propertyId}/guests/{guestId}/ratings` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestRatings.kt:78` (`list`) |
| `POST` | `/properties/{propertyId}/guests/{guestId}/ratings` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/GuestRatings.kt:40` (`create`) |
| `POST` | `/properties/{propertyId}/guests/{guestId}/signature` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:168` (`uploadSignature`) |
| `GET` | `/properties/{propertyId}/guests/{guestId}/signature/file` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:193` (`downloadSignature`) |
| `POST` | `/properties/{propertyId}/guests/{guestId}/vehicles` | `src/main/kotlin/com/android/trisolarisserver/controller/guest/Guests.kt:128` (`addVehicle`) |
## Rooms & Images
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/rooms` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:65` (`listRooms`) |
| `POST` | `/properties/{propertyId}/rooms` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:276` (`createRoom`) |
| `GET` | `/properties/{propertyId}/rooms/availability` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:125` (`roomAvailability`) |
| `GET` | `/properties/{propertyId}/rooms/availability-range` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:183` (`roomAvailabilityRange`) |
| `GET` | `/properties/{propertyId}/rooms/available` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:146` (`availableRooms`) |
| `GET` | `/properties/{propertyId}/rooms/available-range-with-rate` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:220` (`availableRoomsWithRate`) |
| `GET` | `/properties/{propertyId}/rooms/board` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:85` (`roomBoard`) |
| `GET` | `/properties/{propertyId}/rooms/board/stream` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:113` (`roomBoardStream`) |
| `GET` | `/properties/{propertyId}/rooms/by-type/{roomTypeCode}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:159` (`roomsByType`) |
| `DELETE` | `/properties/{propertyId}/rooms/{roomId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:365` (`deleteRoom`) |
| `PUT` | `/properties/{propertyId}/rooms/{roomId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt:322` (`updateRoom`) |
| `POST` | `/properties/{propertyId}/rooms/{roomId}/cards/prepare-temp` | `src/main/kotlin/com/android/trisolarisserver/controller/card/TemporaryRoomCards.kt:43` (`prepareTemporary`) |
| `POST` | `/properties/{propertyId}/rooms/{roomId}/cards/temp` | `src/main/kotlin/com/android/trisolarisserver/controller/card/TemporaryRoomCards.kt:71` (`issueTemporary`) |
| `GET` | `/properties/{propertyId}/rooms/{roomId}/images` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:54` (`list`) |
| `POST` | `/properties/{propertyId}/rooms/{roomId}/images` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:83` (`upload`) |
| `PUT` | `/properties/{propertyId}/rooms/{roomId}/images/reorder-room` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:196` (`reorderRoomImages`) |
| `PUT` | `/properties/{propertyId}/rooms/{roomId}/images/reorder-room-type` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:224` (`reorderRoomTypeImages`) |
| `DELETE` | `/properties/{propertyId}/rooms/{roomId}/images/{imageId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:126` (`delete`) |
| `GET` | `/properties/{propertyId}/rooms/{roomId}/images/{imageId}/file` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:256` (`file`) |
| `PUT` | `/properties/{propertyId}/rooms/{roomId}/images/{imageId}/tags` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImages.kt:177` (`updateTags`) |
## Room Types
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/room-types` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomTypes.kt:48` (`listRoomTypes`) |
| `POST` | `/properties/{propertyId}/room-types` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomTypes.kt:105` (`createRoomType`) |
| `GET` | `/properties/{propertyId}/room-types/{roomTypeCode}/images` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomTypeImages.kt:28` (`listByRoomType`) |
| `GET` | `/properties/{propertyId}/room-types/{roomTypeCode}/rate` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomTypes.kt:59` (`resolveRate`) |
| `DELETE` | `/properties/{propertyId}/room-types/{roomTypeId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomTypes.kt:187` (`deleteRoomType`) |
| `PUT` | `/properties/{propertyId}/room-types/{roomTypeId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomTypes.kt:152` (`updateRoomType`) |
## Room Stays & Cards
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/room-stays/active` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomStays.kt:41` (`listActiveRoomStays`) |
| `GET` | `/properties/{propertyId}/room-stays/cards/{cardIndex}` | `src/main/kotlin/com/android/trisolarisserver/controller/card/IssuedCards.kt:157` (`getCardByIndex`) |
| `POST` | `/properties/{propertyId}/room-stays/cards/{cardIndex}/revoke` | `src/main/kotlin/com/android/trisolarisserver/controller/card/IssuedCards.kt:136` (`revoke`) |
| `GET` | `/properties/{propertyId}/room-stays/{roomStayId}/cards` | `src/main/kotlin/com/android/trisolarisserver/controller/card/IssuedCards.kt:124` (`list`) |
| `POST` | `/properties/{propertyId}/room-stays/{roomStayId}/cards` | `src/main/kotlin/com/android/trisolarisserver/controller/card/IssuedCards.kt:80` (`issue`) |
| `POST` | `/properties/{propertyId}/room-stays/{roomStayId}/cards/prepare` | `src/main/kotlin/com/android/trisolarisserver/controller/card/IssuedCards.kt:47` (`prepare`) |
| `POST` | `/properties/{propertyId}/room-stays/{roomStayId}/void` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomStays.kt:77` (`voidRoomStay`) |
## Rate Plans
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/rate-plans` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:78` (`list`) |
| `POST` | `/properties/{propertyId}/rate-plans` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:49` (`create`) |
| `DELETE` | `/properties/{propertyId}/rate-plans/{ratePlanId}` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:111` (`delete`) |
| `PUT` | `/properties/{propertyId}/rate-plans/{ratePlanId}` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:94` (`update`) |
| `GET` | `/properties/{propertyId}/rate-plans/{ratePlanId}/calendar` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:169` (`listCalendar`) |
| `POST` | `/properties/{propertyId}/rate-plans/{ratePlanId}/calendar` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:126` (`upsertCalendar`) |
| `DELETE` | `/properties/{propertyId}/rate-plans/{ratePlanId}/calendar/{rateDate}` | `src/main/kotlin/com/android/trisolarisserver/controller/rate/RatePlans.kt:204` (`deleteCalendar`) |
## Cancellation Policy
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/cancellation-policy` | `src/main/kotlin/com/android/trisolarisserver/controller/property/CancellationPolicies.kt:33` (`get`) |
| `PUT` | `/properties/{propertyId}/cancellation-policy` | `src/main/kotlin/com/android/trisolarisserver/controller/property/CancellationPolicies.kt:52` (`upsert`) |
## Transport Modes
| Method | Path | Handler |
|---|---|---|
| `GET` | `/properties/{propertyId}/transport-modes` | `src/main/kotlin/com/android/trisolarisserver/controller/transport/TransportModes.kt:25` (`list`) |
## Inbound Email
| Method | Path | Handler |
|---|---|---|
| `POST` | `/properties/{propertyId}/inbound-emails/manual` | `src/main/kotlin/com/android/trisolarisserver/controller/email/InboundEmailManual.kt:39` (`uploadManualPdf`) |
| `GET` | `/properties/{propertyId}/inbound-emails/{emailId}/file` | `src/main/kotlin/com/android/trisolarisserver/controller/email/InboundEmails.kt:31` (`downloadEmailPdf`) |
## Assets & Metadata
| Method | Path | Handler |
|---|---|---|
| `GET` | `/amenities` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomAmenities.kt:39` (`listAmenities`) |
| `POST` | `/amenities` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomAmenities.kt:47` (`createAmenity`) |
| `DELETE` | `/amenities/{amenityId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomAmenities.kt:89` (`deleteAmenity`) |
| `PUT` | `/amenities/{amenityId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomAmenities.kt:67` (`updateAmenity`) |
| `GET` | `/icons/png` | `src/main/kotlin/com/android/trisolarisserver/controller/assets/IconFiles.kt:22` (`listPng`) |
| `GET` | `/icons/png/{filename}` | `src/main/kotlin/com/android/trisolarisserver/controller/assets/IconFiles.kt:38` (`getPng`) |
| `GET` | `/image-tags` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImageTags.kt:34` (`listTags`) |
| `POST` | `/image-tags` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImageTags.kt:41` (`createTag`) |
| `DELETE` | `/image-tags/{tagId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImageTags.kt:71` (`deleteTag`) |
| `PUT` | `/image-tags/{tagId}` | `src/main/kotlin/com/android/trisolarisserver/controller/room/RoomImageTags.kt:55` (`updateTag`) |