IRIDESC E UX · COMMAND
v31 · Program Primary Revision
INTERNALSTEP-BY-STEP

First-Time Cloudflare Setup — Every Click

This is the long version on purpose. Start with a clean deployment and follow every numbered action in order.

RESET FIRST — if you are restarting after a failed setup

R1

Do not delete persistent data blindly

Cloudflare Dashboard

A clean restart does not mean deleting D1, R2, your DNS zone, or the repaired Zero Trust organization. Those can contain persistent data or account-level configuration.

Expected: You know which resources contain real data and which were disposable setup attempts.
R2

Keep the current Zero Trust team domain

Zero Trust → Settings → Team name and domain

For this deployment the intended team domain is iridesceux.cloudflareaccess.com. Open https://iridesceux.cloudflareaccess.com in a private window. If Cloudflare shows a valid Access/App Launcher/Welcome page, keep the organization. Do not rename or delete it.

Expected: The team domain is recognized by Cloudflare.
STOP if: It still says “Unable to find your Access organization” — go directly to document 19 before rebuilding the app.
R3

Remove only the stale Command Access application if you are rebuilding Access

Zero Trust → Access controls → Applications

If an old Iridesceux Command application was created while the team domain was broken, delete that application only. Do not delete the entire Zero Trust organization.

Expected: No stale custom-hostname Access app remains.
R4

Preserve or inventory D1 and R2

Storage & Databases

If iridesceux-command and iridesceux-command-assets already exist, keep them unless you are absolutely certain they contain only disposable test data. The later steps show how to verify/rebind them instead of recreating them unnecessarily.

R5

Decide whether to keep or recreate the Command Pages project

Workers & Pages

If the existing Command *.pages.dev deployment loads correctly and Functions are deployed, you may keep the project. If you want a completely fresh Pages project, first note its project name, custom domain, bindings, and variables, then remove command.iridesceux.com from Custom domains before deleting the old Pages project.

R6

Remove stale manual DNS for command only if it conflicts

iridesceux.com → DNS → Records

Look specifically for a manually created command A/AAAA/CNAME that points somewhere other than the Pages project. Do not touch unrelated DNS records. When the domain is attached through Pages, Cloudflare can manage the correct record.

R7

Revoke temporary team-repair API tokens

Manage Account → API Tokens

If you created a temporary token only to repair auth_domain, revoke it now unless you still need document 19. A one-time repair credential should not remain active indefinitely.

R8

Start the numbered build from Step 1

This document

From this point forward, make one change at a time and verify the expected result before continuing.

Before touching Cloudflare

1

Make a clean working folder

Finder

Extract the full release ZIP into a normal folder. Do not run deployment from inside the ZIP viewer.

Expected: You can open command-app, public-site, hvn-site, and DOCUMENTATION as real folders.
2

Install/confirm Git

Terminal
git --version

If the command is missing, install Apple Command Line Tools when macOS prompts you.

Expected: A Git version prints.
3

Install/confirm Node and npm

Terminal
node --version
npm --version

Node/npm are needed for Wrangler and the Broadcast Agent.

Expected: Both commands print versions.
4

Decide your bootstrap email

Your inbox

Pick the exact email that will be your first Command Super Admin and that can receive Cloudflare OTP email. Write it down exactly; no aliases unless you intend to use that alias everywhere.

Expected: You control the mailbox and can receive mail.

A. Create the private GitHub repository

5

Create a PRIVATE repository

GitHub → New repository

Name it something like iridesceux-hvn. Set visibility to Private. If you are pushing an existing folder, do not initialize it with a README that will create an unrelated first commit.

Expected: The empty private repository exists.
6

Initialize Git in the extracted package

Terminal in the package root
cd "/path/to/Iridesceux-HVN-v20.6-Exhaustive-Documentation"
git init
git branch -M main
git status
Expected: Git reports the project files as untracked/ready to commit.
7

Check that secrets are not about to be committed

Same Terminal
find . -maxdepth 3 \( -name ".env" -o -name ".dev.vars" -o -name "wrangler.toml" \) -print

Review any results. Real secrets must not be committed. Example/template files are okay if they contain placeholders only.

Expected: No real production secret values are present in tracked files.
STOP if: You see an API token, password, private key, stream key, or other real credential in a source file.
8

Commit the monorepo

Same Terminal
git add .
git commit -m "Initial Iridesceux HVN deployment package"
Expected: A commit is created.
9

Attach the GitHub remote and push

Same Terminal
git remote add origin https://github.com/YOUR-OWNER/YOUR-REPO.git
git push -u origin main

If origin already exists, use git remote -v and correct it with git remote set-url origin ....

Expected: GitHub shows the real folders, not a ZIP file.

B. Create Command in Cloudflare Pages

10

Open Workers & Pages

Cloudflare Dashboard → Workers & Pages

Select Create / Create application and choose Pages with Git integration. Connect GitHub if Cloudflare asks.

Expected: Cloudflare can see the private repository.
11

Select the repository

Workers & Pages → Pages → Connect to Git

Choose the Iridesceux/HVN private repository and production branch main.

Expected: The build configuration screen opens.
12

Set the Command root directory

Build configuration

Open the advanced/root-directory control and enter exactly:

command-app
Expected: Cloudflare will run the Pages project from command-app.
13

Set the framework/build settings

Build configuration

Use:

Framework preset
None
Build command
exit 0
Build output directory
public

The code does not require a framework build. Cloudflare documents exit 0 as a valid no-op build command when not using a preset.

Expected: Root = command-app; output = public.
STOP if: You set output to ., repository root, or command-app/public while root is already command-app.
14

Deploy Command

Build configuration → Save and Deploy

Wait for the deployment to finish. Copy the generated *.pages.dev URL somewhere.

Expected: Deployment status is successful and the Pages URL opens.
15

Prove Pages Functions deployed

Open the Pages URL

Open https://YOUR-PROJECT.pages.dev/api/command/me.

At this point it may return a JSON error such as missing D1/authentication. That is okay. The key test is that it is a Function response — not your HTML homepage and not a Pages 404.

Expected: You get JSON from the API route.
STOP if: You get static HTML or 404; check root directory and that command-app/functions exists at the project root.

C. Create D1, load the schema, and bind it

16

Create the D1 database

Cloudflare → Storage & databases → D1

Select Create database. Recommended name:

iridesceux-command
Expected: The D1 database exists.
17

Log Wrangler into Cloudflare

Terminal
cd "/path/to/repo/command-app"
npx wrangler login

Approve the browser authorization using the same Cloudflare account that owns the project.

Expected: Wrangler reports successful login.
18

Load the entire schema into REMOTE D1

Terminal inside command-app
npx wrangler d1 execute iridesceux-command --remote --file=command-schema.sql
Expected: Wrangler reports the SQL file executed successfully.
STOP if: The command reports SQL errors. Fix those before binding/deploying.
19

Verify tables exist

Same Terminal
npx wrangler d1 execute iridesceux-command --remote --command="SELECT name FROM sqlite_schema WHERE type='table' ORDER BY name;"
Expected: A long list of tables appears.
20

Bind D1 to Command

Workers & Pages → Command project → Settings → Bindings → Add → D1 database

Set Variable name exactly:

COMMAND_DB

Select the iridesceux-command database.

Expected: The binding list shows COMMAND_DB.
21

Redeploy after adding the binding

Command project → Deployments

Trigger a new production deployment, or push a harmless commit. A binding added after a deployment does not retroactively change that already-running deployment.

Expected: The newest deployment is created after the binding.
22

Test D1 through Command

Open newest deployment

Open /setup-doctor.html and /api/command/me. Authentication may still fail, but D1 should no longer show “COMMAND_DB binding is not configured.”

Expected: No D1 binding 503.

D. Create R2 and bind uploads

23

Create the R2 bucket

Cloudflare → Storage & databases → R2

If Cloudflare asks you to enable R2 billing/subscription, complete that account setup first. Then create a bucket named:

iridesceux-command-assets

Keep it private; R2 buckets are private by default.

Expected: The bucket exists.
24

Bind R2 to Command

Workers & Pages → Command project → Settings → Bindings → Add → R2 bucket

Variable name must be exactly:

COMMAND_ASSETS

Select iridesceux-command-assets.

Expected: The binding list shows COMMAND_ASSETS.
25

Redeploy again

Command project → Deployments

Create a deployment after the R2 binding was added.

Expected: Newest deployment post-dates the binding.
26

Do not test uploads yet if Access is not complete

Command

The upload UI requires Command authentication. Continue to custom domain + Access first, then return to the R2 persistence test in Step 49.

E. Attach the Command custom domain BEFORE Access

27

Check for a conflicting manual DNS record

Cloudflare → iridesceux.com → DNS → Records

Search for a record whose name/hostname is command. If you previously created a manual A/AAAA/CNAME for Command and it is not the current Pages-managed record, remove the conflicting record before attaching the Pages custom domain.

Expected: There is no stale origin record for command.iridesceux.com.
STOP if: Do not touch unrelated apex/www/mail records.
28

Attach the domain from the Pages project

Workers & Pages → Command project → Custom domains → Set up a domain

Enter exactly:

command.iridesceux.com

Continue/activate. Because the zone is already in the same Cloudflare account, Pages should manage the required DNS record.

Expected: Custom domain progresses to Active.
STOP if: Do not manually point a CNAME at Pages without first associating the custom domain in the Pages UI; Cloudflare documents that this can cause a 522.
29

Wait for Active

Command project → Custom domains

Do not proceed while the domain says Pending/Verifying/Initializing.

Expected: command.iridesceux.com is Active.
30

Test the hostname before Access

Browser

Open https://command.iridesceux.com. It may be temporarily unprotected for this short test. Verify it resolves to Command and not a 522.

Expected: Command loads from the Pages project.
STOP if: If you get 522, return to Pages custom domain setup and DNS. Do not troubleshoot D1/Auth for a routing error.

F. Verify the Zero Trust team itself BEFORE protecting Command

31

Open Zero Trust

Cloudflare Dashboard → Zero Trust

If Cloudflare asks you to initialize a Zero Trust organization, complete the organization setup. The intended team domain for this deployment is:

iridesceux.cloudflareaccess.com
32

Confirm the team name/domain in Settings

Zero Trust → Settings → Team name and domain

Copy the exact current team domain from Cloudflare. For this deployment it should be:

iridesceux.cloudflareaccess.com

Do not confuse this with command.iridesceux.com. The first is the Access organization domain; the second is the protected application.

Expected: The dashboard shows the intended team domain.
33

Directly test the team domain

New private/incognito window

Open:

https://iridesceux.cloudflareaccess.com

A valid organization may show an App Launcher, login page, or “Welcome — enable App Launcher” message.

Expected: Cloudflare Access recognizes the organization.
STOP if: If it says Unable to find your Access organization, stop here and use document 19. Do not create/recreate the Command Access app until the team domain itself works.

G. Configure One-Time PIN

34

Open Identity providers

Zero Trust → Integrations → Identity providers

Check whether One-time PIN already exists.

35

Add One-time PIN if missing

Identity providers → Add new identity provider

Select One-time PIN and save. New Zero Trust organizations may use Cloudflare as the default provider; OTP is not necessarily added automatically.

Expected: One-time PIN appears in the identity-provider list.

H. Protect the raw Command pages.dev domain and previews

36

Enable the Pages Access policy

Workers & Pages → Command project → Settings

Find Enable access policy and enable it for the Command Pages project. Cloudflare documents this as the supported way to secure the project *.pages.dev address and preview deployments.

This matters because the package mirrors internal documentation under command-app/public/docs; protecting only command.iridesceux.com would otherwise leave the raw Pages hostname as an alternate path.

Expected: Cloudflare creates/manages an Access application or policy for the Pages project.
37

Verify both the project pages.dev URL and preview URLs are protected

Zero Trust → Access controls → Applications, then a fresh Incognito window

Follow Cloudflare's Pages procedure: manage the Pages-created Access application, ensure the non-wildcard project hostname is protected, then re-enable preview protection so both the main PROJECT.pages.dev and preview pattern *.PROJECT.pages.dev are covered. Configure the policies so only intended identities can enter; for this setup use One-Time PIN with the same exact bootstrap email while testing.

Then open the raw https://PROJECT.pages.dev URL in Incognito. You should see Access before Command.

Expected: The raw Pages hostname and previews cannot bypass Access.
STOP if: The raw Pages URL opens Command directly without Access — fix this before treating Command or its mirrored documentation as private.

I. Create the Command Access application for the custom hostname

38

Create a new Access application

Zero Trust → Access controls → Applications → Create new application

Select:

Self-hosted and private

Then choose:

Add public hostname
Expected: You are on the self-hosted application configuration screen.
39

Name the application

Application configuration
Iridesceux Command
40

Set the protected public hostname

Application configuration → Public hostname

Use:

Subdomain
command
Domain
iridesceux.com
Path
Leave blank

Blank path means protect the entire hostname.

Expected: Preview destination shows command.iridesceux.com.
41

Create the Allow policy

Access policies → Create new policy

Use:

Policy name
Command Admin Access
Action
Allow
Include selector
Emails
Value
Your exact bootstrap email

Do not use Include → Everyone. Do not use “Emails ending in” unless you deliberately want the whole domain allowed.

Expected: Only the exact intended email matches the policy.
42

Select One-Time PIN

Identity providers / Login methods

Select One-time PIN. If it is the only login method, instant authentication may be on or off; either can work. For troubleshooting, leaving it off gives you the normal Access login screen.

Expected: OTP is the enabled login method.
43

Set session duration

Application settings
24 hours

Cloudflare documents 24 hours as the default application session duration. This is reasonable for initial Command setup.

Expected: Session duration is 24 hours.
44

Leave private-network/clientless isolation settings alone

Additional settings

Do not enable Browser Isolation/clientless private-destination options. Command is a public-hostname self-hosted app, not a private-network destination. Leave custom CORS/cookie/block-page settings at defaults unless you have a separate requirement.

Expected: No clientless/private-destination-only setting is enabled.
45

Create/save the application

Bottom of Access application form

Save the application. If Cloudflare errors about clientless isolation/private destinations, go back to Additional settings and turn that feature off.

Expected: Iridesceux Command appears in the Access application list.

J. Get the AUD and configure Command JWT validation

46

Copy the Application Audience (AUD) Tag

Zero Trust → Access controls → Applications → Iridesceux Command → Configure / Additional settings

Find Application Audience (AUD) Tag. Copy the exact value. Treat it as configuration, not a password, but do not casually publish internal identifiers.

Expected: You have the current AUD for this exact Access application.
47

Set Command variables

Workers & Pages → Command project → Settings → Variables and Secrets

Add these as normal plaintext variables:

BOOTSTRAP_ADMIN_EMAIL=YOUR-EXACT-LOGIN-EMAIL
CF_ACCESS_TEAM_DOMAIN=https://iridesceux.cloudflareaccess.com
CF_ACCESS_AUD=PASTE_CURRENT_APPLICATION_AUD
COMMAND_REQUIRE_ACCESS_JWT=true

Keep COMMAND_ALLOW_HEADER_AUTH unset or false in production.

Expected: All four variables are present for the production environment.
48

Redeploy after variables change

Command project → Deployments

Trigger a new production deployment after changing the variables. Do not test an older deployment.

Expected: Newest deployment post-dates the variable changes.

K. First real login and bootstrap Super Admin

49

Start with a fresh Incognito window

Browser

Open https://command.iridesceux.com. You should hit Cloudflare Access before the Command app.

Expected: The Access login/OTP flow appears.
STOP if: Command opens directly without Access.
50

Request and enter a new OTP

Cloudflare Access

Enter the exact email allowed in the policy. Request the code. Use the newest code Cloudflare sends.

Expected: Cloudflare redirects you into Command.
51

Verify the backend identity

Same authenticated browser

Open:

https://command.iridesceux.com/api/command/me

The first successful login with the bootstrap email should create/recognize the Command user as Super Admin.

Expected: JSON contains your real email and role super_admin.
STOP if: It says Authentication required. — use document 13 section “401 after Access login.”
52

Run Setup Doctor

Command

Open:

https://command.iridesceux.com/setup-doctor.html

Core checks should identify Functions, D1, Access JWT, and R2 configuration. Optional workers/OBS can still be unconfigured.

Expected: Core setup is healthy.
53

Test R2 persistence now

Command → Assets or a harmless upload surface

Upload one small disposable image/file under the app upload limit, refresh the page, and verify the asset still exists. The generic Command asset route currently enforces a 25 MB limit; use your video/storage workflow for large program masters.

Expected: The upload survives refresh and can be read back.

L. Only after Command is healthy: create Iridesceux and HVN Pages projects

54

Create Iridesceux Pages project

Workers & Pages

Connect the same private Git repo. Root public-site, framework None, build exit 0, output public.

Expected: Iridesceux staging *.pages.dev URL loads.
55

Do not attach the production apex until launch rehearsal

Iridesceux project

Keep the production domain unchanged if the public site is still coming soon/offline. Use the Pages staging URL for testing.

56

Create HVN Pages project

Workers & Pages

Same repo. Root hvn-site, framework None, build exit 0, output public.

Expected: HVN staging URL loads and Functions routes exist.
57

Bind shared D1/R2 to HVN if required by the deployed functions

HVN project → Settings → Bindings

Use exact binding names COMMAND_DB and COMMAND_ASSETS where HVN Functions depend on the shared presentation/account/media state. Optional binding: HVN_ANALYTICS. Optional variable: HVN_REALTIME_URL.

Expected: HVN API routes return real data instead of binding errors.

What NOT to do during first setup

Optional — Automatic Dolby/HLS packager

This is not required for ordinary uploaded program playout. It is required for upload-once automatic Dolby Vision/Atmos HLS packaging.

  1. Finish D1/R2/Access setup first.
  2. Apply MIGRATIONS/v31-premium-media-automation.sql to an existing database after v26.
  3. Open media-packager/wrangler.jsonc and insert the same D1 database ID used by Command.
  4. From media-packager/, run npm install.
  5. Generate a token with openssl rand -hex 32.
  6. Run npx wrangler secret put PACKAGER_TOKEN and paste it.
  7. Run npx wrangler deploy.
  8. Copy the deployed Worker URL.
  9. Command Pages → Settings → Variables and Secrets: add MEDIA_PACKAGER_URL and secret MEDIA_PACKAGER_TOKEN.
  10. Redeploy Command and rerun Setup Doctor.