Skip to main content

Tutorial: Set Up Your Own Sandbox Team

The best way to understand how a team exists in Attend is to create one. In this tutorial you'll stand up your own client with a Flex and a Premium schema, wire them through code, and sell a seat in your own sandbox — the same exercise new engineers do in onboarding.

Unlike Trace a Purchase (a code read), this one is hands-on — you'll run real commands and click through Cortex, about 45–60 minutes. It teaches the moving parts; for the terse copy-paste recipe, keep How to onboard a new team open alongside.

What you need: the stack running locally (How to run the stack locally), Cortex super-user access, and a DB client (DBeaver) on the dev RDS. We'll write everything as tm_sandbox_<name>_* — substitute your own name.

Getting Cortex access: dev Cortex authenticates via staging FusionAuth (auth-staging.attendevents.com). Internal users get an invite email (titled "partner dashboard" — the same login serves both), set an 8–12-char mixed-case password, and are then marked super-user. Don't depend on the fusionAuthSource id (it changes if the account is recreated). Ask the staging admin if the invite doesn't arrive.

⚠️ The dev RDS is shared — only insert your own rows; don't touch anyone else's.


Step 1 — A team is two database rows (there's no "create" button)

"Where does a team even come from?"

In the dashboard schema (cortex_dashboard_dev), insert one tbl_clients row (your client) and one tbl_client_schema row per schema — a Flex one and a Premium one. (Exact SQL is in the how-to, Step 1.)

Things to notice:

  • Cortex has no UI for this — clients/schemas are created directly in the DB. Cortex only reads tbl_clients / tbl_products / tbl_client_schema to build its workspace picker.
  • Register both schemas under the Flex product. Premium is administered under Flex in Cortex (Suites & Premium Boxes) — there's no Premium product UI, so a row under the Premium product dead-ends the picker. (Chapter 02 is the client→product→schema model; the how-to callout explains the premium gotcha.)

Checkpoint: you can explain the client → product → schema hierarchy and why a premium schema is registered under the Flex product.

Step 2 — Build the schema's tables from the code

"The schema is named, but it's empty."

Call the builder on flex-v3-backend (POST :5011/builder/schema, once per schema). It reads the TypeORM entity definitions and creates every tbl_* table — no migration files, no copying from another schema.

Things to notice:

  • Only flex-v3-backend has a team-schema builder; cortex-backend writes into the same tables but never creates them. One builder call gives both backends a schema to work with.
  • The tables come out empty — Cortex and the inventory build fill them later (Chapter 17).

Checkpoint: you can say where a team schema's tables come from (entities, via the builder) and which backend owns that.

Step 3 — Teach the backends your schema exists (the whitelist)

"Why won't the app accept my schema?"

Add a team config for each schema in both backends and both relevant frontends (5 files total — see the how-to's table). Each backend validates the X-Team-Schema header against a hard-coded TEAM_CONFIGS whitelist; an unknown schema is rejected.

Things to notice:

  • This is why a new team is a code change, not just data — the whitelist is the SQL-injection barrier (Chapter 18 and the schema-safe-code how-to).
  • flex-v3-backend needs both schemas (it's the shared fan backend for Flex and Premium); the Flex frontend gets the Flex config, the Premium frontend gets the Premium one.
  • Use sandbox credentials (dsn: 'sandbox', siteName: 'integ3') — Chapter 27 explains why those four values are the prod/sandbox switch.

Checkpoint: you can explain why the same schema must be registered in multiple repos, and what the TEAM_CONFIGS whitelist protects against.

Step 4 — Find your workspace in Cortex

"Is it alive?"

Restart both backends — the team whitelist (TEAM_CONFIGS) is a compiled-in constant built from static imports, so a newly added config file is only picked up on process start (it's not a refreshable runtime cache). Then in Cortex Change workspace → your org → Flex → your Flex workspace. Both your Flex and Premium schemas appear under Flex.

Checkpoint: your client appears in the org picker and you can enter the workspace — the DB rows

  • code configs have met.

Step 5 — Stand up a sellable program

"Now actually sell something."

This is the full Cortex flow — and where the real-run gotchas live (the how-to's Step 4 callout spells them out):

  1. Events — Flex Events → Import → codes SS1–SS15Fetch from Ticketmaster → Import. They arrive as Drafts, often dated in the past (stale sandbox).
  2. Future-date each event while it's a Draft — the date locks once published.
  3. Create a venue (Venues & Maps) — name + map name; the map image is optional, because seats come from the TM manifest, not an uploaded map. Assign it to each event, then publish the events.
  4. Create the program (Build-Your-Own, seat-level) → add your published events → set a class name (Inventory Configuration) → Configure Pricing (non-zero) → Build Inventory (this pulls the seats from TM) → Publish.
  5. Buy a seat in your fan app at /<your-schema>/events_home — sandbox card 4444 3333 2222 1111, CVV 111, any future expiry, any US zip.

Checkpoint: a published program with built inventory exists, and you completed a sandbox purchase against your own schema.

What you now know

You can take a team from nothing to selling: two dashboard rows → a built schema → code configs that whitelist it → a Cortex-configured program → real seats pulled from the vendor. You've touched every layer — DB, both backends, both frontends, and the admin UI — and seen exactly where each one's responsibility starts and stops.

Next: now that you have a live sandbox, run Trace a Purchase against your own schema to connect this setup to the code that powers it.