# Events App Calendar and event booking service for the Rose Ash cooperative platform. Manages calendars, time slots, calendar entries (bookings), tickets, and ticket types. ## Architecture One of four Quart microservices sharing a single PostgreSQL database: | App | Port | Domain | |-----|------|--------| | blog (coop) | 8000 | Auth, blog, admin, menus, snippets | | market | 8001 | Product browsing, Suma scraping | | cart | 8002 | Shopping cart, checkout, orders | | **events** | 8003 | Calendars, bookings, tickets | ## Structure ``` app.py # Application factory (create_base_app + blueprints) path_setup.py # Adds project root + app dir to sys.path config/app-config.yaml # App URLs, feature flags events_api.py # Internal API (/internal/events/*) models/ # Events-domain models calendars.py # Calendar, CalendarEntry, CalendarSlot, # TicketType, Ticket, CalendarEntryPost bp/ # Blueprints calendars/ # Calendar listing calendar/ # Single calendar view and admin calendar_entries/ # Calendar entries listing calendar_entry/ # Single entry view and admin day/ # Day view and admin slots/ # Slot listing slot/ # Single slot management ticket_types/ # Ticket type listing ticket_type/ # Single ticket type management tickets/ # Ticket listing ticket_admin/ # Ticket administration markets/ # Page-scoped marketplace views payments/ # Payment-related views templates/ # Jinja2 templates entrypoint.sh # Docker entrypoint Dockerfile shared/ # Submodule → git.rose-ash.com/coop/shared.git glue/ # Submodule → git.rose-ash.com/coop/glue.git ``` ## Models All events-domain models live in `models/calendars.py`: | Model | Description | |-------|-------------| | **Calendar** | Container for entries, scoped to a page via `container_type + container_id` | | **CalendarEntry** | A bookable event/time slot. Has `state` (pending/ordered/provisional), `cost`, ownership (`user_id`/`session_id`), and `order_id` (plain integer, no FK) | | **CalendarSlot** | Recurring time bands (day-of-week + time range) within a calendar | | **TicketType** | Named ticket categories with price and count | | **Ticket** | Individual ticket with unique code, state, and `order_id` (plain integer, no FK) | | **CalendarEntryPost** | Junction linking entries to content via `content_type + content_id` | `order_id` on CalendarEntry and Ticket is a plain integer column — no FK constraint to the orders table. The cart app writes these values via glue services (`order_lifecycle.py`), not directly. ## Dependencies **Cross-app model imports:** - `blog.models.ghost_content.Post` — `app.py` context processor, calendar/market services for page hydration - `market.models.market_place.MarketPlace` — `app.py` context processor, marketplace views - `cart.models.page_config.PageConfig` — `bp/payments/routes.py` for per-page SumUp config **Glue services:** - `glue.services.relationships.attach_child / detach_child` — calendar and marketplace services manage page associations - `glue.services.navigation.get_navigation_tree` — context processor builds site nav **Internal APIs:** - Calls `GET /internal/cart/summary` — context processor for cart widget - Exposes `/internal/events/*` via `events_api.py` — serves calendar data to other apps ## Migrations This app does **not** run Alembic migrations on startup. Migrations are managed in the `shared/` submodule and run from the blog app's entrypoint. The events app's `entrypoint.sh` skips the migration step. ## Running ```bash export DATABASE_URL_ASYNC=postgresql+asyncpg://user:pass@localhost/coop export REDIS_URL=redis://localhost:6379/0 export SECRET_KEY=your-secret-key hypercorn app:app --bind 0.0.0.0:8003 ``` ## Docker ```bash docker build -t events . docker run -p 8003:8000 --env-file .env events ```