XtraDTF Alpha — internal runbook
Manual walkthrough — create a Surface 5 tenant, add a downstream public-film shop, run a referred embed order, and verify merchant-of-record payment, network fulfillment, and affiliate commission accrual.
| Business rule | How you verify it |
|---|---|
| Surface 5 tenant can own downstream Surface 1 | Platform shows child under tenant; child has downstream_surface = public_film |
| Parent is merchant of record (MoR) | Checkout on child embed uses parent mock payment account (DB: parent shop payment settings) |
| XtraDTF network root fulfills the job | Order fulfillment_shop_id = xtradtf; job appears in Ops queue for xtradtf |
| Affiliate commission accrues on parent ledger | Parent shop admin → Affiliates → ledger row after paid order |
| Referral code from URL flows to checkout | Embed shows “Referral code … applied”; commission matches order total × affiliate % |
| App | URL | Login | Password |
|---|---|---|---|
| Platform admin | /platform/ | platform@xtradtf.com |
ChangeMeOnFirstLogin! |
| Network root shop admin (xtradtf) | /admin/ | admin@xtradtf.com |
ChangeMeOnFirstLogin! |
| Production ops (xtradtf queue) | /ops/ | prod@xtradtf.com |
ChangeMeOnFirstLogin! (same seed) |
| Extranet (Surface 3 — not part of this walkthrough) | /extranet/ | Use extranet partner admin you create separately | |
Direct XtraDTF retail calculator (not used in Option B, but handy):
https://alpha.xtradtf.com/embed/?shop=xtradtf&key=b6d4e0747cb9463e18ad1dd202e1e19d36cff36f7d2b75e9
| Plan | Slug | Price | Use in this walkthrough |
|---|---|---|---|
| Surface 5 — Full Tenant | full-tenant | $249/mo | Parent tenant |
| Surface 3 — Extranet Film | extranet-film | $249/mo | Not used here |
| Surface 4 — API/POD | api-pod | — | Deferred / inactive |
Pick your own slugs if these are taken; keep them memorable.
| Role | Suggested slug | Suggested admin email | Admin password |
|---|---|---|---|
| Surface 5 parent tenant | acme-tenant | admin@acme-tenant.test | AcmeTenant123! |
| Downstream Surface 1 child | acme-retail | admin@acme-retail.test (optional) | AcmeRetail123! |
| Affiliate code | acme-ref at 10% commission | ||
Open Platform admin → Partners & tenants → Add partner.
acme-tenant (or your choice)12-3456789admin@acme-tenant.testAcmeTenant123!Click Create partner. New partners always start trial + EIN pending.
In Platform → Edit partner for acme-tenant:
You can verify EIN and activate in one save — partner profile updates run before status checks.
Still editing acme-tenant in Platform — scroll to Downstream accounts → Add downstream.
acme-retailClick Create downstream. Child starts in trial (embed may still work for xtradtf network fulfillment).
Copy the child embed key: re-open the child in Platform (or parent downstream list) and note embed_api_key from shop detail. You need it for the calculator URL.
Sign out of Platform. Open Shop admin and log in as the parent tenant:
admin@acme-tenant.test / AcmeTenant123!
Go to Affiliates → Add affiliate:
acme-refLedger should be empty before the test order.
Build the child embed URL (replace CHILD_EMBED_KEY with the key from step 3):
https://alpha.xtradtf.com/embed/?shop=acme-retail&key=CHILD_EMBED_KEY&affiliate_code=acme-ref
Aliases also work: ?ref=acme-ref or ?affiliate=acme-ref.
In the calculator:
4242 4242 4242 4242 (any future expiry/CVC).Write down the order number (format XT-YYYYMMDD-XXXX).
Back in parent shop admin (admin@acme-tenant.test) → Affiliates:
accrued row for your order number.Example: $22.97 order → $2.30 commission at 10%.
Log into Ops as prod@xtradtf.com.
The paid downstream order should queue on xtradtf printers (network root fulfillment), not on the child tenant’s empty printer list.
Optional: xtradtf admin → Orders — you may see fulfillment-side activity depending on filters.
Orders are stored with origin_shop_id = child (acme-retail). If you created a child admin user, log into child shop admin → Orders to see the order.
Parent tenant admin does not list child-origin orders in the Orders tab today — that’s expected. Parent sees affiliate money; child sees the customer order.
If you have SSH, these queries confirm MoR + fulfillment + affiliate in one glance:
sudo -u postgres psql -d xtradtf_alpha -c "
SELECT o.order_number,
origin.slug AS origin_shop,
fulfill.slug AS fulfillment_shop,
o.total_amount,
o.payment_status,
o.original_quote->>'affiliate_code' AS affiliate_code
FROM orders o
JOIN shops origin ON origin.id = o.origin_shop_id
JOIN shops fulfill ON fulfill.id = o.fulfillment_shop_id
ORDER BY o.id DESC LIMIT 3;"
sudo -u postgres psql -d xtradtf_alpha -c "
SELECT c.order_number, a.code, c.commission_percent,
c.order_total, c.commission_amount, c.status
FROM affiliate_commission_entries c
JOIN shop_affiliates a ON a.id = c.affiliate_id
ORDER BY c.id DESC LIMIT 3;"
Expect: origin_shop = acme-retail, fulfillment_shop = xtradtf, affiliate row on parent shop.
After your manual walkthrough, you can run the scripted smoke test (uses xtradtf embed + creates disposable partners):
php /var/www/alpha.xtradtf.com/scripts/smoke_network_stack.php
That script does not replace Option B — it hits a shorter path on the network root shop.
public_film child exists under tenantaffiliate_code completes mock paymentxtradtf (network root), not child| Symptom | Likely cause |
|---|---|
| Embed “Missing embed key” | Wrong key= in URL; copy from Platform shop detail |
| Cannot activate tenant | EIN not verified first |
| No “Add downstream” section | Parent is not full_tenant type |
| Referral banner missing | Invalid code format; must be 2–32 chars a-z, 0-9, hyphen |
| No ledger entry after pay | Affiliate created on wrong shop (must be parent), or code mismatch |
| Ops queue empty | Production job still pending; check cron or run php scripts/process_production_jobs.php --once |
brand_logo_url per tenant (defaults to XtraDTF logo)