You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This document defines the content publishing workflow for interledger.org, using Strapi CMS, Git branches, and Netlify deployments.
Architecture Overview
flowchart
subgraph gcp["☁️ GCP VM"]
direction TB
strapi[(Strapi CMS)]
gitclone[("Git Clone<br/>(staging)")]
strapi -->|"writes MDX"| gitclone
end
subgraph github["📦 GitHub Repository"]
direction TB
staging["staging branch"]
main["main branch"]
end
subgraph netlify["🚀 Netlify"]
direction TB
preview["Preview Site"]
production["Production Site"]
end
editor["👤 Content Editor"]
dev["👨💻 Developer"]
feature["Feature Branch"]
editor ==>|"Publish"| strapi
dev ==>|"Code PR"| feature
gitclone ==>|"Push via<br/>lifecycle hooks"| staging
feature ==>|"PR"| staging
staging ==>|"Auto-build"| preview
staging -->|"PR (approved)"| main
main ==>|"Auto-build"| production
gitclone -.-|"Sync after<br/>PR merge"| strapi
classDef gcpStyle fill:#4285f4,stroke:#1967d2,color:#fff
classDef githubStyle fill:#24292e,stroke:#000,color:#fff
classDef netlifyStyle fill:#00c7b7,stroke:#008577,color:#fff
classDef userStyle fill:#ff6b6b,stroke:#d63031,color:#fff
classDef branchStyle fill:#6c5ce7,stroke:#5f3dc4,color:#fff
class strapi,gitclone gcpStyle
class staging,main,feature githubStyle
class preview,production netlifyStyle
class editor,dev userStyle
Loading
Workflow Summary
Content editors publish changes in Strapi
Strapi lifecycle hooks generate MDX and commit to staging branch
Netlify automatically builds and deploys staging preview
Product owner reviews staging content
Approved changes are promoted to main via pull request
Netlify automatically deploys main to production
Branch Strategy
staging - Preview environment for content review
main - Production environment (always reflects live site)
All content changes flow through staging → main via pull request.
User Stories
Story 1: Content Editor Publishes Changes
As a content editor I want to publish content changes in Strapi So that they are automatically committed to the staging branch and available for review
Acceptance Criteria:
When I publish content in Strapi, lifecycle hooks generate MDX files
The generated MDX is committed and pushed to the staging branch
The commit message clearly indicates what content was added/updated/deleted
Story 2: Automatic Staging Preview Build
As a content editor or reviewer I want Netlify to automatically build and deploy the staging branch So that I can preview my changes before they go to production
Acceptance Criteria:
Netlify detects commits to staging branch
A new preview build is triggered automatically
The staging preview URL is accessible for review
Build failures are reported clearly
Story 3: Product Owner Reviews Staging Content
As a product owner I want to review content on the staging preview site So that I can approve or reject changes before production
Acceptance Criteria:
Staging preview URL displays the latest content from staging branch
I can view all pages, blog posts, and content changes
The preview accurately represents what will appear in production
I can provide feedback to content editors if changes are needed
Story 4: Promote Staging to Production via PR
As a product owner I want to promote approved staging content to production via a pull request So that changes are traceable and reviewed before going live
Acceptance Criteria:
I create a PR from staging to main
PR shows all content changes (MDX files) clearly
PR can be reviewed and approved by authorized team members
Merging the PR triggers production deployment
main branch always reflects production content
Story 5: Production Deployment
As a the system I want to automatically deploy main branch to production So that approved content goes live
Acceptance Criteria:
Netlify detects commits/merges to main branch
Production build is triggered automatically
Production site is updated with new content
Build artifacts are stored for potential rollback
Deployment status is visible to the team
Story 6: Rollback Production Deployment
As a product owner or site administrator I want to rollback to a previous production deployment So that I can quickly recover from issues
Acceptance Criteria:
Netlify administrators can rollback using Netlify deploy history
Rollback is instant by switching to a previously built deploy
Rollback does not rebuild assets
GitHub remains unchanged by Netlify rollback
Any new merge into main will redeploy and override the rolled-back state
Team is notified when a rollback occurs
Story 7: Preview Unpublished Content
As a content editor I want to preview draft content before publishing So that I can verify it looks correct without triggering builds
Acceptance Criteria:
I can use the preview page URL with a document ID parameter
Preview page fetches draft content directly from Strapi (SSR)
Preview does not require publishing or triggering builds
Preview accurately renders the content as it will appear when published
Story 7a: Host SSR Preview Service on the Strapi VM
As a the system I want to run an Astro SSR preview server on the Strapi VM So that content editors have a fast, build-free preview experience
Acceptance Criteria:
The SSR preview server runs alongside Strapi on the VM
The preview server is reachable at a dedicated URL (e.g. preview.<domain>) and uses HTTPS
Strapi CLIENT_URL points to the preview server URL
Preview routes use export const prerender = false
The preview server can fetch draft content using STRAPI_PREVIEW_TOKEN
Story 7b: Preview Button Integrates with Strapi Admin
As a content editor I want a working Preview button in Strapi that opens the SSR preview So that I can review drafts before publishing
Acceptance Criteria:
The Preview button is disabled until the draft is saved
Strapi uses config/admin.ts preview handler to build the preview URL
The preview URL uses documentId for lookup
Preview works for each configured content type
Preview remains separate from the MDX build pipeline
Story 7c: Maintain Preview Block Rendering
As a developer I want preview block adapters to render Strapi dynamic zones correctly So that previews match the published site as closely as possible
Acceptance Criteria:
Each Strapi block type maps to a block component in src/components/blocks/
If data transformation is required, a block adapter converts Strapi data to presentational props
Presentational components can be reused by both preview and published content
New content types include preview support before release
Story 8: Developer Makes Code Changes
As a developer I want to make code changes (Astro components, layouts, styles, CMS) to the staging branch first So that changes can be reviewed and tested before going to production
Acceptance Criteria:
I create a feature branch from staging (not main)
I commit my code changes to the feature branch
I create a PR targeting staging (not main)
PR is reviewed and approved before merging
Changes are tested on staging preview before promotion to production
Direct commits to main are blocked by branch protection rules
CMS code changes (in cms/ folder) trigger Strapi deployment to VM
Story 9: Deploy CMS Code Changes to Strapi VM
As a the system I want to automatically deploy CMS code changes to the Strapi VM when merged to staging So that the running Strapi instance stays in sync with the codebase
Acceptance Criteria:
When PR with cms/ changes is merged to staging, a deployment pipeline triggers
Pipeline executes git pull on the GCP VM to update the repository
If cms/package.json changed, npm install runs automatically
Strapi service restarts to apply changes
Deployment status is reported (success/failure)
Failed deployments alert the team
Same process applies when staging is merged to main (for production Strapi if separate)
Story 10: Rebuild Strapi Content Database for PR-Based Content Changes
As a the system I want to rebuild Strapi content from MDX after PR merges to staging So that content changes made via feature branches are reflected in Strapi
Acceptance Criteria:
When a PR to staging modifies content (MDX), a Strapi content rebuild is triggered
The rebuild runs cms/scripts/sync-mdx.cjs against the staging Strapi instance
Existing Strapi users and auth data are preserved (content-only rebuild)
The rebuild can run in dry-run mode for validation before applying changes
Rebuild status is reported (success/failure)
Failures alert the team and do not affect the running Strapi service
Technical Implementation Notes
Git Branch Protection Rules
Required for main branch:
Require pull request before merging
Require at least 1 approval
Dismiss stale pull request approvals when new commits are pushed
Require status checks to pass (Netlify build)
Do not allow bypassing the above settings
Restrict who can push to matching branches (no direct commits)
Required for staging branch:
Require pull request before merging (for code changes)
Allow Strapi service account to push directly (for content commits)
Require status checks to pass (Netlify build)
Strapi VM Deployment (GCP)
Critical Requirements:
Strapi VM must maintain a full git clone of the repository
Clone must be on the staging branch (since Strapi commits to staging)
Content Publishing Workflow
Overview
This document defines the content publishing workflow for interledger.org, using Strapi CMS, Git branches, and Netlify deployments.
Architecture Overview
flowchart subgraph gcp["☁️ GCP VM"] direction TB strapi[(Strapi CMS)] gitclone[("Git Clone<br/>(staging)")] strapi -->|"writes MDX"| gitclone end subgraph github["📦 GitHub Repository"] direction TB staging["staging branch"] main["main branch"] end subgraph netlify["🚀 Netlify"] direction TB preview["Preview Site"] production["Production Site"] end editor["👤 Content Editor"] dev["👨💻 Developer"] feature["Feature Branch"] editor ==>|"Publish"| strapi dev ==>|"Code PR"| feature gitclone ==>|"Push via<br/>lifecycle hooks"| staging feature ==>|"PR"| staging staging ==>|"Auto-build"| preview staging -->|"PR (approved)"| main main ==>|"Auto-build"| production gitclone -.-|"Sync after<br/>PR merge"| strapi classDef gcpStyle fill:#4285f4,stroke:#1967d2,color:#fff classDef githubStyle fill:#24292e,stroke:#000,color:#fff classDef netlifyStyle fill:#00c7b7,stroke:#008577,color:#fff classDef userStyle fill:#ff6b6b,stroke:#d63031,color:#fff classDef branchStyle fill:#6c5ce7,stroke:#5f3dc4,color:#fff class strapi,gitclone gcpStyle class staging,main,feature githubStyle class preview,production netlifyStyle class editor,dev userStyleWorkflow Summary
stagingbranchmainvia pull requestmainto productionBranch Strategy
staging- Preview environment for content reviewmain- Production environment (always reflects live site)All content changes flow through
staging→mainvia pull request.User Stories
Story 1: Content Editor Publishes Changes
As a content editor
I want to publish content changes in Strapi
So that they are automatically committed to the staging branch and available for review
Acceptance Criteria:
stagingbranchStory 2: Automatic Staging Preview Build
As a content editor or reviewer
I want Netlify to automatically build and deploy the staging branch
So that I can preview my changes before they go to production
Acceptance Criteria:
stagingbranchStory 3: Product Owner Reviews Staging Content
As a product owner
I want to review content on the staging preview site
So that I can approve or reject changes before production
Acceptance Criteria:
stagingbranchStory 4: Promote Staging to Production via PR
As a product owner
I want to promote approved staging content to production via a pull request
So that changes are traceable and reviewed before going live
Acceptance Criteria:
stagingtomainmainbranch always reflects production contentStory 5: Production Deployment
As a the system
I want to automatically deploy
mainbranch to productionSo that approved content goes live
Acceptance Criteria:
mainbranchStory 6: Rollback Production Deployment
As a product owner or site administrator
I want to rollback to a previous production deployment
So that I can quickly recover from issues
Acceptance Criteria:
mainwill redeploy and override the rolled-back stateStory 7: Preview Unpublished Content
As a content editor
I want to preview draft content before publishing
So that I can verify it looks correct without triggering builds
Acceptance Criteria:
Story 7a: Host SSR Preview Service on the Strapi VM
As a the system
I want to run an Astro SSR preview server on the Strapi VM
So that content editors have a fast, build-free preview experience
Acceptance Criteria:
preview.<domain>) and uses HTTPSCLIENT_URLpoints to the preview server URLexport const prerender = falseSTRAPI_PREVIEW_TOKENStory 7b: Preview Button Integrates with Strapi Admin
As a content editor
I want a working Preview button in Strapi that opens the SSR preview
So that I can review drafts before publishing
Acceptance Criteria:
config/admin.tspreview handler to build the preview URLdocumentIdfor lookupStory 7c: Maintain Preview Block Rendering
As a developer
I want preview block adapters to render Strapi dynamic zones correctly
So that previews match the published site as closely as possible
Acceptance Criteria:
src/components/blocks/Story 8: Developer Makes Code Changes
As a developer
I want to make code changes (Astro components, layouts, styles, CMS) to the staging branch first
So that changes can be reviewed and tested before going to production
Acceptance Criteria:
staging(notmain)staging(notmain)mainare blocked by branch protection rulescms/folder) trigger Strapi deployment to VMStory 9: Deploy CMS Code Changes to Strapi VM
As a the system
I want to automatically deploy CMS code changes to the Strapi VM when merged to staging
So that the running Strapi instance stays in sync with the codebase
Acceptance Criteria:
cms/changes is merged tostaging, a deployment pipeline triggersgit pullon the GCP VM to update the repositorycms/package.jsonchanged,npm installruns automaticallyStory 10: Rebuild Strapi Content Database for PR-Based Content Changes
As a the system
I want to rebuild Strapi content from MDX after PR merges to
stagingSo that content changes made via feature branches are reflected in Strapi
Acceptance Criteria:
stagingmodifies content (MDX), a Strapi content rebuild is triggeredcms/scripts/sync-mdx.cjsagainst the staging Strapi instanceTechnical Implementation Notes
Git Branch Protection Rules
Required for
mainbranch:Required for
stagingbranch:Strapi VM Deployment (GCP)
Critical Requirements:
stagingbranch (since Strapi commits to staging)/var/www/interledger.org-v5/cms/subdirectory within the clonesrc/content/directoriesDeployment Process:
git clone <repo-url> --branch staginggit config credential.helper storecms/directorySecurity Considerations:
CMS Code Deployment Pipeline
Trigger: PR merge into
staging(code changes). Do not trigger on direct Strapi content pushes.Pipeline Steps:
sudo systemctl stop strapi # or: pm2 stop strapicd /var/www/interledger.org-v5 git pull origin stagingcd cms npm installsudo systemctl start strapi # or: pm2 start strapicurl http://localhost:1337/admin)Implementation Options:
Considerations:
Strapi Configuration
cms/src/api/*/content-types/*/lifecycles.tshandle MDX generationstagingbranch (current working branch)STRAPI_DISABLE_GIT_SYNC=trueto disable automatic commits (for local development)MDX Output Locations
src/content/foundation-pages/(localized:src/content/{locale}/foundation-pages/)src/content/blog/src/content/grants/Netlify Configuration
stagingbranchmainbranchPreview Page
/developers/blog/preview?slug={documentId}