7.0 KiB
7.0 KiB
AlpineBits Python Server - AI Agent Instructions
Project Overview
This is an AlpineBits 2024-10 server that bridges booking requests from Wix landing pages to hotel partners. It's a dual-purpose system:
- FastAPI webhook receiver - accepts booking forms from wix.com landing pages via
/api/webhook/wix-form - AlpineBits OTA server - exposes hotel reservation data at
/api/alpinebits/server-2024-10using OpenTravel Alliance XML protocol
Data flows: Wix form → Database → AlpineBits XML → Hotel systems (pull or push)
Architecture Patterns
XML Generation with xsdata
- Never manually construct XML strings. Use xsdata-generated Pydantic dataclasses from
src/alpine_bits_python/generated/alpinebits.py - Parse XML:
XmlParser().from_string(xml_string, OtaPingRq) - Serialize XML:
XmlSerializer(config=SerializerConfig(...)).render(ota_object) - Factory pattern: Use classes in
alpine_bits_helpers.py(e.g.,CustomerFactory,GuestCountsFactory) to build complex OTA objects from DB models - Example:
create_res_retrieve_response()builds OTA_ResRetrieveRS from(Reservation, Customer)tuples - Regenerating XML classes: Run
xsdataonAlpineBits-HotelData-2024-10/files/schema-xsd/alpinebits.xsdto regenerategenerated/alpinebits.py(only if XSD spec changes)
Configuration System
- Config loaded from YAML with secret injection via
!secrettags (seeconfig_loader.py) - Default config location:
config/config.yaml+config/secrets.yaml - Override via
ALPINEBITS_CONFIG_DIRenvironment variable - Multi-hotel support: Each hotel in
alpine_bits_autharray gets own credentials and optionalpush_endpoint - Logging: Centralized logging configured via
loggersection (seelogging_config.pyandLOGGING.md)- Use
from logging_config import get_logger; _LOGGER = get_logger(__name__)in any module - Logs to console always; optionally to file if
logger.fileis set - Format includes timestamp:
%(asctime)s - %(name)s - %(levelname)s - %(message)s
- Use
Database Layer
- Async-only SQLAlchemy with
AsyncSession(seedb.py) - Three core tables:
Customer,Reservation,AckedRequest(tracks which clients acknowledged which reservations) - DB URL configurable: SQLite for dev (
sqlite+aiosqlite:///alpinebits.db), PostgreSQL for prod - Database auto-created on startup in
api.py:create_app()
Event-Driven Push System
EventDispatcherinapi.pyenables hotel-specific listeners:event_dispatcher.register_hotel_listener("reservation:created", hotel_code, push_listener)- Push listener sends OTA_HotelResNotif XML to hotel's configured
push_endpoint.urlwith Bearer token auth - Push requests logged to
logs/push_requests/with timestamp and unique ID - Note: Push endpoint support is currently dormant - configured but not actively used by partners
AlpineBits Action Pattern
- Each OTA action is a class inheriting
AlpineBitsActionHandler(seealpinebits_server.py) - Actions:
PingAction,ReadAction,NotifReportAction,PushAction - Request flow: Parse XML → Call
handle()→ ReturnAlpineBitsActionResultwith XML response + HTTP status AlpineBitsActionNameenum maps capability names to request names (e.g.,OTA_READ→"OTA_Read:GuestRequests")- Server supports multiple AlpineBits versions (2024-10, 2022-10) when actions are identical across versions
Acknowledgment System
AckedRequesttable tracks which clients acknowledged which reservations viaOTA_NotifReport:GuestRequests- Read requests filter out acknowledged reservations for clients with
client_id - Prevents duplicate reservation sends: once acknowledged, data won't appear in subsequent reads for that client
Critical Workflows
Running Locally
uv sync # Install dependencies (uses uv, not pip!)
uv run python -m alpine_bits_python.run_api # Start server on port 8080, clears DB on startup
Testing
uv run pytest # Run all tests
uv run pytest tests/test_alpine_bits_server_read.py # Specific test file
- Tests use in-memory SQLite via
test_db_enginefixture (seetests/test_alpine_bits_server_read.py) - Test data fixtures in
tests/test_data/directory
Building for Deployment
uv sync
docker build . -t gitea.linter-home.com/jonas/asa_api:master
- Multi-stage Dockerfile: builder stage installs deps with uv, production stage copies
.venv - Runs as non-root user (UID 1000) for security
- Requires
ALPINEBITS_CONFIG_DIR=/configvolume mount for config files - Deployment: Docker build pipeline exists and works; can also build manually on target system
Project-Specific Conventions
Naming Patterns
- OTA message types use full AlpineBits names:
OtaReadRq,OtaResRetrieveRs,OtaHotelResNotifRq - Factory classes suffix with
Factory:CustomerFactory,HotelReservationIdFactory - DB models in
db.py, validation schemas inschemas.py, OTA helpers inalpine_bits_helpers.py
Data Validation Flow
- API Layer → Pydantic schemas (
schemas.py) validate incoming data - DB Layer → SQLAlchemy models (
db.py) persist validated data - XML Layer → xsdata classes (
generated/alpinebits.py) + factories (alpine_bits_helpers.py) generate OTA XML
This separation prevents mixing concerns (validation ≠ persistence ≠ XML generation).
Unique ID Generation
- Reservation IDs: 35-char max, format
{hotel_code}_{uuid4}_{timestamp} - Generated via
generate_unique_id()inauth.py
Rate Limiting
- Uses
slowapiwith Redis backend - Three tiers:
DEFAULT_RATE_LIMIT(100/hour),WEBHOOK_RATE_LIMIT(300/hour),BURST_RATE_LIMIT(10/minute) - Applied via decorators:
@limiter.limit(DEFAULT_RATE_LIMIT)
Common Pitfalls
- Don't use synchronous SQLAlchemy calls - Always
await session.execute(), neversession.query() - Don't hardcode XML namespaces - Let xsdata handle them via generated classes
- Don't skip config validation - Voluptuous schemas in
config_loader.pycatch config errors early - Auth is per-hotel - HTTP Basic Auth credentials from
alpine_bits_authconfig array - AlpineBits version matters - Server implements 2024-10 spec (see
AlpineBits-HotelData-2024-10/directory)
Key Files Reference
api.py- FastAPI app, all endpoints, event dispatcheralpinebits_server.py- AlpineBits action handlers (Ping, Read, NotifReport)alpine_bits_helpers.py- Factory classes for building OTA XML from DB modelsconfig_loader.py- YAML config loading with secret injectiondb.py- SQLAlchemy async models (Customer, Reservation, AckedRequest)schemas.py- Pydantic validation schemasgenerated/alpinebits.py- xsdata-generated OTA XML classes (DO NOT EDIT - regenerate from XSD)
Testing Strategy
- Fixtures create isolated in-memory databases per test
- Use
test_config()fixture for test configuration - XML serialization/parsing tested via xsdata round-trips
- Push endpoint mocking via httpx in tests