diff --git a/account/README.md b/account/README.md new file mode 100644 index 0000000..1dca8a7 --- /dev/null +++ b/account/README.md @@ -0,0 +1,36 @@ +# Account App + +User dashboard for the Rose Ash cooperative. Provides account management, newsletter preferences, and widget pages for tickets and bookings. + +## Structure + +``` +app.py # Application factory (create_base_app + blueprints) +path_setup.py # Adds project root + app dir to sys.path +entrypoint.sh # Container entrypoint (Redis flush, start) +bp/ + account/ # Dashboard, newsletters, widget pages (tickets, bookings) + auth/ # OAuth client routes + HTTP token exchange for non-coop clients + fragments/ # auth-menu fragment (sign-in button / user menu) +models/ # Re-export stubs pointing to shared/models/ +services/ # register_domain_services() — wires all domains +templates/ # Account-specific templates (override shared/) +``` + +## Auth menu + +Account serves the `auth-menu` fragment consumed by all other apps' headers. It renders either a sign-in button (anonymous) or the user's email with a dropdown (authenticated), for both desktop and mobile layouts. + +## OAuth token exchange + +`POST /auth/oauth/token` provides HTTP-based token exchange for non-coop OAuth clients (e.g., Artdag). + +## Cross-domain communication + +- `services.blog.*` — post queries for page context +- `services.calendar.*` — calendar/entry queries for bookings panel +- `services.cart.*` — cart summary + orders for tickets panel + +## Fragments served + +- **auth-menu** — sign-in button or user email menu (desktop + mobile) diff --git a/blog/README.md b/blog/README.md index ef45943..b9ccd6a 100644 --- a/blog/README.md +++ b/blog/README.md @@ -1,39 +1,26 @@ # Blog App (Coop) -Blog, authentication, and content management service for the Rose Ash cooperative platform. Handles Ghost CMS integration, user auth, and admin settings. - -## Architecture - -One of five 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 | -| federation | 8004 | ActivityPub, fediverse social | +Content management, Ghost CMS sync, navigation, and the prose editor for the Rose Ash cooperative platform. Runs database migrations on startup and serves as the primary content hub. ## 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, SumUp config -models/ # Blog-domain models (+ re-export stubs for shared models) -bp/ # Blueprints - auth/ # Magic link login, account, newsletters - blog/ # Post listing, Ghost CMS sync +entrypoint.sh # Container entrypoint (migrations, Redis flush, start) +bp/ + blog/ # Post listing, Ghost CMS sync, webhooks post/ # Single post view and admin admin/ # Settings admin interface menu_items/ # Navigation menu management snippets/ # Reusable content snippets -templates/ # Jinja2 templates + fragments/ # nav-tree fragment for cross-app navigation +models/ # Re-export stubs pointing to shared/models/ services/ # register_domain_services() — wires blog + calendar + market + cart -shared/ # Submodule -> git.rose-ash.com/coop/shared.git +templates/ # Blog-specific templates (override shared/) ``` -## Cross-Domain Communication +## Cross-domain communication All inter-app communication uses typed service contracts (no HTTP APIs): @@ -41,20 +28,14 @@ All inter-app communication uses typed service contracts (no HTTP APIs): - `services.market.*` — marketplace queries via MarketService protocol - `services.cart.*` — cart summary via CartService protocol - `services.federation.*` — AP publishing via FederationService protocol -- `shared.services.navigation` — site navigation tree -## Domain Events +## Fragments served -- `auth/routes.py` emits `user.logged_in` via `shared.events.emit_event` -- Ghost sync emits `post.published` / `post.updated` for federation +- **nav-tree** — site navigation tree, fetched by all other apps -## Running +## Fragments consumed -```bash -export DATABASE_URL_ASYNC=postgresql+asyncpg://user:pass@localhost/coop -export REDIS_URL=redis://localhost:6379/0 -export SECRET_KEY=your-secret-key - -alembic -c shared/alembic.ini upgrade head -hypercorn app:app --bind 0.0.0.0:8000 -``` +- **cart-mini** (from cart) — cart icon + badge +- **auth-menu** (from account) — sign-in / user menu +- **container-nav** (from events, market) — sidebar widgets +- **container-cards** (from events) — event cards on listing pages diff --git a/cart/README.md b/cart/README.md index 22374d1..45823ec 100644 --- a/cart/README.md +++ b/cart/README.md @@ -1,26 +1,13 @@ # Cart App -Shopping cart, checkout, and order management service for the Rose Ash cooperative. - -## Architecture - -One of five 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 | -| federation | 8004 | ActivityPub, fediverse social | +Shopping cart, checkout, and order management service for the Rose Ash cooperative. Integrates with SumUp for payment processing. ## 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, SumUp config -models/ # Cart-domain models (Order, OrderItem, PageConfig) +entrypoint.sh # Container entrypoint (Redis flush, start) bp/ cart/ # Cart blueprint global_routes.py # Add to cart, checkout, webhooks, return page @@ -37,40 +24,33 @@ bp/ clear_cart_for_order.py # Soft-delete cart after checkout order/ # Single order detail view orders/ # Order listing view + fragments/ # cart-mini fragment, account-nav-item fragment +models/ # Re-export stubs (Order, OrderItem, PageConfig) services/ # register_domain_services() — wires cart + calendar + market -shared/ # Submodule -> git.rose-ash.com/coop/shared.git +templates/ # Cart-specific templates (override shared/) ``` -## Cross-Domain Communication +## Cart identity + +Cart items are keyed by `user_id` (logged in) or `session_id` (anonymous). On login, anonymous cart items are adopted to the user's account. + +## Cross-domain communication - `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 -## Domain Events +## Fragments served -- `checkout.py` emits `order.created` via `shared.events.emit_event` -- `check_sumup_status.py` emits `order.paid` via `shared.events.emit_event` +- **cart-mini** — cart icon + badge count +- **account-nav-item** — orders link for account nav -## Checkout Flow +## Checkout flow -``` 1. User clicks "Checkout" -2. create_order_from_cart() creates Order + OrderItems -3. services.calendar.claim_entries_for_order() marks entries as "ordered" -4. emit: order.created event +2. `create_order_from_cart()` creates Order + OrderItems +3. `services.calendar.claim_entries_for_order()` marks entries as "ordered" +4. Emits `Create` / `rose:Order` activity 5. SumUp hosted checkout created, user redirected -6. SumUp webhook / return page triggers check_sumup_status() -7. If PAID: services.calendar.confirm_entries_for_order(), emit: order.paid -``` - -## 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:8002 -``` +6. SumUp webhook / return page triggers `check_sumup_status()` +7. If PAID: `services.calendar.confirm_entries_for_order()`, emits `rose:OrderPaid` diff --git a/events/README.md b/events/README.md index 5327685..52ec0c7 100644 --- a/events/README.md +++ b/events/README.md @@ -2,28 +2,13 @@ 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 five 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 | -| federation | 8004 | ActivityPub, fediverse social | - ## 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 -models/ # Events-domain models - calendars.py # Calendar, CalendarEntry, CalendarSlot, - # TicketType, Ticket, CalendarEntryPost -bp/ # Blueprints +entrypoint.sh # Container entrypoint (Redis flush, start) +bp/ calendars/ # Calendar listing calendar/ # Single calendar view and admin calendar_entries/ # Calendar entries listing @@ -37,18 +22,20 @@ bp/ # Blueprints ticket_admin/ # Ticket administration markets/ # Page-scoped marketplace views payments/ # Payment-related views + fragments/ # container-nav, container-cards fragments +models/ # Re-export stubs (Calendar, CalendarEntry, Ticket, etc.) services/ # register_domain_services() — wires calendar + market + cart -shared/ # Submodule -> git.rose-ash.com/coop/shared.git +templates/ # Events-specific templates (override shared/) ``` ## Models -All events-domain models live in `models/calendars.py`: +All events-domain models live in `shared/models/`: | 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) | +| **CalendarEntry** | A bookable event/time slot with state (pending/ordered/provisional) and cost | | **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) | @@ -56,23 +43,13 @@ All events-domain models live in `models/calendars.py`: `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 service calls, not directly. -## Cross-Domain Communication +## Cross-domain communication - `services.market.*` — marketplace queries for page views - `services.cart.*` — cart summary for context processor - `services.federation.*` — AP publishing for new entries -- `shared.services.navigation` — site navigation tree -## Migrations +## Fragments served -This app does **not** run Alembic migrations on startup. Migrations are managed in the `shared/` submodule and run from the blog app's entrypoint. - -## 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 -``` +- **container-nav** — calendar entries + links for blog sidebar +- **container-cards** — event cards for blog listing pages diff --git a/federation/README.md b/federation/README.md new file mode 100644 index 0000000..a89207d --- /dev/null +++ b/federation/README.md @@ -0,0 +1,44 @@ +# Federation App + +OAuth2 authorization server and ActivityPub social hub for the Rose Ash cooperative. Handles user authentication, fediverse federation, and social features (timeline, compose, follow, notifications). + +## Structure + +``` +app.py # Application factory (create_base_app + blueprints) +path_setup.py # Adds project root + app dir to sys.path +entrypoint.sh # Container entrypoint (optional migrations, Redis flush, start) +bp/ + auth/ # Login, magic link, logout, OAuth2 authorize endpoint + identity/ # Actor profile management + social/ # Timeline, compose, search, follow/unfollow, + # like/boost, notifications, following/followers lists + fragments/ # Fragment endpoints +models/ # Re-export stubs pointing to shared/models/ +services/ # register_domain_services() — wires all domains +templates/ # Federation-specific templates (override shared/) +``` + +## OAuth2 SSO + +Federation is the authorization server for all Rose Ash apps: + +- `/oauth/authorize` — authorization endpoint (PKCE supported) +- Magic link login (passwordless email) +- All client apps auto-get `/auth/login`, `/auth/callback`, `/auth/logout` via `shared/infrastructure/oauth.py` +- Per-app first-party session cookies (Safari ITP compatible) + +## ActivityPub + +- Per-app actors: each app has its own AP actor (virtual projection of the same keypair) +- Actor endpoints: webfinger, actor profile, inbox, outbox, followers +- Social features: timeline, compose, search, follow/unfollow, like/boost, notifications +- Activities emitted to `ap_activities` table, processed by `EventProcessor` +- HTTP signatures + IPFS content addressing + +## Cross-domain communication + +- `services.blog.*` — post queries for content federation +- `services.calendar.*` — event queries +- `services.market.*` — product queries +- `services.cart.*` — cart summary for context processor diff --git a/market/README.md b/market/README.md index 6d9a840..7ac142c 100644 --- a/market/README.md +++ b/market/README.md @@ -2,41 +2,33 @@ Product browsing and marketplace service for the Rose Ash cooperative. Displays products scraped from Suma Wholesale. -## Architecture - -One of five 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 | -| federation | 8004 | ActivityPub, fediverse social | - ## 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 -models/ # Market-domain models (+ re-export stubs) -bp/ # Blueprints +entrypoint.sh # Container entrypoint (Redis flush, start) +bp/ market/ # Market root, navigation, category listing browse/ # Product browsing with filters and infinite scroll product/ # Product detail pages cart/ # Page-scoped cart views api/ # Product sync API (used by scraper) + fragments/ # container-nav fragment (market links) scrape/ # Suma Wholesale scraper +models/ # Re-export stubs pointing to shared/models/ services/ # register_domain_services() — wires market + cart -shared/ # Submodule -> git.rose-ash.com/coop/shared.git +templates/ # Market-specific templates (override shared/) ``` -## Cross-Domain Communication +## Cross-domain communication - `services.cart.*` — cart summary via CartService protocol - `services.federation.*` — AP publishing via FederationService protocol -- `shared.services.navigation` — site navigation tree + +## Fragments served + +- **container-nav** — market navigation links for blog sidebar ## Scraping @@ -44,13 +36,3 @@ shared/ # Submodule -> git.rose-ash.com/coop/shared.git bash scrape.sh # Full Suma Wholesale catalogue bash scrape-test.sh # Limited test scrape ``` - -## 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:8001 -```