Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions content/docs/storefront/app/marketplace-edition.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
title: Marketplace Edition
description: Run the Storefront App as a multi-vendor marketplace with a network key, merchant discovery, map browsing, scoped carts, and optional multi-store checkout.
---

# Marketplace Edition

The Storefront App selects its edition from `STOREFRONT_KEY`. A `store_...` key opens the established single-store experience. A `network_...` key opens the marketplace experience without requiring a separate build or a copied application.

```bash
FLEETBASE_HOST=https://your-fleetbase.example.com
FLEETBASE_KEY=flb_live_...
STOREFRONT_KEY=network_your_network_key
```

At boot, the app requests `GET /storefront/v1/about`, identifies the returned owner, and builds the appropriate navigator. Changing the key and restarting is enough to switch editions; cached marketplace, selected-store, location, and cart state are namespaced by host and owner so one deployment cannot leak state into another.

## Marketplace navigation

The marketplace tab bar provides:

| Tab | Behavior |
| :--- | :--- |
| **Discover** | Paginated member-store discovery, marketplace categories, tags, online filtering, and rating, age, popularity, trending, or nearest sorting |
| **Search** | Concurrent product and merchant search with separate result types and direct navigation to either detail screen |
| **Map** | Network store locations on a synchronized map and list; invalid coordinates are ignored safely |
| **Cart** | Store-grouped line items, combined quantity badge, delivery-origin selection, and checkout policy feedback |
| **Profile** | The existing customer account, locations, order history, locale, and authentication flows |

Opening a merchant keeps the marketplace shell visible. Product categories and searches inside that merchant are explicitly scoped to its store ID, while the user can return to discovery without resetting their marketplace cart.

## Configure the network first

Before launching the app:

1. Create a [Network](/docs/storefront/networks/overview) and add each merchant store.
2. Give every visible store at least one valid Store Location and published, available products.
3. Set store logos, backdrops, operating state, categories, and tags used by discovery.
4. Configure network-level payment gateways, notification channels, currency, and Fleet-Ops order configuration.
5. Decide whether to enable `options.multi_cart_enabled`.
6. Copy the network's `network_...` key from **Storefront → Settings → API** into the app environment.

Only active network members are returned through marketplace routes. Store, category, product, review, and location identifiers from another network are treated as unavailable rather than exposed across tenant boundaries.

## Cart policy

Every marketplace line item records both the product's `store_id` and a `store_location_id` belonging to that store.

- With `multi_cart_enabled` off, adding an item from another merchant prompts the customer to replace the current cart or cancel.
- With it on, items are grouped by merchant and checkout derives one delivery origin per store.
- Products and locations are revalidated at checkout so removed membership, offline stores, unpublished products, or mismatched store locations fail before payment starts.
- A cart cannot mix currencies. Keep all member stores and network gateways on the same currency.

Cart decisions and recoverable errors are shown before payment, so customers can remove an invalid merchant group or choose another location without losing unrelated items.

## Location and privacy

Discovery works without location permission. The app asks for location only after the customer chooses a map/nearby action. Denial leaves list browsing, search, and manual address selection available; it does not create a permission loop at boot.

For nearest sorting or distance filtering, the app sends latitude and longitude to `GET /storefront/v1/stores`. The backend calculates the nearest valid location per member store and applies `maximum_distance` in meters.

## Customer and checkout security

The Storefront key is public application configuration, not a customer credential. Authenticated requests additionally send the token returned by customer login as `Customer-Token`.

During checkout, `Customer-Token` is authoritative. If the request body supplies another customer's public ID, Storefront returns `403`. Guest checkout can still submit a customer ID when no customer token is present.

## Verification checklist

Test both editions before release:

- Boot once with a `store_...` key and confirm the original store home, cart, checkout, and profile flows.
- Boot with a `network_...` key and confirm discovery pagination, categories, filters, search, merchant navigation, and map/list synchronization.
- Exercise permission granted, denied, and unavailable-device location states.
- Exercise single-store replacement and enabled multi-store cart policies.
- Complete delivery and pickup checkout with each enabled payment gateway.
- Remove a store from the network or take it offline and confirm stale products and cart items fail safely.
- Run `yarn lint:marketplace`, `yarn typecheck:marketplace`, `yarn test:ci`, and `yarn web:build` before producing native release builds.

## Troubleshooting

| Symptom | Check |
| :--- | :--- |
| Empty marketplace | The key starts with `network_`, the network is online, member stores have locations, and stores are assigned to this network |
| Merchant opens with no products | Products are published and available, and their store still belongs to the network |
| Nearest sorting has no results | Store locations have valid coordinates and `maximum_distance` is in meters |
| A second merchant cannot be added | Enable `options.multi_cart_enabled`, or accept the app's replace-cart prompt |
| Checkout rejects a location | The selected location must belong to the same store as its cart product |
| Checkout returns `403` for customer | Clear stale customer state and sign in again; the submitted customer must match `Customer-Token` |

See [Cart](/docs/storefront/orders/cart), [Service Quotes](/docs/storefront/orders/service-quotes), and [Checkout](/docs/storefront/orders/checkout) for the corresponding backend contracts.
8 changes: 4 additions & 4 deletions content/docs/storefront/app/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The **Storefront App** is the open-source customer-facing client for the Storefr
| Capability | Notes |
| :--- | :--- |
| **iOS, Android & web** | Single codebase. Native via React Native + Hermes (New Architecture); web via `react-native-web` + Webpack |
| **Storefront browsing** | Home, search, map view, product detail, cart, checkout, receipt — wired to the [Storefront API](/docs/storefront/settings/api) |
| **Store and marketplace browsing** | Store home or marketplace discovery, merchant search, map/list view, product detail, cart, checkout, and receipt — selected automatically from the Storefront key |
| **Cart & checkout** | Multi-product cart with options/variants/addons, address book, location picker, real-time service quote |
| **Payments** | Stripe (PaymentSheet or CardField, with Apple Pay & Google Pay), QPay, PayPal scaffolding |
| **Customer auth** | Phone + 2FA SMS, email/password, plus optional Apple, Google, and Facebook social sign-in |
Expand Down Expand Up @@ -42,14 +42,14 @@ You point the app at a backend by setting three environment variables in `.env`:
```
FLEETBASE_HOST=https://your-fleetbase.example.com
FLEETBASE_KEY=flb_live_...
STOREFRONT_KEY=$store.your_store_key
STOREFRONT_KEY=store_your_store_key
```

See [Quickstart](/docs/storefront/app/quickstart) for the full setup.
Use a `network_...` key instead to launch the [Marketplace Edition](/docs/storefront/app/marketplace-edition). See [Quickstart](/docs/storefront/app/quickstart) for the full setup.

## Project Status

Single-store mode is production-ready and runs in real deployments today. The multi-vendor / network navigator is scaffolded in the codebase but not feature-complete — most teams currently use the app in single-store mode.
The same app build supports both production editions. Store keys preserve the direct-to-store experience; network keys activate marketplace discovery, merchant and product search, map browsing, network-scoped carts, and multi-store checkout when enabled by the network.

## Next Steps

Expand Down
9 changes: 5 additions & 4 deletions content/docs/storefront/app/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ APP_IDENTIFIER=com.yourcompany.storefront
# Your Fleetbase backend
FLEETBASE_HOST=https://your-fleetbase.example.com
FLEETBASE_KEY=flb_live_...
STOREFRONT_KEY=$store.your_store_key
STOREFRONT_KEY=store_your_store_key

# Real-time order updates
SOCKETCLUSTER_HOST=socket.your-fleetbase.example.com
Expand Down Expand Up @@ -106,9 +106,7 @@ yarn web

Webpack dev server boots and serves the app at the URL it logs. The web target uses `react-native-web` with build-time aliasing for native-only modules.

<Callout type="info">
The web build is functional for development and demos. There is no production-optimized webpack configuration in the repo — if you intend to ship the web app to customers, plan to add one.
</Callout>
Create a production web bundle with `yarn web:build`. The build performs Tamagui extraction and writes the deployable output to `dist/`.

## 5. Sign In and Browse

Expand All @@ -117,6 +115,8 @@ Once the app launches:
2. The app discovers the configured store (or network) and renders its catalog.
3. Customer accounts are created via the **Phone + SMS** flow by default, or via Apple/Google/Facebook if you've enabled those (see [Integrations](/docs/storefront/app/integrations)).

A `network_...` key automatically opens merchant discovery, marketplace search, map browsing, and the network-aware cart. See [Marketplace Edition](/docs/storefront/app/marketplace-edition) for network preparation and release verification.

## Common Issues

| Symptom | Likely cause |
Expand All @@ -131,6 +131,7 @@ Once the app launches:
## Next Steps

- [Configuration](/docs/storefront/app/configuration) — full env-var and config reference
- [Marketplace Edition](/docs/storefront/app/marketplace-edition) — configure and validate a network-powered app
- [Theming](/docs/storefront/app/theming) — colors, fonts, branding assets
- [Integrations](/docs/storefront/app/integrations) — payment gateways, social login, push notifications
- [Build & Release](/docs/storefront/app/build-and-release) — release builds for App Store, Play Store, and web
1 change: 1 addition & 0 deletions content/docs/storefront/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"settings/notifications",
"---Storefront App---",
"app/overview",
"app/marketplace-edition",
"app/quickstart",
"app/configuration",
"app/theming",
Expand Down
2 changes: 2 additions & 0 deletions content/docs/storefront/networks/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Authorization: Bearer network_a1b2c3d4...

See [API Settings](/docs/storefront/settings/api) for the full authentication model.

The open-source Storefront App recognizes the prefix at boot and switches to its marketplace navigator automatically. See [Storefront App Marketplace Edition](/docs/storefront/app/marketplace-edition) for discovery, search, map, cart, and release behavior.

## Deleting a Network

Open the network in the console and click **Delete**. Member stores are not deleted — they remain available as standalone stores or can be re-attached to another network. Historical orders associated with the network are retained.
Expand Down
4 changes: 3 additions & 1 deletion content/docs/storefront/orders/cart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Authorization: Bearer store_your_store_key
}
```

`store_location` is optional — if omitted, the cart picks the store's first location. Variants and addons are stored as full objects (their `additional_cost` and `price` are read by the cart subtotal calculator).
`store_location` is optional — if omitted, the cart picks the store's first location. When supplied, it must belong to the product's store. Variants and addons are stored as full objects (their `additional_cost` and `price` are read by the cart subtotal calculator).

## Updating Items

Expand Down Expand Up @@ -115,6 +115,8 @@ When **Enable multi-cart checkout** is toggled on for a Network:
- On successful capture, Storefront produces **one Fleet-Ops order per store**, each with its own pickup location, store-specific dispatch, and proof-of-delivery
- The customer pays once but receives multiple deliveries

Before payment initialization, Storefront revalidates that every store remains an online network member, every product is published and available from the recorded store, every location belongs to that store, and all products use one currency. A failed validation does not charge the customer.

Toggle this from **Storefront → Networks → [Network] → General Settings → Enable multi-cart checkout**.

<Callout type="info">
Expand Down
15 changes: 12 additions & 3 deletions content/docs/storefront/orders/checkout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This split exists so the frontend can confirm payment with the gateway SDK (whic
## Step 1 — `/checkouts/before`

```http
POST /storefront/v1/checkouts/before
GET /storefront/v1/checkouts/before
Authorization: Bearer store_your_store_key
Customer-Token: 1|VlKK7lZ...

Expand All @@ -30,11 +30,15 @@ Customer-Token: 1|VlKK7lZ...
}
```

Required:
Required parameters:
- **`cart`** — the cart's public id
- **`gateway`** — the gateway public id selected by the customer
- **`serviceQuote`** — the [Service Quote](/docs/storefront/orders/service-quotes) id (omit for pickup orders)
- **`customer`** — the customer's public id
- **`customer`** — the customer's public id for guest checkout, or the same customer represented by `Customer-Token`

<Callout type="warn">
When `Customer-Token` is present, it is authoritative. Supplying another customer's public ID returns `403`; a public Storefront key cannot be used to check out as an arbitrary customer.
</Callout>

Optional:
- **`pickup`** — `true` for in-store pickup, defaults to delivery
Expand Down Expand Up @@ -106,6 +110,11 @@ The `/before` step validates that:
- The selected gateway is configured for the store/network
- The customer is authenticated (when authentication is required by your flow)
- The cart subtotal meets the minimum order amount (if configured)
- Every marketplace store is still an online member of the authenticated network
- Every product and store location still belongs to its recorded store
- Multi-store checkout is enabled when the cart spans merchants
- Every cart line uses the same currency
- A submitted customer matches the authenticated `Customer-Token`

The `/capture` step validates that:
- The token is valid and not yet used
Expand Down
17 changes: 5 additions & 12 deletions content/docs/storefront/orders/service-quotes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,13 @@ Request a quote whenever the customer:
## Endpoint

```http
POST /storefront/v1/service-quotes/from-cart
GET /storefront/v1/service-quotes/from-cart
Authorization: Bearer store_your_store_key

{
"cart": "cart_abc123",
"delivery_address": {
"street": "123 Main St",
"city": "San Francisco",
"country": "US",
"coordinates": [-122.4194, 37.7749]
}
}
?cart=cart_abc123&destination=place_customer_address
```

The endpoint accepts a `cart` reference plus a delivery address. Storefront looks up the cart's pickup location(s), asks Fleet-Ops for the matching Service Rate, and returns a quote.
The endpoint accepts a `cart` reference plus a destination Place public ID or coordinate payload. Storefront looks up the cart's pickup location(s), asks Fleet-Ops for the matching Service Rate, and returns a quote. `origin` is an optional fallback store-location public ID; marketplace carts normally derive origins from each line item or the corresponding store's default location.

## Response

Expand Down Expand Up @@ -66,7 +58,7 @@ Display `amount` to the customer as the delivery fee. When they confirm and proc

## Multi-Store Carts

For a multi-cart in a network, the cart spans multiple pickup locations. Storefront produces a service quote that aggregates the delivery legs — at capture time, this becomes one Fleet-Ops order per store, each with its own dispatch.
For a multi-cart in a network, the cart spans multiple pickup locations. Storefront resolves one valid origin per member store in the cart, preserves stable cart order, and rejects missing or cross-store location IDs with `422`. The resulting quote carries those origins into store-specific fulfillment at capture time.

## Pickup Orders

Expand All @@ -78,5 +70,6 @@ The endpoint returns an error when:
- The cart's pickup location cannot deliver to the given address (out of range)
- No Service Rate is configured in Fleet-Ops for the route
- Required address fields are missing
- A marketplace origin is missing, belongs to another store, or is outside the authenticated network

Surface the error message to the customer so they can adjust their address or switch to pickup.