diff --git a/README.md b/README.md index 7dfabed..22374d1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Shopping cart, checkout, and order management service for the Rose Ash cooperati ## Architecture -One of four Quart microservices sharing a single PostgreSQL database: +One of five Quart microservices sharing a single PostgreSQL database: | App | Port | Domain | |-----|------|--------| @@ -12,6 +12,7 @@ One of four Quart microservices sharing a single PostgreSQL database: | market | 8001 | Product browsing, Suma scraping | | **cart** | 8002 | Shopping cart, checkout, orders | | events | 8003 | Calendars, bookings, tickets | +| federation | 8004 | ActivityPub, fediverse social | ## Structure @@ -19,15 +20,12 @@ One of four Quart microservices sharing a single PostgreSQL database: 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) +models/ # Cart-domain models (Order, OrderItem, PageConfig) bp/ 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 @@ -39,31 +37,19 @@ bp/ 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 +services/ # register_domain_services() — wires cart + calendar + market +shared/ # Submodule -> git.rose-ash.com/coop/shared.git ``` -## Dependencies +## Cross-Domain Communication -**Cross-app model imports:** -- `market.models.market.Product, CartItem` — cart services, checkout, API -- `market.models.market_place.MarketPlace` — checkout page-config resolution, API page filtering -- `events.models.calendars.CalendarEntry, Calendar` — checkout, API summary, calendar cart services -- `blog.models.ghost_content.Post` — `app.py` context processor, API page-slug lookup +- `services.calendar.*` — claim/confirm entries for orders, adopt on login +- `services.market.*` — marketplace queries for page-scoped carts +- `services.blog.*` — post lookup for page context +- `shared.services.navigation` — site navigation tree -**Glue services:** -- `glue.services.order_lifecycle.claim_entries_for_order` — checkout marks entries as "ordered" -- `glue.services.order_lifecycle.confirm_entries_for_order` — payment confirmation marks entries "provisional" -- `glue.services.order_lifecycle.get_entries_for_order` — checkout return page loads entries -- `glue.services.navigation.get_navigation_tree` — context processor builds site nav +## Domain Events -**Internal APIs:** -- Exposes `GET /internal/cart/summary` — cart count + total for current session/user - -**Domain events:** - `checkout.py` emits `order.created` via `shared.events.emit_event` - `check_sumup_status.py` emits `order.paid` via `shared.events.emit_event` @@ -72,11 +58,11 @@ glue/ # Submodule → git.rose-ash.com/coop/glue.git ``` 1. User clicks "Checkout" 2. create_order_from_cart() creates Order + OrderItems -3. glue: claim_entries_for_order() marks CalendarEntries as "ordered" +3. services.calendar.claim_entries_for_order() marks entries 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 +7. If PAID: services.calendar.confirm_entries_for_order(), emit: order.paid ``` ## Running @@ -86,12 +72,5 @@ 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 --reload --bind 0.0.0.0:8002 -``` - -## Docker - -```bash -docker build -t cart . -docker run -p 8002:8000 --env-file .env cart +hypercorn app:app --bind 0.0.0.0:8002 ``` diff --git a/app.py b/app.py index e3e1122..b07534a 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,5 @@ from __future__ import annotations -import path_setup # noqa: F401 # adds shared_lib to sys.path +import path_setup # noqa: F401 # adds shared/ to sys.path from decimal import Decimal from pathlib import Path @@ -44,7 +44,7 @@ async def cart_context() -> dict: - cart / calendar_cart_entries / total / calendar_total: direct DB (cart app owns this data) - cart_count: derived from cart + calendar entries (for _mini.html) - - menu_items: direct DB query via glue layer + - menu_items: via shared.services.navigation When g.page_post exists, cart and calendar_cart_entries are page-scoped. Global cart_count / cart_total stay global for cart-mini. diff --git a/shared b/shared index bccfff0..d697709 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit bccfff0c699fdf9e3ee7c911af1f17a5294943f6 +Subproject commit d697709f60a71941880f4288be469913d11ce967