Store Architecture Guide
Audience: Engineers and architects designing a Dr Green-backed storefront. This document explains the complete moving parts so you can decide where each piece of your store lives.
The big picture
Components and ownership
Owned by you (the store builder)
- Store UI — the storefront the customer sees. Web, mobile, both. Yours.
- Store backend — your service that calls Dr Green’s API on behalf of the customer. Keeps your own customer DB, cart/order state, polling jobs.
- Customer DB — typically you mirror Dr Green’s
clients/ordersrecords to your own DB so you can render fast (don’t hit Dr Green for every page load). Keep it lean: store IDs, status, last-known shape; don’t duplicate PII unless you have a clear retention reason. - Polling infrastructure — background jobs that periodically check order/KYC status and notify customers of changes.
Owned by Dr Green
- API backend (
api.drgreennft.com) — NestJS, Postgres, behind Envoy proxy - Auth — both the DAPP UI’s JWT auth flow and your API-key signature flow
- Catalogue & inventory — the strain catalogue, country-availability, pricing
- Order fulfilment — admin approval, payment processor integration, dispatch
- KYC integration — the FirstAML relationship and case management
- Smart-contract integration — NFT ownership, on-chain commission settlements
- Email — transactional emails to customers (KYC, order updates)
Owned by third parties
- FirstAML — KYC/AML verification (customer interacts directly with their portal)
- CoinRemitter — crypto payment gateway
- Payinn / PGPay — fiat payment gateways
- Sumsub ❌ — not used. (Older versions of these docs incorrectly listed Sumsub as the KYC provider; that was based on a mis-read of the codebase. The provider is FirstAML.)
Data flows in detail
Read flow (browsing the catalogue)
(countryCode, page, limit) cache key. Cache strain detail for 10 minutes per strainId. Drop on 404.
Write flow (customer onboarding)
Order lifecycle flow
See order-lifecycle.md for the detailed version.Where to put which logic
| Concern | Your backend | Dr Green | Why |
|---|---|---|---|
| Customer-facing UI | ✅ | — | You own the brand experience |
| Customer login (your store) | ✅ | — | Decoupled from Dr Green wallet auth |
| Cart state during shopping | ✅ | (also stored, but defer to yours) | Fast UI; Dr Green’s /dapp/carts is the audit copy |
| KYC verification | — | ✅ | Compliance ownership; FirstAML relationship |
| Order pricing in customer currency | — | ✅ | Dr Green sets pricing; your store displays |
| Payment collection | — | ✅ | Dr Green owns the processor relationships |
| Inventory & stock-outs | — | ✅ | Strain catalogue is Dr Green’s source-of-truth |
| Order shipping | — | ✅ | Dispatch is Dr Green’s responsibility |
| Customer support (general) | ✅ | — | First-line is your team |
| Customer support (KYC issues) | (escalate) | ✅ | Dr Green ↔ FirstAML; you can’t resolve directly |
| Customer support (delivery issues) | (escalate) | ✅ | Same — Dr Green dispatches |
| Marketing & customer comms | ✅ | (transactional only) | Dr Green sends KYC + order emails; you do everything else |
Auth boundaries
- No auth — public endpoints (
/auth/nonce,/public/healthStatus, customer-facing KYC/payment redirects) - JWT — used by the DAPP UI when the holder is logged in. Generated via wallet sign-in. Required for
/keys/*,/user/me,/dapp/users/nfts. Store builders do not have a JWT — they have the API key pair the holder generated using their JWT. - API-key + signature — used by stores. Long-lived (no expiry, no refresh), per-NFT scope, signed per-request with ECDSA secp256k1.
DualAuthGuard on /dapp/* routes accepts either JWT or API-key+signature — meaning the same endpoints serve the DAPP UI and external stores.
Scoping: per-NFT, per-key
Every API key pair is scoped to one primary NFT. If a holder owns multiple NFTs and runs separate businesses for each:- Generate one key pair per NFT
- Treat them as separate stores in your code (or as separate accounts in your multi-tenant setup)
- Don’t try to “swap NFTs” mid-session — switching primary NFT is a DAPP-UI-only operation, and doing it from your store would corrupt your in-flight state
nft.tokenId from any authenticated response tells you which NFT the current key is scoped to. Cache it on first call; verify on startup if you’ve encoded NFT-specific config.
Network topology
Production
- API base:
https://api.drgreennft.com/api/v1 - TLS enforced
- Reverse proxy: Envoy (production deployment)
- The OpenAPI spec is publicly accessible at
/api-json
Staging
- API base:
https://stage-api.drgreennft.com/api/v1 - ⚠️ Currently HTTP 503 (Envoy upstream connect error) — has been since at least 8 May 2026. If you need staging access, contact Dr Green.
Your topology (recommendations)
- Outbound from your backend → Dr Green: stable IPs are not currently required by Dr Green, but expect this to change. If your hosting rotates IPs, talk to Dr Green about IP allow-listing if/when they enforce it.
- No customer-browser → Dr Green calls. Your backend is the proxy. CORS-allowed origins are limited; call from server-side only.
- Outbound to FirstAML, payment processors: none. You do not call these directly. All third-party integrations are Dr Green’s domain.
Operational concerns
Rate limits
Not enforced as of 10 May 2026, but engineer politely:- ≤ 1 req/sec per holder for background polling
- Cache the catalogue aggressively (5–60 min TTLs)
- Use
/dapp/orders/recentas a heartbeat across all customers rather than polling each one
Failure modes you must handle
| Mode | Detection | Mitigation |
|---|---|---|
| Dr Green API 5xx | Retryable HTTP error | Exponential backoff, max 3 attempts. Surface as “temporarily unavailable” |
| API key revoked by holder | 401 "User is not authorized" after previously working | Alert ops; degrade to read-only or stop accepting orders |
| FirstAML KYC stuck for hours | isKYCVerified stays false for >24h | Surface to customer (“verification in progress, contact support if it persists”); escalate to Dr Green |
| Payment processor down | Order stuck in paymentStatus: PENDING | Wait — can take hours for crypto. If >24h, escalate |
| Idempotency on order POST | Network error during placement | GET /dapp/orders to check before retrying. See 04-errors.md § Idempotency |
| Strain soft-deleted between catalogue and order | 404 on order line | Re-fetch catalogue, drop stale items, re-render |
Observability
For every Dr Green API call, log:- HTTP method, path, status code
- Response time
- Your generated correlation ID (for cross-service tracing)
- Truncated
x-auth-apikey(first 16 chars) for key-rotation diagnostics
- Full
secretKeyever - Customer KYC fields (DOB, ID numbers, medical record content)
- Full
x-auth-signatureheaders (verbose; useful only for very specific debugging)
Multi-tenant store builders
If you operate stores for multiple holders (e.g. you sell a SaaS that wraps Dr Green):- Store each holder’s
(apiKey, secretKey)pair encrypted-at-rest, indexed by your tenant ID - Cache the resolved
nft.tokenIdper tenant for routing/scoping - Use a separate DAPP-Green API client instance per tenant (don’t share the long-lived signing key across requests)
- Implement bulk operations carefully — a 1000-tenant batch poll without jitter will create thundering herds
Anti-patterns to avoid
| Anti-pattern | Why bad | Do instead |
|---|---|---|
Storing secretKey in code or git | Catastrophic if leaked | Secrets manager + env var injection at deploy |
| Calling Dr Green from customer browsers | CORS, exposes API keys, fragile | Server-side only, your backend proxies |
| Polling every customer every minute | Rate-limit risk + infrastructure cost | Active-set polling with jitter, see 06-webhooks.md |
| Using customer email as primary key | Email is not unique across holders | Always use the UUID id |
Auto-correcting profitRecieved to profitReceived | Returns undefined from API | Match the typo until Dr Green ships v2 |
Trusting data.totalProfit from /revenue/summary | Equals totalSales in observed data — likely buggy | Use dashboard.totalProfit as canonical |
| Re-implementing FirstAML’s KYC UI | Not your job | Customer goes to FirstAML’s hosted portal via Dr Green’s email |
Where to next
- KYC flow — the full FirstAML integration deep-dive
- Order lifecycle — every status transition explained
- Reference index — endpoint-by-endpoint detail