Applied Module 12 · AI-Powered Music Production Workflows

The Release Ops Command Center

What you'll learn

~35 min
  • Build a Node.js static site generator producing a multi-page command center
  • Understand the SSG pattern: data + templates = deployable HTML
  • Integrate outputs from Lessons 1-5 into a unified dashboard
  • Deploy the command center to Netlify, Vercel, or GitHub Pages

What you’re building

You’ve built five tools across this module. Asset engine. Campaign generator. YouTube episode builder. Analytics dashboard. Royalty reconciler. They all work. They all produce useful output. But right now, the output lives in five different folders, and every week you’re opening files in three different places to figure out what to do next.

You’re going to build one command center that pulls everything together. A static website — generated from your data files — that gives you a single place to see this week’s priorities, your campaign status, your revenue numbers, and your platform analytics. Not a live app with servers and databases. Just HTML files generated from your data, deployed for free, accessible from your phone or laptop anywhere.

💬This is for you, not your fans

This isn’t a fan-facing website. It’s your private operations dashboard. Think of it like a cockpit: all the instruments in one place so you can make decisions without switching between five different tools. You can password-protect it or just keep the URL private. Nobody needs to see this except you (and maybe your manager, if you have one).


How the pieces connect

Here’s what you built in each lesson and what data flows into the command center:

LessonToolOutput the command center uses
L1Release Asset EngineAsset file paths (generated artwork)
L2Campaign Generatorcampaign.json (captions, calendar, EPK status)
L3Episode BuilderEpisode metadata (next YouTube publish date)
L4Control Roomanalytics.csv (Spotify/Shopify data)
L5Royalty Reconcilerroyalties.csv (revenue data, discrepancy flags)

The command center reads from a release-data/ directory. You drop your data files there. One command generates the whole site.

Software pattern: Static Site Generator (SSG)

Data files + templates = a deployable website. That’s it. Astro (this very training site), Hugo, Jekyll, Eleventy — they all work this way. You’re building a tiny version of the same pattern. No server runs your site. No database stores your data. A build script reads files and writes HTML. You deploy the HTML. Done.


The prompt

Start your AI CLI tool and paste this prompt:

Build a Node.js static site generator that produces a multi-page command center
for an independent music artist. The tool reads data files from a release-data/
directory and generates a deployable static site.
PROJECT STRUCTURE:
command-center/
package.json
src/
build.js (main build script, entry point)
data-loader.js (reads and validates all data files)
templates/
layout.hbs (shared HTML layout with nav and footer)
index.hbs (This Week's Actions page)
campaign.hbs (Campaign Status page)
revenue.hbs (Revenue Dashboard page)
analytics.hbs (Platform Analytics page)
static/
style.css (dark theme stylesheet)
release-data/ (input data directory -- sample data included)
campaign.json
analytics.csv
royalties.csv
release-info.json (basic release metadata)
dist/ (generated output -- the deployable site)
REQUIREMENTS:
1. BUILD SCRIPT (src/build.js)
- Usage: node src/build.js
- Read all data files from release-data/
- Compile Handlebars templates
- Generate HTML pages into dist/
- Copy static/ assets into dist/
- Print build summary: pages generated, data files loaded, any warnings
2. DATA LOADER (src/data-loader.js)
- Load release-info.json: { artist, currentRelease, releaseDate, nextActions }
- Load campaign.json: { posts (array of { platform, date, caption, status }),
epkUrl, hashtags }
- Parse analytics.csv: columns for date, platform, metric, value
(streams, listeners, followers, merch_orders, merch_revenue)
- Parse royalties.csv: columns for track, platform, streams, revenue,
period, discrepancy_flag (boolean), discrepancy_note
- If a file is missing, log a warning and use empty defaults (the site
should still build with partial data)
3. PAGES:
a. index.html — "THIS WEEK'S ACTIONS"
- Top 5 action items generated from the data:
* Next scheduled social post from campaign.json (with date and platform)
* Any royalty discrepancies that need follow-up
* Revenue milestone alerts (e.g., "JADED crossed $500 total revenue")
* Upcoming release date countdown
* Analytics highlight (e.g., "Spotify listeners up 12% this week")
- Each action item: icon indicator, description, priority level
(urgent/normal/info)
- Current release info card at the top
b. campaign.html — "CAMPAIGN STATUS"
- Posting calendar: table with date, platform, caption preview, status
(scheduled/posted/skipped)
- Caption queue: next 5 unposted captions with full text
- EPK link if available
- Campaign completion percentage (posted / total posts)
c. revenue.html — "REVENUE DASHBOARD"
- Total revenue summary card (all platforms combined)
- Revenue breakdown by platform (table: platform, streams, revenue,
avg per-stream rate)
- Per-track revenue table: track name, total streams, total revenue,
best platform
- Discrepancy flags section: highlighted rows for any track where
discrepancy_flag is true, showing the discrepancy_note
- All currency values formatted with $ and 2 decimal places
d. analytics.html — "PLATFORM ANALYTICS"
- Spotify section: total streams, total listeners, follower count
- Merch section: total orders, total revenue, best-selling item
- Week-over-week comparison if enough data points exist
- Geographic summary if territory data is available
4. DESIGN
- Dark theme: background #09090b, cards #141414, borders #262626,
text #e5e5e5
- Accent color: #f97316 (orange) for highlights and active nav
- Shared navigation bar across all pages with links to each section
- Navigation shows current page as active (orange underline)
- Responsive: single column on mobile, 2-column grid on desktop
- Font: system sans-serif stack (-apple-system, BlinkMacSystemFont,
Segoe UI, sans-serif)
- Site title: "COMMAND CENTER" with artist name below
- Footer: "Built with AI CLI tools | Data stays local"
5. SAMPLE DATA
- Include realistic sample data in release-data/:
- release-info.json: artist "moodmixformat", current release "JADED",
release date "2026-03-14"
- campaign.json: 14 posts across Instagram, TikTok, YouTube over 2 weeks,
mix of "posted" and "scheduled" statuses
- analytics.csv: 30 days of Spotify streams (trending up), Shopify orders,
listener counts by city
- royalties.csv: 6 tracks across 4 platforms, Q4 2025 data, with 2 rows
flagged as discrepancies
6. DEPLOYMENT
- Include a netlify.toml in the project root:
[build]
publish = "dist"
command = "node src/build.js"
- Include a vercel.json with similar config
- Add a "deploy:github-pages" npm script that builds and copies dist/ to
docs/ (for GitHub Pages)
DEPENDENCIES: handlebars, csv-parser, chalk (for build output coloring)

What you get

After your AI CLI tool finishes, you’ll have the project:

command-center/
package.json
netlify.toml
vercel.json
src/
build.js
data-loader.js
templates/
layout.hbs
index.hbs
campaign.hbs
revenue.hbs
analytics.hbs
static/
style.css
release-data/
release-info.json
campaign.json
analytics.csv
royalties.csv

Set it up and build

Terminal window
cd command-center
npm install
node src/build.js

You should see output like:

Loading data files...
✓ release-info.json (1 release)
✓ campaign.json (14 posts)
✓ analytics.csv (127 rows)
✓ royalties.csv (24 rows, 2 discrepancies)
Building pages...
✓ dist/index.html — This Week's Actions
✓ dist/campaign.html — Campaign Status
✓ dist/revenue.html — Revenue Dashboard
✓ dist/analytics.html — Platform Analytics
✓ dist/style.css
Build complete: 4 pages generated

Open dist/index.html in your browser. Click through all four pages. Check:

  • Does the navigation work between pages?
  • Does “This Week’s Actions” show relevant priorities from the sample data?
  • Does the revenue page show discrepancy flags?
  • Is the dark theme applied consistently?
💡Live reload during development

While tweaking templates, you can add a watch mode: "If I ask you to 'add a watch mode', add a file watcher that rebuilds when any template or data file changes. Use fs.watch or chokidar." This makes it easy to iterate on the design without rerunning the build manually.


A worked example: building for a new single

Here’s a real scenario. You’re releasing “JADED” on March 14. Your data:

  1. release-info.json — You fill in the track name, release date, and your top priorities for the week
  2. campaign.json — You already generated this with the Campaign Generator (Lesson 2). Copy it into release-data/
  3. analytics.csv — You exported this from your Control Room (Lesson 4) or directly from Spotify for Artists
  4. royalties.csv — You generated this with the Royalty Reconciler (Lesson 5)

Drop all four files into release-data/, run the build, and open the site. Your “This Week’s Actions” page might show:

  • URGENT: Post Instagram teaser caption (scheduled for tomorrow, 6pm ET)
  • URGENT: Follow up on MOOD’s Apple Music royalty discrepancy (-18% streams)
  • NORMAL: Release day is in 4 days — EPK is ready, check all platform links
  • INFO: Spotify listeners up 8% this week (52,400 → 56,590)
  • INFO: KICK IT W/U crossed $1,000 total revenue this quarter

That’s your week in one glance. No digging through five different folders.


Deploying your command center

The generated site is just HTML, CSS, and nothing else. No server needed. Three free options:

Netlify

Terminal window
# Install Netlify CLI (one time)
npm install -g netlify-cli
# Deploy
cd command-center
netlify deploy --prod --dir=dist

Vercel

Terminal window
# Install Vercel CLI (one time)
npm install -g vercel
# Deploy
cd command-center
vercel --prod

GitHub Pages

Terminal window
# Build and copy to docs/
npm run deploy:github-pages
# Commit and push
git add docs/
git commit -m "Update command center"
git push

Then enable GitHub Pages in your repo settings, pointing to the docs/ folder.

🔍Why a static site instead of a 'real' app

You might be wondering: why not build a React app with a database? Or use a service like Notion or Airtable?

A static site wins for this use case because:

  • No server costs: HTML files served from a CDN cost nothing. Netlify, Vercel, and GitHub Pages are all free for this.
  • No maintenance: There’s no database to back up, no server to keep running, no dependencies to update continuously. The site is just files.
  • Fast: Static HTML loads instantly. No JavaScript frameworks, no API calls, no loading spinners.
  • Private: Your data is baked into the HTML at build time. Nobody can query your database because there is no database. The built site contains only the data you chose to include.
  • Portable: You can open the HTML files directly from your filesystem without deploying anywhere. It works offline.

The tradeoff: you have to rebuild when data changes. For a weekly check-in dashboard, that’s running one command before you look at it. Perfectly fine.

All three platforms are free

Netlify, Vercel, and GitHub Pages all have free tiers that are more than enough for a private dashboard. You’re not going to hit any limits with a 4-page static site. Pick whichever one feels simplest — Netlify’s drag-and-drop deployment is the easiest if you’ve never deployed anything before.


If something is off

ProblemFollow-up prompt
Navigation links are broken between pagesThe nav links use absolute paths (/campaign.html) but the site is deployed to a subdirectory. Change all nav links to relative paths (campaign.html, revenue.html, etc.) so they work whether the site is at the root or in a subdirectory.
Missing data file crashes the buildThe build crashes when analytics.csv is missing. Make the data loader resilient: if a file doesn't exist, log a warning and use an empty default. The site should still build with partial data -- just show "No data available" in sections that need the missing file.
The CSS isn’t applied to generated pagesThe pages are unstyled. Make sure build.js copies static/style.css to dist/style.css, and the layout template links to it with a relative path: <link rel="stylesheet" href="style.css">. Check that the copy step happens after the dist directory is created.
Handlebars template has raw curly bracesThe template is rendering raw Handlebars syntax like {{revenue}} instead of actual values. Make sure build.js compiles each template with Handlebars.compile() and passes the data context when calling the compiled function. Check that the template files use .hbs extension and are read as strings.

Customize it

Add automatic rebuild on data change

Add a "watch" npm script that uses chokidar to watch the release-data/ directory
and templates/ directory. When any file changes, automatically rebuild the site.
Print a timestamp and which file triggered the rebuild. This way I can update a
CSV, save it, and the site refreshes automatically.

Add an email digest

Add a --digest flag to build.js that generates a plain-text email summary in
dist/digest.txt. Include: the top 5 action items from the index page, total
revenue this period, any discrepancy flags, and the next 3 scheduled posts.
Format it as a clean email I could send to myself or my manager every Monday.
Keep it under 500 words.

Add social media preview images

Add Open Graph meta tags to each page so they have proper previews when shared.
Set og:title to the page name, og:description to a summary, and og:image to a
generated preview image. For the preview image, create a simple 1200x630 PNG
with the page title and a key metric on a dark background with the orange accent.
Use the sharp npm package for image generation.

Add historical release comparison

Add support for multiple releases. Instead of one release-data/ directory,
support release-data/jaded/, release-data/kick-it-wu/, etc. Add a releases.html
page that compares metrics across releases: which release had the most first-week
streams, best revenue, highest merch conversion. Show a comparison table and
highlight your best-performing release.

🔧

When Things Go Wrong

Use the Symptom → Evidence → Request pattern: describe what you see, paste the error, then ask for a fix.

Symptom
The build completes but dist/ is empty
Evidence
Running node src/build.js prints 'Build complete' but the dist/ directory has no files in it
What to ask the AI
"The build script isn't writing files to dist/. Check that it creates the dist/ directory with fs.mkdirSync('dist', { recursive: true }) before writing. Make sure fs.writeFileSync is called with the correct path (path.join('dist', 'index.html'), not just 'index.html'). Add console.log for each file written."
Symptom
The action items are all 'No data available'
Evidence
The index page shows 5 action items but they all say 'No data available' even though my data files are in release-data/
What to ask the AI
"The data loader is failing silently. Add error logging to data-loader.js so it prints what it's reading and any parse errors. Check that the file paths are relative to the project root (release-data/campaign.json), not relative to src/. Use path.resolve(__dirname, '..', 'release-data') to build correct paths."
Symptom
The Netlify deploy fails with 'build command failed'
Evidence
Netlify shows 'Build failed: command "node src/build.js" exited with code 1'
What to ask the AI
"The build script works locally but fails on Netlify. Common causes: (1) node_modules not installed -- add a 'npm install' step before the build, or make sure package.json has all dependencies. (2) Node version mismatch -- add a .node-version file with '18' or set NODE_VERSION=18 in Netlify env vars. (3) Path issues -- Netlify runs from the repo root, so paths must be relative to the project root."
Symptom
The campaign page shows dates in the wrong format
Evidence
Campaign dates show as '2026-03-14T00:00:00.000Z' instead of 'March 14, 2026'
What to ask the AI
"The dates are displaying as raw ISO strings. Add a Handlebars helper for date formatting: Handlebars.registerHelper('formatDate', function(dateStr) { return new Date(dateStr).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); }). Use it in templates as {{formatDate post.date}}."
Symptom
Relative links break when opening files directly from filesystem
Evidence
Clicking 'Revenue' in the nav while viewing dist/index.html from file:// goes to file:///revenue.html instead of the correct path
What to ask the AI
"The nav links need to be sibling-relative. Use href="revenue.html" not href="/revenue.html". The leading slash causes the browser to go to the filesystem root when opened via file://. All internal links should be relative with no leading slash."

The story so far

Over six lessons, you’ve built the operations backbone:

  1. Release Asset Engine (Lesson 1) — one cover image in, six platform-sized assets out
  2. Campaign Generator (Lesson 2) — one metadata file in, captions, hashtags, calendar, and an EPK out
  3. Episode Builder (Lesson 3) — one notes file in, all YouTube publishing metadata out
  4. Control Room (Lesson 4) — CSV exports in, geographic and business intelligence out
  5. Royalty Reconciler (Lesson 5) — distributor CSVs in, discrepancy flags and revenue report out
  6. Command Center (Lesson 6) — all of the above in, one weekly action-plan dashboard out

These tools chain together. The campaign generator’s output feeds the command center’s campaign page. The reconciler’s flags appear on the revenue dashboard. The control room’s analytics populate the analytics page. The command center is the hub that ties every tool into a single view.

Next up: building your signature visualizer content — the tape deck aesthetic that makes your brand recognizable across every platform.


Try it yourself

  1. Open your AI CLI tool in an empty folder.
  2. Paste the main prompt.
  3. Run npm install and then node src/build.js.
  4. Open dist/index.html and click through all four pages.
  5. Replace the sample data with real output from your Lessons 1-5 tools.
  6. Deploy to Netlify, Vercel, or GitHub Pages.

Key takeaways

  • Static site generators are data + templates — no server, no database, no complexity. Read files, render templates, write HTML. That’s the entire pattern.
  • Free deployment is real — Netlify, Vercel, and GitHub Pages all host static sites for free. Your command center costs nothing to run.
  • Integration is the capstone skill — building individual tools is valuable, but connecting them into a unified workflow is where the real power is. The command center doesn’t do anything new; it orchestrates what you already built.
  • Private dashboards beat scattered files — one URL with all your release data is better than five folders you have to remember to check.
  • Rebuild, don’t maintain — when data changes, rebuild the site. There’s no state to manage, no cache to invalidate, no database to migrate. Just run the build and deploy.

KNOWLEDGE CHECK

Your command center works locally but you want to deploy it. You choose Netlify. What does Netlify actually serve to visitors?


What’s next

The operations side is locked in. Next lesson: you build your signature audio visualizer — the tape deck aesthetic that turns every track into content for Reels, Shorts, and TikTok.