# Shared Shared infrastructure, models, templates, and configuration used by all four Rose Ash microservices (blog, market, cart, events). Included as a git submodule in each app. ## Structure ``` shared/ db/ base.py # SQLAlchemy declarative Base session.py # Async session factory (get_session) models/ # Shared domain models user.py # User magic_link.py # MagicLink (auth tokens) domain_event.py # DomainEvent (transactional outbox) kv.py # KeyValue (key-value store) menu_item.py # MenuItem ghost_membership_entities.py # GhostNewsletter, UserNewsletter infrastructure/ factory.py # create_base_app() — Quart app factory cart_identity.py # current_cart_identity() (user_id or session_id) cart_loader.py # Cart data loader for context processors context.py # Jinja2 context processors internal_api.py # Inter-app HTTP client (get/post via httpx) jinja_setup.py # Jinja2 template environment setup urls.py # URL helpers (coop_url, market_url, etc.) user_loader.py # Load current user from session http_utils.py # HTTP utility functions events/ bus.py # emit_event(), register_handler() processor.py # EventProcessor (polls domain_events, runs handlers) browser/app/ csrf.py # CSRF protection errors.py # Error handlers middleware.py # Request/response middleware redis_cacher.py # Tag-based Redis page caching authz.py # Authorization helpers filters/ # Jinja2 template filters (currency, truncate, etc.) utils/ # HTMX helpers, UTC time, parsing payments/sumup.py # SumUp checkout API integration browser/templates/ # ~300 Jinja2 templates shared across all apps config.py # YAML config loader containers.py # ContainerType, container_filter, content_filter helpers log_config/setup.py # Logging configuration (JSON formatter) utils.py # host_url and other shared utilities static/ # Shared static assets (CSS, JS, images, FontAwesome) editor/ # Koenig (Ghost) rich text editor build alembic/ # Database migrations (25 versions) env.py # Imports models from all apps (with try/except guards) versions/ # Migration files — single head: j0h8e4f6g7 ``` ## Key Patterns - **App factory:** All apps call `create_base_app()` which sets up DB sessions, CSRF, error handling, event processing, logging, and the glue handler registry. - **Event bus:** `emit_event()` writes to `domain_events` table in the caller's transaction. `EventProcessor` polls and dispatches to registered handlers. - **Inter-app HTTP:** `internal_api.get/post("cart", "/internal/cart/summary")` for cross-app reads. URLs resolved from `app-config.yaml`. - **Cart identity:** `current_cart_identity()` returns `{"user_id": int|None, "session_id": str|None}` from the request session. ## Alembic Migrations All apps share one PostgreSQL database. Migrations are managed here and run from the blog app's entrypoint (other apps skip migrations on startup). ```bash # From any app directory (shared/ must be on sys.path) alembic -c shared/alembic.ini upgrade head ``` Current head: `j0h8e4f6g7` (drop cross-domain FK constraints).