Market CRUD in blog now delegates to services.market.create_marketplace()
and soft_delete_marketplace() instead of importing MarketPlace directly.
Adds TODO comments on Calendar imports in admin routes (deferred to
admin UI rework). Updates shared submodule.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The glue layer's models (MenuNode, ContainerRelation), services
(navigation, relationships), and event handlers have been absorbed
into shared/. The glue submodule caused duplicate SQLAlchemy table
registration for 'menu_nodes'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace direct Calendar, MarketPlace, and Post model queries with typed
service calls (services.blog, services.calendar, services.market,
services.cart). Blog registers all 4 services via domain_services_fn
with has() guards for composable deployment.
Key changes:
- app.py: use domain_services_fn instead of inline service registration
- admin routes: MarketPlace queries → services.market.marketplaces_for_container()
- entry_associations: CalendarEntryPost → services.calendar.entry_ids_for_content()
- markets service: Post query → services.blog.get_post_by_id/slug()
- posts_data, post routes: use calendar/market/cart services
- menu_items: glue imports → shared imports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Context processor now sums product count + calendar_count from the
cart API, so the cart badge shows the correct total on all pages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace all imports from cart.models, market.models, events.models
with shared.models equivalents
- Convert blog/models/ghost_content.py to re-export stub
- Update shared + glue submodule pointers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These were duplicates of files in shared/browser/templates/ and
silently prevented shared updates from taking effect (as happened
with the auth nav orders link fix). 8 blog-specific overrides with
genuine differences are kept.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The orders link was using links.link macro which adds hx-get, causing
htmx:invalidPath because cart.rose-ash.com is cross-origin. Use a
plain <a> tag for this cross-domain link instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract inline email body into separate Jinja2 templates
(_email/magic_link.html and .txt) with a styled sign-in
button and fallback plain-text link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
List specific model imports, glue services, internal APIs, and
domain events that blog code actually references.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document submodules, models, cross-app integration (event-driven
login adoption), and accurate directory structure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
shared: migration to drop cross-domain FK constraints
glue: order lifecycle services, cart adoption, login/order handlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Emit user.logged_in event instead of HTTP POST to /internal/cart/adopt.
Event is emitted inside the last_login_at transaction for atomicity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up ContainerRelation tracking via attach_child/detach_child in:
- menu_items: create, update (re-link on post change), delete
- markets: create (including revive), soft_delete
- page config: creation in update_features and update_sumup routes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous runs left self-copies (e.g. blog/blog/) that caused
'Table already defined' errors. Split into two loops: first rm -rf
all sibling dirs, then copy only non-self siblings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each app has its own models/ at the root (imported as bare `models.X`).
The CI copy was also creating {app}/models/ (imported as `{app}.models.X`),
causing SQLAlchemy to see the same table defined twice.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The cp approach failed when sibling repos were mid-update from
their own CI runs. git archive reads directly from git objects,
and git fetch ensures origin/decoupling is available even if the
sibling working tree is on a different branch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phases 1-3 split models by domain ownership, but cross-app imports
still exist (e.g. cart imports market.models.CartItem). In Docker
each app only has its own code. The CI step now copies sibling app
model packages into the build context before docker build.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update shared submodule (adds alembic.ini for migrations).
Use subshell for alembic so CWD is never affected by cd shared,
preventing cascading config path errors if migration fails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hypercorn spawns worker processes via multiprocessing spawn, which
starts a fresh Python interpreter without the parent's sys.path
modifications from path_setup.py. Setting PYTHONPATH=/app ensures
the worker can import app.py and all project packages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Swap shared_lib submodule → shared (tracking decoupling branch)
- Dockerfile: shared_lib/ → shared/, remove bp symlink hack
- entrypoint.sh: cd shared for alembic upgrade head
- CI: trigger on decoupling branch, use dynamic ref_name
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 1-3 of decoupling:
- path_setup.py adds project root to sys.path
- Blog-owned models in blog/models/ (ghost_content, snippet, tag_group)
- Re-export shims for shared models (user, kv, magic_link, menu_item)
- All imports updated: shared.infrastructure, shared.db, shared.browser, etc.
- No more cross-app post_id FKs in calendar/market/page_config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cross-app nav buttons for markets and payments (events app)
- Remove page features panel and markets panel from blog admin
(calendars, markets, and payments are now managed in the events app)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When toggling market/calendar features or saving SumUp settings,
create a PageConfig row if one doesn't exist yet instead of returning
a 404 error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The editor.js/editor.css were gitignored and never built during docker
build, causing 404s on the edit page. Add a Node multi-stage build step
to compile them. Also replace "nowt" placeholder in admin templates with
the actual main panel include.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetches page-scoped cart count from /internal/cart/summary?page_slug=
for page posts and displays a cart icon with count in the post header
that links to the page cart.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace SumUp placeholder with real form for merchant code, API key, prefix
- Add PUT /admin/sumup/ route to save per-page SumUp credentials
- Pass sumup_configured/merchant_code/checkout_prefix to template context
- SumUp form only shown when calendar or market feature is enabled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>