This repository has been archived on 2026-02-24 . You can view files and clone it. You cannot open issues or pull requests or push a commit.
a626dd849dd35ed4f8f69395d1754817256811bb
Mastodon ignored Delete activities because the Tombstone id was the post URL, not the object id from the original Create activity. Now looks up the existing Create activity and uses its object id. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 todomain_eventstable in the caller's transaction.EventProcessorpolls and dispatches to registered handlers. - Inter-app HTTP:
internal_api.get/post("cart", "/internal/cart/summary")for cross-app reads. URLs resolved fromapp-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).
# 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).
Description
Languages
HTML
55.7%
Python
31.7%
CSS
7.6%
JavaScript
4.9%