Files
wyndham-Condon/backend/README.md
2026-08-03 16:43:57 +08:00

6.8 KiB

CONDO Backend

TypeScript/Fastify API and PostgreSQL database layer for the current CONDO owner-account frontend.

Current state

  • Database: existing booking_test.
  • Isolated schema: condon.
  • Migrations: 001_create_condon_schema, 002_legacy_import_and_bookings, 003_delete_usage_record.
  • Reference data: 11 room types.
  • Imported latest (2) batch: 388 owners, 389 periods, 155 bookings, 157 usage records and 547 ledger rows.
  • Historical data import: legacy-016dc36d15cc40a5 completed after local preflight and read-only verification.
  • Existing booking, finance, ingestion and public objects were not changed.
  • Operator access uses an expiring opaque server session and an HttpOnly cookie; credentials are verified only in the backend.

Database objects

Object Purpose
condon.room_types Room codes, automatic tiers and AC2 manual-rule marker
condon.owner_accounts One independent account per owner room
condon.entitlement_periods Annual grant, carry-forward and the single authoritative balance
condon.bookings Unique Confirmation booking header; usage is 1:N
condon.usage_records Confirmation, stay dates, Night, multiplier, Use and post-use Balance
condon.entitlement_ledger Annual grant, carry-forward and usage balance movements
condon.schema_migrations Migrations belonging only to condon

The database functions are:

  • condon.calculate_multiplier
  • condon.open_entitlement_period
  • condon.create_usage_record
  • condon.create_usage_record_v2
  • condon.delete_usage_record

create_usage_record_v2 is the authoritative new-record write path. It calculates Night, Multiplier, Use and Balance, locks the entitlement period and writes the usage row, ledger row and new balance atomically. Historical rows use legacy-source, preserve source Use/Balance/Room/raw room type, and may have a null multiplier.

API

Method Path Purpose
POST /auth/login Verify operator credentials and create a 12-hour session
GET /auth/session Check the current browser session without exposing the cookie
POST /auth/logout Revoke the current session and expire its cookie
GET /health Database/schema/migration health
GET /room-types Room-type rule metadata
GET /owner-accounts Searchable, paginated account list
GET /owner-accounts/:id Account detail and period balance
GET /usage-records Searchable, paginated usage history
POST /usage-records Transactional usage deduction
DELETE /usage-records/:id Transactional usage deletion and balance restoration
GET /dashboard Annual totals and room-type/month aggregates

Runtime OpenAPI documentation is available at /docs.

Only the three /auth/* routes and CORS preflight are public. Health, OpenAPI documentation and every business route require the condon_session cookie. Session tokens are cryptographically random, stored only as SHA-256 keys in backend memory, and expire after the configured TTL or logout.

Example POST body:

{
  "ownerAccountId": "00000000-0000-4000-8000-000000000001",
  "confirmationNo": "26090001",
  "checkIn": "2026-09-01",
  "checkOut": "2026-09-04",
  "usedRoomType": "SU1",
  "manualMultiplier": null,
  "remark": "",
  "idempotencyKey": "00000000-0000-4000-8000-000000000002"
}

The request does not accept Night, Use, Balance or an automatic multiplier. PostgreSQL derives them from the account, dates and room rules.

Configuration

Use runtime environment variables or a deployment secret manager. Do not commit live credentials.

Required variables:

  • DB_HOST
  • DB_PORT
  • DB_USER
  • DB_PASSWORD
  • DB_NAME=booking_test

Optional variables and safe placeholders are documented in .env.example. The application refuses to start if DB_NAME is anything other than booking_test.

Authentication defaults for this deployment are wyndhamcondon / wyndhamcondon. Override AUTH_USERNAME, AUTH_PASSWORD, AUTH_SESSION_TTL_HOURS and AUTH_COOKIE_SECURE through runtime secrets for another environment. Secure cookies default on automatically when NODE_ENV=production.

Local commands

npm install
npm run typecheck
npm test
npm run build
npm run preview:history:check
npm run preview:history
npm run dev

The API listens on 127.0.0.1:3000 by default. The default CORS allowlist accepts the existing frontend at 127.0.0.1:4173 and localhost:4173.

preview:history:check validates the retained import source hash and the fixed 388 owner / 157 usage / 438 used / 5,394 remaining totals without opening a port. preview:history serves that exact snapshot through the normal Fastify authentication and API routes without connecting to PostgreSQL. It is intended for safe local preview when remote database secrets are not present; any new preview records and balance changes are memory-only and reset when the process stops.

Database operator commands:

npm run db:check-migrations
npm run db:inventory
npm run db:verify
npm run db:test-integration
npm run db:verify-import

db:test-integration is an empty-database migration test; it must not be run against the imported production data.

The database commands read connection material from one non-echoed standard-input line. They do not read .env files or print credentials.

Verification

  • Migration safety checks: 16/16.
  • API/auth/config/error tests: 12/12.
  • Live imported-database API smoke checks: 6/6.
  • Live transactional API write checks: 8/8.
  • Imported-batch read-only verification: 6/6.
  • Post-test deployment checks: 11/11.
  • npm vulnerability audit: 0.

The database integration test covers all 100 automatic room-type combinations, both AC2 manual paths, annual grant/carry-forward, derived Night/Use/Balance, idempotency, duplicate confirmation, cross-year rejection, insufficient balance and concurrent overspend protection. Synthetic records are removed and the final four business tables must be empty.

Rollback

The latest migration rollback is 003_delete_usage_record.down.sql. Do not run it after business data has been imported. The previous legacy rollback remains 002_legacy_import_and_bookings.down.sql, and the original empty-schema rollback remains 001_create_condon_schema.down.sql.

Do not run rollback after business data has been imported. Rollback is an explicit operator action and is not exposed as a normal npm command.

Deliberately deferred

  • Importing a newer workbook without a new preflight batch.
  • Switching the static frontend to the API.
  • Multi-user identities, roles and backend-restart-persistent sessions.
  • Manual balance adjustment.
  • Cross-entitlement-year stays.