Repo Layout & Deploy Targets
Where the code physically lives, where each piece is deployed, and which accounts own what.
The platform spans two GitHub repos and four deploy surfaces, and the source repo is not always the same as the account that hosts the deploy. This page maps it out so the question "where do I edit X and what does deploying it actually touch?" has a single answer.
TL;DR
Roam (ai-advisor, hosted by Roam HQ Inc.)
▲
│ webhook
│
┌─── fcr-dashboard ── worker ──► fcr-dashboard-api.fcrmedia.workers.dev
│ (FCR4IE/DASHBOARD) (FCR Cloudflare)
│ │
│ ├── docs/ + scripts/build-docs-site.mjs ──► fcr-dashboard-docs.pages.dev
│ │ (FCR Cloudflare)
│ │
│ └── services/image-normalizer/ ──► …--fcr-image-normalizer-fastapi-app.modal.run
│ (cathaldempsey Modal workspace)
│
└─── workflowlogo-repo ── studio/ ──► creator-studio-738.pages.dev
(DCathal/workflowlogo) (FCR Cloudflare)
│
└── workflows/imagegen.json ──► Creator — Image Gen
(source-of-truth) (fcrmedia n8n)
Two repos. Source in either FCR-owned or personal GitHub. Deploys hit FCR Cloudflare, fcrmedia n8n, and a personal Modal workspace.
The two GitHub repos
fcr-dashboard — the FCR-owned monorepo
- Remote:
github.com/FCR4IE/DASHBOARD - Local clone:
~/fcr-dashboard/ - Owner: FCR org
| Subtree | Deploys to | Deploy command |
|---|---|---|
worker/ |
api.fcrinsights.ie (custom domain) + fcr-dashboard-api.fcrmedia.workers.dev + .cathaldempsey.workers.dev (dev mirror) |
scripts/ship.sh (auto) or scripts/deploy-worker.sh |
docs/ + docs-site/ (gitignored build) |
fcr-dashboard-docs.pages.dev (FCR CF Pages project fcr-dashboard-docs) |
scripts/ship.sh (auto-detects docs changes) or scripts/deploy-docs.sh |
services/image-normalizer/normalize.py |
Modal app fcr-image-normalizer (workspace cathaldempsey) |
modal deploy services/image-normalizer/normalize.py |
.claude/skills/ + .agents/skills/ |
the slash-command catalogue (rendered into the docs site at build time) | — (consumed by build-docs-site.mjs) |
scripts/ship.sh |
the canonical deploy orchestrator — routes worker + docs + reindex by what's changed since the last tag | — |
dashboard.html + assets/ |
fcrinsights.ie (apex) + fcr-dashboard-ui.pages.dev (FCR CF Pages project fcr-dashboard-ui, manual deploy — NOT GitHub-connected) |
npm run deploy (build + wrangler pages deploy dist --project-name=fcr-dashboard-ui --branch=production) |
Anything that calls out to BQ / HubSpot / Teamwork / Ahrefs / SerpAPI / GBP / GA4 / Search Console / iovox / GMC lives in worker/src/handlers/. The advisor is worker/src/handlers/ai-advisor.js.
workflowlogo-repo — Studio + Creator n8n workflows
- Remote:
github.com/DCathal/workflowlogo - Local clone:
~/workflowlogo-repo/ - Owner: personal GitHub (Cathal). Not under FCR4IE. See Ownership gaps worth closing.
| File | Deploys to | Deploy command |
|---|---|---|
studio/index.html |
creator-studio-738.pages.dev (FCR CF Pages project creator-studio) |
wrangler pages deploy studio --project-name creator-studio with CF_API_TOKEN_FCR |
workflows/imagegen.json |
n8n workflow Creator — Image Gen (id K5OJSy8uI31UwTKl) on fcrmedia.app.n8n.cloud |
n8n REST PUT /api/v1/workflows/:id with N8N_API_KEY (surgical), or paste into the n8n UI |
MIGRATION_GUIDE.md |
— | reference for moving Creator workflows between n8n instances |
Agents.md |
— | agent-context doc for Studio |
creator-workflow-restructure — local working dir (not a git repo)
- Path:
~/creator-workflow-restructure/ - Migration scripts, backup JSONs of the Creator router/agent/pack-resolver/delivery workflows, and
TODO.md(open bugs noted during the migration sprint, e.g./edit-/remix-/reframe from non-reply context). - Not version-controlled. These are scratch files; the workflow JSONs that are source-of-truth live in
workflowlogo-repo/workflows/.
The deploy surfaces
1. Cloudflare Worker — fcr-dashboard-api
| FCR (prod) | CD (dev mirror) | |
|---|---|---|
| URL | fcr-dashboard-api.fcrmedia.workers.dev |
fcr-dashboard-api.cathaldempsey.workers.dev |
| CF Account | FCR Media Ltd (0481b38f86c96053c528ec08d7d7dddc) |
cathaldempsey personal (1ceb8928d441467855ece30aa22f8283) |
| Wrangler env | --env fcr |
--env="" (top-level block) |
| API token | CF_API_TOKEN_FCR in .env.local |
CF_API_TOKEN_CD in .env.local |
| Where Roam + HubSpot card call | ✅ | ❌ (dev mirror only — never wired to real surfaces) |
Both env blocks share the same worker/ source. scripts/deploy-worker.sh deploys to both, gates on a clean worker/ git state, and writes a deploy/worker/<timestamp>-<sha> tag pushed to origin. scripts/ship.sh is the recommended entry point — it also routes docs + reindex.
2. Cloudflare Pages — three projects, all on the FCR account
| Project | Domain | Source | Deploy |
|---|---|---|---|
fcr-dashboard-ui |
fcr-dashboard-ui.pages.dev |
fcr-dashboard/dashboard.html + assets |
auto on push to main |
fcr-dashboard-docs |
fcr-dashboard-docs.pages.dev |
fcr-dashboard/docs/** (+ skill SKILL.md + build-docs-site.mjs) → built into docs-site/ (gitignored) |
scripts/deploy-docs.sh (or ship.sh) — builds, uploads, reindexes Vectorize, tags deploy/docs/... |
creator-studio |
creator-studio-738.pages.dev |
workflowlogo-repo/studio/index.html |
wrangler pages deploy studio --project-name creator-studio (manual; no git auto-deploy) |
The CF account holds all three Pages projects, but the project sources live in different git repos.
3. n8n — fcrmedia.app.n8n.cloud
55+ workflows. The ones in the Creator stack (per the Creator/Studio migration memory):
| Workflow | id | Source-of-truth |
|---|---|---|
| Creator (router) | 6tHvygC2CupKlVyy |
— (n8n is the source) |
| Creator — Agent | V70HT8Od6meZnHEb |
— |
| Creator — Pack Resolver | LyhB6IKzqGpllR07 |
— |
| Creator — Image Gen | K5OJSy8uI31UwTKl |
workflowlogo-repo/workflows/imagegen.json (the only one with a committed JSON source) |
| Creator — Delivery | wTMr3YZ1YEuRd8rH |
— |
| Creator — Roam Link | Hs0Klsc5Dr1ULVfj |
— |
| Creator — Yext Gallery | 9r168h632Cw0M9HL |
— |
API token (N8N_API_KEY in .env.local) authorises surgical PUT /api/v1/workflows/:id edits. See docs/n8n-workflows.md for the broader workflow inventory.
4. Modal — fcr-image-normalizer
- URL:
https://cathaldempsey--fcr-image-normalizer-fastapi-app.modal.run - Modal workspace:
cathaldempsey(personal — see Ownership gaps) - Source:
fcr-dashboard/services/image-normalizer/normalize.py - Deploy:
modal deploy services/image-normalizer/normalize.py(aftermodal token newonce) - Endpoints:
POST /normalize(called by workerhydrateUserImages/hydrateHubspotImages),POST /composite(called by the n8nComposite Imagesnode),GET /health - Secrets: two Modal secrets,
image-normalizer(carriesFCR_NORMALIZER_TOKENused by the worker) andimage-normalizer-n8n(carriesFCR_N8N_TOKENused by n8n). Either authenticates either endpoint — the split is rotation-isolation.
Cross-repo dependencies (who calls whom)
roam advisor HubSpot card iframe
│ │
└─────────────► dashboard-ai-advisor (worker)
│
┌───────────────┼───────────────────────┐
▼ ▼ ▼
BQ / HubSpot / open_studio tool generate_image
Teamwork / etc. ─── JWT link ──► tool
creator-studio-738 │
(Studio app) ▼
│ creator-image-gen gateway (worker)
│ │
│ ▼
└───── HTTP POST ──► fcrmedia n8n
/webhook/Creator700
│
▼
Creator router → Image Gen → Composite Images
│
▼
Modal /composite
▲
│
└── Modal /normalize ◄── worker hydrateUserImages
(HEIC/AVIF fallback)
Practical: Studio is the only piece in the personal GitHub repo. Everything else (worker, docs, Modal source, dashboard UI) is in FCR4IE/DASHBOARD. The n8n workflows are in n8n itself; only Image Gen has a JSON twin in workflowlogo-repo/workflows/.
Where the deploy lever lives for each change
| You want to change… | Edit in… | Deploy with… |
|---|---|---|
| The advisor's tools, prompt, hydrate logic, etc. | fcr-dashboard/worker/src/handlers/ai-advisor.js |
scripts/ship.sh |
| A worker route or composite endpoint | fcr-dashboard/worker/src/handlers/<file>.js |
scripts/ship.sh |
| A docs page (or add a new one) | fcr-dashboard/docs/<page>.md + nav entry in scripts/build-docs-site.mjs |
scripts/ship.sh (auto-routes to docs) |
| A skill's behaviour or args | fcr-dashboard/.claude/skills/<name>/SKILL.md |
git commit + scripts/ship.sh (docs page regenerates) |
| The dashboard UI | fcr-dashboard/dashboard.html (+ assets) |
git push (Pages auto-deploys) |
| The Studio frontend | workflowlogo-repo/studio/index.html |
wrangler pages deploy studio --project-name creator-studio (FCR CF) |
| The Creator — Image Gen workflow | workflowlogo-repo/workflows/imagegen.json AND live n8n (PUT or UI) |
n8n REST PUT or paste in UI |
Modal /normalize or /composite |
fcr-dashboard/services/image-normalizer/normalize.py |
modal deploy …/normalize.py |
A Modal secret (e.g. rotate FCR_NORMALIZER_TOKEN) |
— | modal secret create image-normalizer FCR_NORMALIZER_TOKEN=… --force + corresponding wrangler secret put IMAGE_NORMALIZER_TOKEN on both worker envs |
For the worker-secret rotation step: wrangler secret put --env="" doesn't work for the CD/dev env — omit --env entirely and pass CLOUDFLARE_ACCOUNT_ID=1ceb8928… explicitly. --env fcr is normal.
Ownership gaps worth closing
A few pieces of the platform live in personal accounts, not under FCR org control. Production touches FCR Cloudflare + fcrmedia n8n in every case, but the source / Modal compute is personal. If the maintainer changes, these would need transfer to remain accessible:
github.com/DCathal/workflowlogo— Studio frontend + Image Gen workflow JSON. Should be transferred toFCR4IE(or mirrored intofcr-dashboardas astudio/subtree).cathaldempseyModal workspace —/normalize+/compositerun on a personal Modal account. Should be moved to an FCR Modal org workspace if one is created.
Neither blocks day-to-day work; both are organisational hygiene for handover/continuity.
Why "split" repos at all?
Studio was a personal experiment (Creator/Studio migration onto the FCR stack, 2026-05-25) that proved out and moved its deploy targets (CF Pages, n8n, R2) onto the FCR stack — but the source repo didn't migrate with the deploys. Same for Modal: chosen for time-to-ship (scale-to-zero, single-file deploy), but the workspace is personal because that's whose Modal account was set up.
The deploy outcome is correct (everything runs on FCR infrastructure that the team controls). The source ownership is the residual cleanup.
FCR Dashboard documentation · generated from docs/ · keep counts verified, not guessed.