Commerce (Shop)
A real storefront — products and services, a client-side cart, and three real checkout paths, via the real Adhara Commerce SDK.
/shop is new in this port — not in the Python original. A real storefront: products and
services, a client-side cart (localStorage — no server session needed for anonymous
shoppers), and checkout — local JSON by default, real Adhara Commerce when configured.
A real SDK layer, not raw HTTP
Unlike blog/events/scheduling/links, the shop goes through the real Adhara SDK’s commerce
resource (src/lib/adharaCommerce.ts), not fetch() against raw endpoints — checkout is
genuinely complex (payment sessions, line-item pricing), and the SDK already has that logic.
See The Adhara SDK for the two real gaps found and fixed there while building
this feature.
Backend
- Local (default) — one JSON file per catalog item under
data/content/shop/items/*.json(ships pre-seeded with 4 sample items spanning all 5 product types), edited vianpm run shop -- import <file>. - Adhara (
GRAVITY_SHOP_BACKEND=adhara, or auto-detected once the SDK is installed +ADHARA_WORKSPACEis set) — real Products and Services, fetched via the SDK’slistPublicProducts/getPublicProduct/listPublicServices/getPublicService(no API key needed for browsing).
Three real checkout paths, tried in order
shopStore.checkout() tries these in order — which path is even reachable depends on what’s
configured:
- Authenticated multi-item (
ADHARA_API_KEYset) — real cart checkout via the SDK’screateCheckoutSession, Products only, priced by a specificProductPrice.id. Whether Services can go through this endpoint isn’t confirmed. - Public single-item (
ADHARA_WORKSPACEonly, no API key) — real checkout viacreatePublicCheckout, but only for a cart that resolves to exactly one distinct line item — Adhara has no public multi-item checkout endpoint yet. - Local pending order (always available) —
data/content/shop/orders/<id>.json, statuspending, no payment taken — for manual follow-up. Same honesty principle as scheduling’s local demo mode: never claim something happened that didn’t.
Payment-provider agnostic
The checkout layer doesn’t name a specific payment processor anywhere in this repo’s code or docs — Adhara’s backend may support more than one in the future, and nothing here should assume it’s locked to one.
A known, confirmed extension point
Adhara’s backend also has a full session-based public shopping cart API
(/public/cart/{workspace_slug} — create/read/clear a cart, add/update/remove items,
validate, checkout) that would remove path 2’s one-item limit for public storefronts. The
SDK doesn’t wrap it yet, and adopting it means moving the cart from this repo’s client-side
localStorage (public/js/shop-cart.js) to an Adhara-hosted server session — a real
architectural change, not a small patch. See The Adhara SDK for the full list of
confirmed-but-unbuilt extension points.
Architecture
src/lib/adharaCommerce.ts (SDK calls) → src/services/shopStore.ts (catalog merge,
backend/checkout-path resolution) →
src/pages/shop/{index,[slug],cart,checkout,checkout/confirmed,checkout/cancelled}.astro +
src/pages/api/shop/{catalog,checkout}.ts + public/js/shop-cart.js.