feat: decouple market from shared_lib, add app-owned models

Phase 1-3 of decoupling:
- path_setup.py adds project root to sys.path
- Market-owned models in market/models/ (market, market_place)
- All imports updated: shared.infrastructure, shared.db, shared.browser, etc.
- MarketPlace uses container_type/container_id instead of post_id FK

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-11 12:46:32 +00:00
parent 41b4e0fe24
commit 478636f799
51 changed files with 604 additions and 93 deletions

40
app.py
View File

@@ -7,11 +7,10 @@ from quart import g, abort, render_template, make_response
from jinja2 import FileSystemLoader, ChoiceLoader
from sqlalchemy import select
from shared.factory import create_base_app
from shared.cart_loader import load_cart
from config import config
from shared.infrastructure.factory import create_base_app
from shared.config import config
from suma_browser.app.bp import register_market_bp
from bp import register_market_bp
async def market_context() -> dict:
@@ -21,8 +20,8 @@ async def market_context() -> dict:
- menu_items: fetched from coop internal API
- cart_count/cart_total: fetched from cart internal API
"""
from shared.context import base_context
from shared.internal_api import get as api_get, dictobj
from shared.infrastructure.context import base_context
from shared.infrastructure.internal_api import get as api_get, dictobj
ctx = await base_context()
@@ -44,9 +43,9 @@ async def market_context() -> dict:
def create_app() -> "Quart":
from models.market_place import MarketPlace
from models.ghost_content import Post
from blog.models.ghost_content import Post
app = create_base_app("market", context_fn=market_context, before_request_fns=[load_cart])
app = create_base_app("market", context_fn=market_context)
# App-specific templates override shared templates
app_templates = str(Path(__file__).resolve().parent / "templates")
@@ -111,12 +110,13 @@ def create_app() -> "Quart":
},
}
# Load market scoped to post
# Load market scoped to post (container pattern)
market = (
await g.s.execute(
select(MarketPlace).where(
MarketPlace.slug == market_slug,
MarketPlace.post_id == post.id,
MarketPlace.container_type == "page",
MarketPlace.container_id == post.id,
MarketPlace.deleted_at.is_(None),
)
)
@@ -135,16 +135,24 @@ def create_app() -> "Quart":
# --- Root route: market listing ---
@app.get("/")
async def markets_listing():
from sqlalchemy.orm import selectinload
markets = (
rows = (
await g.s.execute(
select(MarketPlace)
select(MarketPlace, Post)
.join(
Post,
(MarketPlace.container_type == "page")
& (MarketPlace.container_id == Post.id),
)
.where(MarketPlace.deleted_at.is_(None))
.options(selectinload(MarketPlace.post))
.order_by(MarketPlace.name)
)
).scalars().all()
).all()
# Attach the joined post to each market for template access
markets = []
for market, post in rows:
market.page = post
markets.append(market)
html = await render_template(
"_types/market/markets_listing.html",