# Building on mongrl

This storefront runs on the mongrl API (https://dev.mongrl.com). mongrl owns the
data and the rules: accounts, listings, search, checkout, orders, payouts,
shipping and messages. This repo is only the storefront.

## Sources of truth

- Docs for agents: https://dev.mongrl.com/llms.txt (index) and
  https://dev.mongrl.com/llms-full.txt (everything). Any page as Markdown: add
  `.md` to its URL.
- API: the OpenAPI spec in this repo (copied from https://dev.mongrl.com/openapi.json).
  Never guess an endpoint, parameter or field: look it up there.
- The generated client in `src/api/generated` comes from that spec. Don't edit
  it; regenerate it (`npx openapi-ts`) after updating the spec.

## Rules

1. **Server only.** Call mongrl from the server. The secret key
   (`MONGRL_SECRET_KEY`, `sk_…`) and users' session tokens never reach the
   browser. Browsers can't call the API directly.
2. **Sessions.** Sign-in returns `session.token`. Keep it in an HttpOnly,
   Secure, SameSite=Lax cookie and send it as `X-User-Session` with the secret
   key. On a 401 for a user request, clear the cookie and ask them to sign in.
3. **Money** is `{ amount, currency }`, `amount` in minor units (`125000` SEK
   is 1 250,00 kr). Format with `Intl.NumberFormat`; never do float maths on it.
   Show `display_price` when you asked for a `currency`; charge what the quote
   says.
4. **Errors** are RFC 9457 problems: show `detail` to people, and map
   `errors[].location` (e.g. `body.title`) onto form fields. Never show a raw
   status code.
5. **Retries.** Send an `Idempotency-Key` (a fresh UUID per user action) on
   writes that might be retried, above all `placeOrder`.
6. **Orders** move only by transitions. Offer the buyer or seller exactly the
   ones in `order.available_transitions`; don't infer them from `state`.
7. **Checkout:** `quoteOrder` to show the price, `placeOrder` to reserve the
   listing and get `payment.client_secret`, then Stripe's Payment Element with
   the marketplace's Stripe publishable key. The order becomes `purchased` when
   Stripe confirms; read it back instead of assuming.
8. **Paging:** listings, favourites, catalogue terms and a seller's listings
   use `cursor` / `next_cursor`; orders and conversations use `offset`.
9. **Words:** the thing on sale is a "listing" (not item or product). Buyers
   and sellers are users; the marketplace's team are operators.
10. **Emailed links** land on your pages: `/<lang>/auth/sign-in?token=`,
    `/<lang>/auth/verify-email?token=`, `/<lang>/auth/reset-password?token=`,
    `/<lang>/orders/<id>`, `/<lang>/messages/<id>` and
    `/<lang>/account/listings/<id>`. Build all of them
    (https://dev.mongrl.com/guides/storefront-pages.md).

11. **Pages:** the home page and content pages come from `GET /v1/pages/{slug}`.
    Render each block by its `type` in your design and skip unknown types; don't
    hard-code their content (https://mongrl.dev/guides/pages.md).

## Before you say it's done

- Typecheck against the generated client: no `any` around API calls.
- Try the flow in the test environment (`https://api.staging.mongrl.com`,
  `sk_test_…` keys, Stripe test card 4242 4242 4242 4242).
