Version: 1.0
Date: 2025-11-20
Infrastructure Repo: CoreMemorySquad/cms_infrastructure
CMS Repo: CoreMemorySquad/cms
This document specifies the interface contract between the CMS repository and the Infrastructure repository for automated ephemeral and staging environment deployments.
The CMS repository triggers deployments by sending repository_dispatch events to the infrastructure repository. Infrastructure workflows consume these events and provision the appropriate environments.
Infrastructure supports three repository_dispatch event types:
| Event Type | Triggered By | Purpose |
|---|---|---|
deploy-ephemeral |
/test-deploy PR comment |
Create or update ephemeral/staging environment |
destroy-ephemeral |
/destroy-test PR comment |
Manually destroy environment |
pr-closed |
PR closed/merged webhook | Auto-cleanup environment |
Event Type: deploy-ephemeral
Trigger: User comments /test-deploy on a PR in CMS repo
{
"pr_number": "string", // PR number (e.g., "123")
"branch": "string", // Head branch name (e.g., "feature/new-feature")
"base_branch": "string", // Base/target branch (e.g., "dev" or "main")
"commit_sha": "string", // HEAD commit SHA of the branch
"sender": "string" // GitHub username who triggered deploy
}-
pr_number(required): The PR number as a string- Example:
"123" - Used for: Workspace naming, PR comments, concurrency control
- Example:
-
branch(required): The feature branch being deployed- Example:
"feature/gamification" - Used for: Deploying the correct code for ephemeral environments
- Note: For staging (PR to main), infrastructure deploys
devbranch instead
- Example:
-
base_branch(required): The target branch of the PR- Example:
"dev"or"main" - Used for: Environment type detection
- Logic:
"main"→ Staging environment (deploysdevbranch)"dev"→ Ephemeral environment (deploys feature branch)
- Example:
-
commit_sha(required): The commit SHA being deployed- Example:
"a1b2c3d4e5f6" - Used for: PR comment information, deployment tracking
- Example:
-
sender(required): GitHub username who requested deployment- Example:
"syneto" - Used for: PR comment attribution
- Example:
- name: Get PR details
id: pr
uses: actions/github-script@v7
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
return {
head_ref: pr.data.head.ref,
base_ref: pr.data.base.ref,
head_sha: pr.data.head.sha
};
- name: Trigger infrastructure deployment
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.INFRASTRUCTURE_REPO_PAT }}
repository: CoreMemorySquad/cms_infrastructure
event-type: deploy-ephemeral
client-payload: |
{
"pr_number": "${{ github.event.issue.number }}",
"branch": "${{ fromJson(steps.pr.outputs.result).head_ref }}",
"base_branch": "${{ fromJson(steps.pr.outputs.result).base_ref }}",
"commit_sha": "${{ fromJson(steps.pr.outputs.result).head_sha }}",
"sender": "${{ github.event.comment.user.login }}"
}| Base Branch | Environment Type | Workspace Name | Branch Deployed | Subdomain |
|---|---|---|---|---|
dev |
Ephemeral | pr-{number} |
Feature branch | pr-{number}-testing.ernjv.me |
main |
Staging | staging |
dev branch |
staging.ernjv.me |
Infrastructure will comment on the CMS PR with:
- ✅ Success: Deployment URL, admin panel URL, environment details
- ❌ Failure: Error details and manual cleanup instructions
Event Type: destroy-ephemeral
Trigger: User comments /destroy-test on a PR in CMS repo
{
"pr_number": "string", // PR number
"base_branch": "string", // Base/target branch (for workspace detection)
"sender": "string" // GitHub username who triggered destroy
}pr_number(required): The PR numberbase_branch(required): Target branch (to determine if staging or ephemeral)sender(required): GitHub username who requested destroy
- name: Get PR details
id: pr
uses: actions/github-script@v7
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
return {
base_ref: pr.data.base.ref
};
- name: Trigger infrastructure destroy
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.INFRASTRUCTURE_REPO_PAT }}
repository: CoreMemorySquad/cms_infrastructure
event-type: destroy-ephemeral
client-payload: |
{
"pr_number": "${{ github.event.issue.number }}",
"base_branch": "${{ fromJson(steps.pr.outputs.result).base_ref }}",
"sender": "${{ github.event.comment.user.login }}"
}Infrastructure will comment on the CMS PR with destroy status.
Event Type: pr-closed
Trigger: PR closed or merged webhook in CMS repo
{
"pr_number": "string", // PR number
"base_branch": "string", // Base/target branch
"merged": "boolean" // true if PR was merged, false if just closed
}pr_number(required): The PR numberbase_branch(required): Target branch (to determine workspace name)merged(required): Whether PR was merged or just closed
on:
pull_request:
types: [closed]
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Trigger infrastructure cleanup
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.INFRASTRUCTURE_REPO_PAT }}
repository: CoreMemorySquad/cms_infrastructure
event-type: pr-closed
client-payload: |
{
"pr_number": "${{ github.event.pull_request.number }}",
"base_branch": "${{ github.event.pull_request.base.ref }}",
"merged": ${{ github.event.pull_request.merged }}
}No PR comment (environment already closed), but workflow logs available.
| Secret Name | Description | Scope |
|---|---|---|
INFRASTRUCTURE_REPO_PAT |
GitHub Personal Access Token with repo scope |
Repository-level |
- Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
- Generate new token with
reposcope - Add as repository secret in CMS repo:
INFRASTRUCTURE_REPO_PAT
Important: The PAT must have write access to the infrastructure repository to trigger repository_dispatch events.
Infrastructure workflows support manual triggering for testing:
# In infrastructure repo workflows, these inputs exist:
workflow_dispatch:
inputs:
pr_number:
description: 'PR number'
required: true
type: string
branch:
description: 'Branch name'
required: true
type: stringYou can test infrastructure workflows directly before implementing CMS triggers.
| Environment | Created When | Destroyed When |
|---|---|---|
Ephemeral (pr-{number}) |
/test-deploy on PR to dev |
/destroy-test OR PR closed |
Staging (staging) |
/test-deploy on PR to main |
/destroy-test OR PR to main closed |
Infrastructure will comment on the PR with markdown formatted messages.
🚀 **Ephemeral Environment Deployed Successfully!**
**Environment**: `pr-123`
**URL**: https://pr-123-testing.ernjv.me
**Admin Panel**: https://pr-123-testing.ernjv.me/admin
**Mailpit**: https://pr-123-testing.ernjv.me/mailpit
**Database**: `pr_123` (isolated)
**Files**: `pr-123/*` (prefix-isolated in shared bucket)
**Region**: NYC3
**Instance**: Basic XXS
**Email Testing (Mailpit)**:
- Web UI: https://pr-123-testing.ernjv.me/mailpit
- All emails captured for testing (registration, password reset, etc.)
- No real emails sent
...🚀 **Staging Environment Deployed Successfully!**
**Environment**: `staging`
**URL**: https://staging.ernjv.me
**Admin Panel**: https://staging.ernjv.me/admin
**Database**: `staging` (isolated)
**Files**: `staging/*` (prefix-isolated in shared bucket)
**Region**: NYC3
**Instance**: Basic XS
**Production Services Integrated**:
- Twilio SendGrid (real email delivery)
- Twilio SMS (real SMS delivery)
- All production-like external services
...- Create
.github/workflows/pr-commands.ymlto handle PR comments - Implement
/test-deploycommand detection - Implement
/destroy-testcommand detection - Create
.github/workflows/pr-closed.ymlfor auto-cleanup - Get PR details using
actions/github-script - Send
repository_dispatchwith correct event types - Include all required payload fields
- Add
INFRASTRUCTURE_REPO_PATsecret - Test with a real PR
- ADR-006: Staging environment architecture (infrastructure repo)
- ADR-002: GitHub Actions automation (infrastructure repo)
- Infrastructure Workflows:
.github/workflows/ephemeral-*.yml
If payload format needs adjustment, infrastructure should update this specification and notify CMS team.