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 (after modal token new once)
  • Endpoints: POST /normalize (called by worker hydrateUserImages/hydrateHubspotImages), POST /composite (called by the n8n Composite Images node), GET /health
  • Secrets: two Modal secrets, image-normalizer (carries FCR_NORMALIZER_TOKEN used by the worker) and image-normalizer-n8n (carries FCR_N8N_TOKEN used 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 to FCR4IE (or mirrored into fcr-dashboard as a studio/ subtree).
  • cathaldempsey Modal workspace/normalize + /composite run 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.

Ask the docsRAG over this site
Ask anything about the FCR Dashboard platform — architecture, BigQuery, the worker routes, billing rules, the LRC stack, scoring… Answers are grounded in this documentation, with source links.
How does the deal-brief refresh work? Which routes are Worker vs n8n? How is account health scored?