# 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).
