Commit Graph

34 Commits

Author SHA1 Message Date
giles
7882644731 Add widget registry for universal UI decoupling
Introduces a widget system where domains register UI fragments into
named slots (container_nav, container_card, account_page, account_link).
Host apps iterate widgets generically without naming any domain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:04:13 +00:00
giles
dfc324b1be Add tickets & bookings to account page
Add TicketDTO, user_tickets/user_bookings to CalendarService protocol
and SqlCalendarService implementation, plus nav links and panel
templates for the auth account sub-pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 16:06:21 +00:00
giles
98c3df860b Fix category selector highlighting to use slug comparison
Use top_slug/sub_slug directly instead of current_local_href for
active state detection. The previous approach compared full request
paths against short category-relative paths, which never matched.
This also avoids conflicting with current_local_href used by brand
filter URL construction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:28:51 +00:00
giles
d404349806 Add select_colours as Jinja global for consistent nav highlighting
select_colours was only defined via {% set %} in the root header
template, making it undefined in market/browse nav templates. Moving
it to a Jinja global ensures aria-selected styling works everywhere.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:17:04 +00:00
giles
3febef074b Fix menu item highlighting with aria-selected attribute
Added app_name Jinja global and aria-selected to nav menu links.
Matches by first path segment (e.g. /market/... → "market") or by
app_name for cross-domain cases (e.g. cart app → "cart" menu item).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:56:07 +00:00
giles
6db91cb3c1 Add delete button with confirm modal to cart_item, clamp minus at 0
Minus button now floors at 0 instead of going negative. A trash button
with SweetAlert2 confirmation appears when cart_delete_url is defined
(cart app only). Items at quantity 0 remain visible for re-increment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:43:12 +00:00
giles
7b55d78214 Fix cross-origin cart +/- buttons by supporting cart_quantity_url in template
The cart_item macro now checks for cart_quantity_url (defined only in the cart app)
and uses it for same-origin quantity updates, falling back to market_product_url.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:31:06 +00:00
giles
b3a0e9922a Add MarketService write methods and clean up stubs
Add create_marketplace() and soft_delete_marketplace() to MarketService
protocol, SQL implementation, and stubs — centralises market CRUD that
was previously duplicated in blog and events app-level service files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 05:43:55 +00:00
giles
9cba422aa9 Fix DTO compatibility: replace ORM relationship traversals with DTO fields
Templates were accessing entry.calendar.name/slug/post via ORM relationships,
but these entries are now CalendarEntryDTOs. Use flat fields instead
(calendar_name, calendar_slug, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 05:04:53 +00:00
giles
de4bc92fce Revert extend_existing workaround on MenuNode and ContainerRelation
The root cause (glue submodule) was fixed by removing it from app repos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 04:50:04 +00:00
giles
f1716a0fc0 Add extend_existing=True to MenuNode and ContainerRelation models
Prevents SQLAlchemy 'table already defined' error if the table gets
registered by a stale glue submodule or cached Docker layer before
the shared model is loaded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 04:48:07 +00:00
giles
5bcf68af2b Fix duplicate table error: remove glue.models from model import loop
MenuNode and ContainerRelation now live in shared/models/ — importing
glue.models caused SQLAlchemy to see duplicate table definitions.
Also register the two new models in shared/models/__init__.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 04:34:28 +00:00
giles
70b1c7de10 Domain isolation: typed contracts, service registry, and composable wiring
Add typed service contracts (Protocols + frozen DTOs) in shared/contracts/
for cross-domain communication. Each domain exposes a service interface
(BlogService, CalendarService, MarketService, CartService) backed by SQL
implementations in shared/services/. A singleton registry with has() guards
enables composable startup — apps register their own domain service and
stubs for absent domains.

Absorbs glue layer: navigation, relationships, event handlers (login,
container, order) now live in shared/ with has()-guarded service calls.
Factory gains domain_services_fn parameter for per-app service registration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 04:29:10 +00:00
giles
ea7dc9723a Fix ticket_types lazy-load in async: add lazy=selectin
CalendarEntry.ticket_types used default lazy loading which triggers
MissingGreenlet in async context when accessed in templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 22:02:03 +00:00
giles
e3f8ff6e3c Fix cart-mini home link: use coop_url instead of broken qs|host filter
The |qs filter returns "" when makeqs_factory is not set (events app),
causing |host to generate the events app root URL which has no route.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:49:28 +00:00
giles
0c0f3c8416 Decouple cross-app models: move canonical definitions to shared/models/
- Move 6 model files to shared/models/ (ghost_content, order, page_config,
  market, market_place, calendars) so apps import from shared, not each other
- Fix auth templates: replace url_for('auth.*') with coop_url() for
  cross-app compatibility
- Fix TYPE_CHECKING import in sumup.py to use shared.models.order
- Delete dead infrastructure/cart_loader.py (inverted dependency)
- Update models/__init__.py to export all new models

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 20:46:36 +00:00
giles
da10fc4cf9 Add data-hx-disable to orders link to prevent htmx interception
The orders link navigates cross-domain (cart subdomain from coop) and
htmx 2.0 selfRequestsOnly blocks cross-origin requests. Explicitly
disable htmx on this link so the browser does a normal navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 19:30:45 +00:00
giles
526d4f6e1b Use coop_url for auth links in shared templates
url_for('auth.account') and url_for('auth.newsletters') only work in
the blog app. Other apps (cart) that render these shared templates
don't have an auth blueprint. Use coop_url() so links always resolve
to the blog subdomain regardless of which app renders the template.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 19:18:28 +00:00
giles
97bd6162c5 Fix market nav link: point to coop.rose-ash.com/market/ not market subdomain
The market menu item in the top bar should link to the blog page at
coop_url('/market/'), not to market_url('/') which goes to the market
subdomain. Reverts the incorrect 'market' addition to _app_slugs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 18:48:24 +00:00
giles
d805af0764 Add page_config support to get_checkout for per-page SumUp credentials
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 18:37:55 +00:00
giles
3aa1aadd0b Add market_product_url helper for correct product URLs
market_url('/product/...') was missing the /<page_slug>/<market_slug>/
prefix required by the market app's route structure. New helper
market_product_url() resolves the prefix from request context
(g.post_slug/g.market_slug in market app, g.page_slug + market_place
in cart app).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 18:19:36 +00:00
giles
a858e33ca3 Add page_config support to SumUp create_checkout
Accept optional page_config parameter to use per-page
SumUp merchant code and API key instead of global config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 17:51:35 +00:00
giles
4d00ba3dbe Fix doubled URLs when |host filter receives absolute URLs
_join_url_parts() only checked the first segment for a scheme, so
passing an already-absolute URL (e.g. from cart_url()) through the
|host filter would join route_prefix() + absolute URL, producing
"https://host/https://host/path/".

Now detects schemes in later segments and resets the base.

Also add missing 'market' entry to _nav.html _app_slugs to match
_nav_oob.html — without it the market menu item fell through to
coop_url('/market/') instead of market_url('/').

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:45:35 +00:00
giles
d1621b8e70 Use cart_url/page_cart_url for checkout action instead of url_for
The checkout form action used url_for('cart_global.checkout') which
only resolves inside the cart app. Replace with cart_url() and
page_cart_url() Jinja globals that work across all apps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:22:22 +00:00
giles
5877a7702f Add README documenting shared infrastructure
Covers structure, key patterns, models, event bus, and alembic setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 19:28:44 +00:00
giles
346d3f4e05 Phase 5: Drop cross-domain FK constraints (events → cart)
Merge three alembic heads and drop:
- calendar_entries.order_id FK → orders.id
- tickets.order_id FK → orders.id

Columns kept as plain integers for glue-service bridging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 17:35:17 +00:00
giles
0c6eee18de Remove MenuItem.post relationship to fix mapper init error
The back_populates="menu_items" referenced a relationship removed from
Post in the glue layer commit. MenuItem model kept for table preservation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 01:58:18 +00:00
giles
2c4ab9e3c8 Add glue layer support: MenuNode templates, factory registration, migration
- Templates: item.post.X → item.X (MenuNode has label/slug/feature_image directly)
- factory.py: add glue.models to import loop + register_glue_handlers() at startup
- alembic env.py: add glue.models to import loop
- New migration: container_relations + menu_nodes tables with backfill from existing data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:37:35 +00:00
giles
e1e6a7a98b Import all app model packages at startup for SQLAlchemy mapper
Cross-domain relationships like Product.order_items → OrderItem use
string references that SQLAlchemy resolves by class name lookup. All
model packages must be imported so every class is registered before
mapper configuration runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 16:00:32 +00:00
giles
22e09cf66b Add merge migration to unify diverged alembic heads
Two branches diverged from e5c3f9a2b1d6 (tag_groups):
- domain_events → generic_containers (g7e5b1c3d4f8)
- tickets → page_configs → market_places → page_tracking (c3d4e5f6a7b8)

This merge migration joins them into a single head so
alembic upgrade head works without specifying a branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:26:43 +00:00
giles
ddc66fb1cf Add alembic.ini missing from decoupling branch
Was present on main but never carried over. Without it, alembic
upgrade head fails with 'No script_location key found'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:11:20 +00:00
giles
9bc9f64dce Rename shared/logging/ to shared/log_config/ to avoid stdlib shadow
shared/logging/ shadows Python's stdlib logging module, causing a
circular import when any code does `import logging`. This breaks
both the entrypoint Redis flush and Hypercorn app loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 13:55:20 +00:00
giles
4dd25526b9 Add requirements.txt and guard app model imports in env.py
requirements.txt copied from shared_lib for Docker build compatibility.
Alembic env.py now uses try/except for app-specific model imports so
upgrade head works in Docker where only one app's code is present.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 13:16:04 +00:00
giles
ef806f8fbb feat: extract shared infrastructure from shared_lib
Phase 1-3 of decoupling plan:
- Shared DB, models, infrastructure, browser, config, utils
- Event infrastructure (domain_events outbox, bus, processor)
- Structured logging
- Generic container concept (container_type/container_id)
- Alembic migrations for all schema changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:45:56 +00:00