A South African men's apparel store on Spree 5.6 + Next.js 15. 160 products
live, three markets, live Malaysian courier rates, customer-owned carts.
What is here:
storefront/ the Next.js app
backend/ ONLY the custom Spree code. Spree itself is a prebuilt image
that mounts no app code, so every file here needs an explicit
volume entry in docker-compose.yml or it is silently ignored.
catalogue/ the scripts that loaded and maintain the products
docs/ manifest, mock registry, napkins
Real .env files are committed deliberately. This lives on the house's private
Gitea, and a clone that runs beats a clone that needs a secrets handover.
LANDMINE.md maps every key, what it opens, and what must be rotated before this
repo goes anywhere less private.
The admin API key used to be a literal in six catalogue scripts. They now read
SPREE_ADMIN_KEY from the environment and refuse to run without it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
140 lines
6.5 KiB
Markdown
140 lines
6.5 KiB
Markdown
# 🏷️ MOCKS — every fake value in Pak Jabit
|
||
|
||
**The convention:** anything standing in for a real credential, rate, or record is
|
||
tagged `#mock`. Going live = find them all, replace them, delete this list.
|
||
|
||
```bash
|
||
# storefront + backend files
|
||
rg '#mock' ~/pak-jabit-store ~/pak-jabit
|
||
```
|
||
|
||
🔴 **`rg` cannot find half of them.** Mocks that live in the Spree **database** —
|
||
payment methods, test products, test orders, test users — have no file to grep.
|
||
This file is the authority; the inline tags are a convenience. When you add a
|
||
mock, add it here first.
|
||
|
||
⚠️ **Never tag an env var inline.** Docker Compose's `env_file` does not strip
|
||
trailing comments — it takes the rest of the line as the value, so
|
||
`PHOTOROOM_API_KEY=abc123 #mock` makes the key literally `abc123 #mock` and
|
||
Photoroom fails with no error anywhere. The tag goes on its **own line above**,
|
||
which is safe in both Compose and dotenv.
|
||
|
||
---
|
||
|
||
## Files — `rg '#mock'` finds these
|
||
|
||
### Storefront `~/pak-jabit-store/.env.production` (celest-proto, 34.21.217.116)
|
||
|
||
| Var | Why it's mock | Replace with |
|
||
|---|---|---|
|
||
| `EASYPARCEL_CLIENT_ID` | Malaysia-only courier, left from the MY phase | Bob Go credentials |
|
||
| `EASYPARCEL_CLIENT_SECRET` | same | Bob Go credentials |
|
||
| `STORE_POSTCODE` | `10150` = Penang, Malaysia | real SA warehouse postcode |
|
||
| `STORE_STATE` | `MY-07` = Penang, Malaysia | real SA province |
|
||
|
||
The whole EasyParcel lane (`src/lib/easyparcel.ts`, `src/app/api/shipping/*`,
|
||
`src/app/api/webhooks/easyparcel`) is MY-only and dead for a South African store.
|
||
It points at `https://api.easyparcel.com` — the production host, not a sandbox.
|
||
It is not wired into the SA checkout path; it just hasn't been removed.
|
||
|
||
### Backend `~/pak-jabit/.env` (pak-jabit-backend, 35.247.170.3)
|
||
|
||
| Var | Why it's mock | Replace with |
|
||
|---|---|---|
|
||
| `PHOTOROOM_API_KEY` | sandbox key — **every output is watermarked** | live key from `/root/.photoroom/credentials` (house box), 10/month |
|
||
|
||
### Storefront env — `SPREE_CARD_PAYMENT_METHOD_ID`
|
||
|
||
Tagged in `.env.production`. Holds `pm_EfhxLZ9ck8`, the prefixed id of the Bogus
|
||
gateway. Repoint it at the Payfast payment method when that lands. The route that
|
||
reads it (`src/app/api/auth/cards/setup/route.ts`) errors loud with an explicit
|
||
message when it is unset — it never guesses an id, because a wrong one would
|
||
attach cards to whichever gateway happened to match.
|
||
|
||
That route is itself `#mock`-shaped: it does BOTH halves of card setup in one
|
||
request, which only works because Bogus needs no card entry. A real gateway must
|
||
split it — server creates the session, the CLIENT collects the card in the
|
||
gateway's hosted field against `external_client_secret`, then the server
|
||
completes. Card numbers must never reach our server. The file says so at the top.
|
||
|
||
---
|
||
|
||
## Database — grep will never find these
|
||
|
||
### Payment methods
|
||
|
||
| Name | Class | Why it's mock |
|
||
|---|---|---|
|
||
| `Test Card (sandbox)` | `Spree::Gateway::Bogus` | Fake card gateway, added 2026-09-15. Accepts `4111111111111111` (Visa), `5555555555554444` (MC), `378282246310005` (Amex), `6011111111111117` (Discover); **anything else is a forced decline**, which is how to test the failure path. `show_in_admin?` is false so it stays out of the admin list. |
|
||
| `Test Payment` | `Spree::PaymentMethod::Check` | Offline placeholder. No money moves. |
|
||
|
||
Both carry `#mock` in their `description` column, visible in admin.
|
||
|
||
**Replace with:** Payfast, once NSH's merchant registration lands. Payflex after.
|
||
Deactivate both of these before launch — a live store must not offer a gateway
|
||
that approves every card ending in the right digits.
|
||
|
||
### Shipping methods
|
||
|
||
| Name | Why it's mock |
|
||
|---|---|
|
||
| `Standard Delivery (South Africa)` | Flat **R99**, zone `South Africa` (ZA only), added 2026-09-15. The number is a PLACEHOLDER, not a quoted rate — it exists so SA checkout can complete at all. Replace with Bob Go once the SA courier account is registered. |
|
||
|
||
Before this, ZA sat in the `Africa` zone with no method attached and every
|
||
physical method was bound to Malaysia/US, so a South African buyer got no quote
|
||
and checkout dead-ended.
|
||
|
||
### Shipping rates per market — all placeholders
|
||
|
||
| Market | Method | Rate |
|
||
|---|---|---|
|
||
| South Africa (ZAR) | `Standard Delivery (South Africa)` | R99 |
|
||
| Malaysia (MYR) | `EasyParcel Domestic` | **live EasyParcel quote** — not mock |
|
||
| United States (USD) | `Free Shipping` | $0 |
|
||
|
||
🔴 **ZA and US are placeholders; Malaysia is real.** MY charges the courier the customer picked, verified server-side against a live EasyParcel quote. They exist so each market can complete a
|
||
checkout at all. A shipping rate only applies when its calculator's currency
|
||
matches the ORDER's currency — every non-SA method was priced in a currency no
|
||
order used, which produced no rate, no fulfillment, and a checkout with nothing
|
||
to charge. That, not zones or stock, is why Malaysian checkout died silently.
|
||
|
||
`Standard Shipping` (USD $15) sits in the Malaysia zone and will never offer —
|
||
wrong currency for that market. Harmless, but it is noise to clear when the MY
|
||
lane is removed.
|
||
|
||
### Products
|
||
|
||
| Slug | Why it's mock |
|
||
|---|---|
|
||
| `studio-test-chinos` | Built 2026-09-15 proving the Image Studio pipe end to end. Kept deliberately as the worked example for colleagues testing the image editor. R259.11, watermarked sandbox images. **Delete before launch.** |
|
||
|
||
That's 1 of 161 products. The other 160 are real scraped stock.
|
||
|
||
### Orders
|
||
|
||
14 orders, 4 completed, all test. They are priced in the **old currency at the
|
||
old 23× rate** — the newest completed one reads `$2,577.12`, which is neither
|
||
ZAR nor a real price. They predate both the price fix and the ZAR switch.
|
||
**Purge before launch** or the first real report is nonsense.
|
||
|
||
### Users
|
||
|
||
Test accounts matching `celeste-*@example.com` — created during API verification
|
||
on 2026-09-15. No real customers exist yet.
|
||
|
||
---
|
||
|
||
## Not mock, but not real either
|
||
|
||
These aren't fake credentials; they're claims the store makes that nothing backs.
|
||
|
||
| Thing | Problem |
|
||
|---|---|
|
||
| **"Free shipping over R500"** | Hardcoded storefront copy. No shipping rule exists behind it. A buyer who qualifies gets charged anyway — or gets no quote at all, see below. |
|
||
| **SA shipping** | ZA is in the `Africa` zone with **no shipping method attached**. Every physical method is bound to Malaysia/US. A South African buyer gets no quote and cannot complete checkout. Blocked on courier registration. |
|
||
| **S/M/L/XL buttons** | Decorative. No `Spree::Variant` behind them — every product is one variant. |
|
||
|
||
---
|
||
|
||
*Started 2026-09-15. Add to this file when you add a mock, not after.*
|