From 4f9f482c6c2c5092fc7e3d486253d6d1512ae664 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 14 Feb 2026 19:29:03 +0000 Subject: [PATCH] Rewrite README for post-decoupling architecture Remove stale /adopt endpoint reference, document submodules, all services, glue integration, checkout flow, and domain events. Co-Authored-By: Claude Opus 4.6 --- README.md | 105 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 75dd08e..95c9cc3 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,84 @@ # Cart App -Shopping cart, checkout, and order management service for the Rose Ash cooperative marketplace. - -## Overview - -This is the **cart** microservice, split from the Rose Ash monolith. It handles: - -- **Shopping cart** - Add/remove products, view cart, cart summary API -- **Checkout** - SumUp payment integration with hosted checkout -- **Orders** - Order listing, detail view, payment status tracking -- **Calendar bookings** - Calendar entry cart items and checkout integration +Shopping cart, checkout, and order management service for the Rose Ash cooperative. ## Architecture -- **Framework:** Quart (async Flask) -- **Database:** PostgreSQL 16 via SQLAlchemy 2.0 (async) -- **Payments:** SumUp Hosted Checkout -- **Frontend:** HTMX + Jinja2 templates + Tailwind CSS +One of four Quart microservices sharing a single PostgreSQL database: -## Directory Structure +| 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 # Quart application factory +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, SumUp config +models/ # Cart-domain models + order.py # Order, OrderItem + page_config.py # PageConfig (per-page SumUp credentials) bp/ - cart/ # Cart blueprint (add, view, checkout, webhooks) - routes.py - api.py # Internal API (server-to-server, CSRF-exempt) - login_helper.py # Cart merge on login - services/ # Business logic layer - order/ # Single order detail blueprint - routes.py - filters/qs.py # Query string helpers - orders/ # Order listing blueprint - routes.py - filters/qs.py -templates/ - _types/cart/ # Cart templates - _types/order/ # Single order templates - _types/orders/ # Order listing templates -entrypoint.sh # Docker entrypoint (migrations + server start) -Dockerfile # Container build -.gitea/workflows/ci.yml # CI/CD pipeline + cart/ # Cart blueprint + global_routes.py # Add to cart, checkout, webhooks, return page + page_routes.py # Page-scoped cart and checkout + overview_routes.py # Cart overview / summary page + api.py # Internal API (/internal/cart/summary) + services/ # Business logic + checkout.py # Order creation, SumUp integration + check_sumup_status.py # Payment status polling + calendar_cart.py # Calendar entry cart queries + page_cart.py # Page-scoped cart queries + get_cart.py # Cart item queries + identity.py # Cart identity (user_id / session_id) + total.py # Price calculations + clear_cart_for_order.py # Soft-delete cart after checkout + order/ # Single order detail view + orders/ # Order listing view +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 +``` + +## Cross-App Integration + +- **Internal API:** `GET /internal/cart/summary` returns cart count + total for the current session/user. Called by blog and market context processors. +- **Calendar entries:** Checkout marks CalendarEntries (events domain) as "ordered" via `glue/services/order_lifecycle.py` — not by direct model write. +- **Payment confirmation:** When SumUp payment confirms, entries are marked "provisional" via the same glue service. +- **Domain events:** Emits `order.created` and `order.paid` events for observability. +- **Login adoption:** Anonymous cart/entries are adopted when `user.logged_in` event fires (handled by `glue/handlers/login_handlers.py`). + +## Checkout Flow + +``` +1. User clicks "Checkout" +2. create_order_from_cart() creates Order + OrderItems +3. glue: claim_entries_for_order() marks CalendarEntries as "ordered" +4. emit: order.created event +5. SumUp hosted checkout created, user redirected +6. SumUp webhook / return page triggers check_sumup_status() +7. If PAID: glue: confirm_entries_for_order(), emit: order.paid ``` ## Running ```bash -# Set environment variables -export APP_MODULE=app:app export DATABASE_URL_ASYNC=postgresql+asyncpg://user:pass@localhost/coop export REDIS_URL=redis://localhost:6379/0 export SECRET_KEY=your-secret-key -# Run the server hypercorn app:app --reload --bind 0.0.0.0:8002 ``` -## Cross-App Communication - -The cart app exposes internal API endpoints at `/internal/cart/` for other services: - -- `GET /internal/cart/summary` - Cart count and total for the current session/user -- `POST /internal/cart/adopt` - Adopt anonymous cart items after user login - ## Docker ```bash -docker build -t cart:latest . -docker run -p 8002:8000 --env-file .env cart:latest +docker build -t cart . +docker run -p 8002:8000 --env-file .env cart ```