Git Workflow & Contribution Guide¶
This guide is the canonical reference for how code moves from a developer's laptop into production for the mr-mentor-backend repository (MAS-Mr-Mentor/mr-mentor-backend). It documents branch naming, commit-message conventions, the dated changelog discipline, the pull-request and @claude review flow, the CI gates that must pass, and exactly how a feature graduates from development to production via the automated Docker build + blue-green deploy. Read this before opening your first PR.
Status: documented from source on this branch. Everything below is derived from .github/workflows/*.yml, the changelog/ directory (202 dated entries + README.md), root roadmap/planning markdown, CI-CD.md, DOCKER_DEPLOYMENT.md, and package.json.
Overview¶
mr-mentor-backend is a single-repo, multi-product backend (Node 20 + Express + TypeScript + TypeORM + Redis/BullMQ + Socket.IO). Contribution is governed less by a written CONTRIBUTING.md (there is none) and more by a set of conventions baked into:
- GitHub Actions — four workflows in
.github/workflows/:build.yml,deploy-development.yml,deploy-production.yml,claude.yml. - A dated changelog convention —
changelog/YYYY-MM-DD-<sha>-<slug>.md, one file per significant commit, indexed bychangelog/README.md. - Living roadmap docs —
ROADMAP_COURSE_BATCH_TEST_CONNECTIONS.md,PHASE2_ROHAN_TASKS.md,WHATSAPP_LEADS_STRATEGY.mdtrack in-flight work and ownership.
Who participates¶
| Persona | Responsibility in the flow |
|---|---|
| Developer / contributor | Branches off development, commits, adds a changelog entry, opens a PR. |
| Reviewer | Reviews the PR diff; may tag @claude to invoke the automated reviewer (claude.yml). |
@claude bot |
The anthropics/claude-code-action GitHub App — runs on @claude mentions in issues, PR reviews, and comments. |
| Release / deploy owner | Merges to main; this auto-triggers the production blue-green deploy. |
claude-code-india GitHub account |
The only account with push rights to this repo (see Edge cases & gotchas). |
Where it sits in the suite¶
This repo is the first service to deploy in the MAS suite (other services depend on its API). Its branches map directly to running environments: development → dev EC2 box, main → production (blue-green). See deployment-architecture and cicd-pipelines for the infrastructure detail this guide cross-references.
Key concepts & entities¶
This is a process guideline, not a code domain, so there are no TypeORM entities. The "entities" here are repository artifacts and their file paths.
| Term | Meaning | Where it lives |
|---|---|---|
| Default integration branch | development — where day-to-day feature branches merge first. |
git ref |
| Production branch | main — merging here ships to prod. |
git ref |
| Staging branch | staging — recognized by build.yml but not wired to a deploy workflow. |
git ref |
| Feature branch | feature/<slug> or fix/<slug> (also feat/<slug>, ad-hoc name-slug). |
git ref |
| Changelog entry | One markdown file per significant commit. | changelog/YYYY-MM-DD-<sha>-<slug>.md |
| Changelog index | Hand/auto-maintained table of all entries by year + category. | changelog/README.md |
| Build workflow | Builds + pushes the Docker image to GHCR. | .github/workflows/build.yml |
| Dev deploy workflow | Pulls the image onto the dev server via SSH + compose. | .github/workflows/deploy-development.yml |
| Prod deploy workflow | Blue-green zero-downtime deploy with rollback. | .github/workflows/deploy-production.yml |
| Claude review workflow | @claude automated reviewer/assistant. |
.github/workflows/claude.yml |
| Blue-green scripts | Server-side deploy.sh, rollback.sh, health-check.sh. |
/home/ubuntu/blue-green-deployment/ on prod box |
| Health gate | GET /api/health returning "success":true. |
src/routes/health.routes.ts, mounted in src/routes/index.ts |
Architecture¶
The end-to-end pipeline: a push event triggers a single image build, and the build's completion (a workflow_run event) fans out to the environment-specific deploy workflow that matches the source branch.
flowchart TD
Dev["Developer laptop"] -->|"git push feature branch"| GH["GitHub repo MAS-Mr-Mentor/mr-mentor-backend"]
Dev -->|"open PR into development"| PR["Pull Request"]
PR -->|"comment @claude"| CLAUDE["claude.yml (Claude Code Action)"]
PR -->|"merge"| DEVBR["development branch"]
DEVBR -->|"merge / promote"| MAINBR["main branch"]
subgraph CI["GitHub Actions"]
BUILD["build.yml: docker build + push to GHCR"]
DEPDEV["deploy-development.yml"]
DEPPROD["deploy-production.yml (blue-green)"]
end
DEVBR -->|"push event"| BUILD
MAINBR -->|"push event"| BUILD
BUILD -->|"image to GHCR ghcr.io/mas-mr-mentor/..."| GHCR["GHCR registry"]
BUILD -->|"workflow_run success on development"| DEPDEV
BUILD -->|"workflow_run success on main"| DEPPROD
subgraph DEVSRV["Dev EC2 server"]
DCOMPOSE["docker compose -f docker-compose.prod.yml up -d"]
end
subgraph PRODSRV["Prod EC2 server"]
BG["deploy.sh blue/green container + nginx switch"]
HC["health-check.sh + /api/health"]
end
DEPDEV -->|"scp .env from AWS Secrets Manager + SSH"| DCOMPOSE
DEPPROD -->|"scp .env.original from AWS Secrets Manager + SSH"| BG
BG --> HC
GHCR -.->|"docker pull"| DCOMPOSE
GHCR -.->|"docker pull"| BG
Data model¶
There is no database schema for this domain. The closest "data model" is the relationship between git refs, the build artifact, and the changelog records. The diagram below shows how those records relate.
erDiagram
BRANCH ||--o{ COMMIT : "contains"
COMMIT ||--o| CHANGELOG_ENTRY : "documented by"
COMMIT ||--o{ PULL_REQUEST : "referenced by"
PULL_REQUEST }o--|| BRANCH : "targets"
COMMIT ||--|| DOCKER_IMAGE : "builds"
DOCKER_IMAGE }o--|| ENVIRONMENT : "deploys to"
CHANGELOG_ENTRY }o--|| CHANGELOG_INDEX : "listed in"
BRANCH {
string name "main development staging feature-*"
string role "prod integration staging work"
}
COMMIT {
string sha "7-char short sha"
string message "conventional-ish"
}
CHANGELOG_ENTRY {
string filename "YYYY-MM-DD-sha-slug.md"
string date
string description
string breakingChanges
}
DOCKER_IMAGE {
string tag "branch and branch-sha and latest"
string registry "ghcr.io"
}
ENVIRONMENT {
string name "development production"
string secretId "mr-mentor-backend/{env}"
}
Branch naming¶
Branch conventions, inferred from the merge entries in changelog/README.md (e.g. MAS-Mr-Mentor/feature/add-rating-filter, shubham21155102/feature/get-online-mentors, shubham21155102/fix/meeting-issues-and-improvements, shubham21155102/feat/jwt-auth-routes):
| Branch | Purpose | Deploys to | Notes |
|---|---|---|---|
main |
Production-ready code. | Production (blue-green) | Push/merge auto-builds + deploys. Protected by convention — only claude-code-india can push. |
development |
Default integration branch. | Development server | Open feature PRs here first. (Renamed from develop in commit 5c9bf2d.) |
staging |
Pre-prod staging. | none wired | Recognized by build.yml (builds an image) but no deploy workflow consumes it. (inferred) |
feature/<slug> |
New features. | n/a | e.g. feature/add-rating-filter, feature/get-online-mentors. |
fix/<slug> |
Bug fixes. | n/a | e.g. fix/meeting-issues-and-improvements. |
feat/<slug> |
Variant of feature prefix seen in early history. | n/a | e.g. feat/jwt-auth-routes. |
Recommended convention going forward: feature/<kebab-slug> or fix/<kebab-slug>, branched from development. Forked-branch contributions (from personal accounts such as shubham21155102) are also part of the repo history.
Commit message style¶
Commit history shows a loosely-followed Conventional Commits style. There is no commit linter (the lint step was removed from CI — see commit ff3c3f7 "Remove linter step from CI/CD pipeline").
Observed prefixes (from changelog/ filenames and the index):
| Prefix | Use | Example commit |
|---|---|---|
feat: |
New feature | feat: add rating filter to mentors API |
fix: |
Bug fix | fix: resolve Docker container naming conflict in deployment |
chore: |
Tooling / runtime | chore: Switch from Bun to Node.js runtime |
refactor: |
Restructure without behavior change | refactor: split CI/CD pipeline into separate build and deploy workflows |
docs: |
Documentation | docs: add cleanup API usage guide |
Reality check: a large share of commits are plain imperative strings with no prefix (add slots, fix login error, release slot, db chnages). Some were even auto-generated by an LLM (commits literally titled 🧠 Generating commit message using Groq API...). Aim for the type: short imperative summary form, but the existing history is not strict.
Recommended format:
<type>: <imperative summary, lower-case, no trailing period>
<optional body: what & why, not how>
<optional footer: Breaking Changes / refs #issue>
The changelog discipline¶
This repo's most distinctive convention: every significant commit gets its own dated markdown file in changelog/. There are 202 such files plus changelog/README.md.
Filename format¶
Examples:
- 2025-09-25-aa58c78-feat-implement-jwt-authentication-routes.md
- 2025-11-11-cfb28b0-feat-add-rating-filter-to-mentors-api.md
- 2026-01-04-f956226-chore-switch-from-bun-to-node-js-runtime-for-better-socket-io-compatibility.md
The <slug> is the commit subject lower-cased with non-alphanumerics replaced by hyphens — i.e. it mirrors the commit message, which is why the commit message and the changelog slug are coupled. Merge commits get entries too (...-merge-pull-request-3-from-mas-mr-mentor-feature-add-rating-filter.md).
Entry body format¶
Each file follows this template (from 2025-09-25-aa58c78-feat-implement-jwt-authentication-routes.md):
# feat: Implement JWT authentication routes (aa58c78)
**Date:** 2025-09-25 18:32:41
**Commit:** aa58c789a8d308ba20e994eae22b6063c1d88811
## Files Changed
### Added
- `src/controllers/auth.controller.ts` - Authentication controller
### Modified
- `src/app.ts` - Updated app configuration
## Description
Implemented JWT-based authentication routes including login, register, and token validation.
## Breaking Changes
None
Required sections: a title with (short-sha), a **Date:** and full **Commit:** hash, a ## Files Changed block grouped by Added/Modified/Deleted, a ## Description, and a ## Breaking Changes (write None if not applicable).
The index: changelog/README.md¶
changelog/README.md aggregates all entries:
- Per-year tables (### 2025, ### 2026) with | Date | Commit | Description | rows, the commit linking to its entry file.
- Per-month archive lists.
- A ## Categories section bucketing work into Features (feat), Bug Fixes (fix), Infrastructure, and Breaking Changes (with dates — e.g. "Runtime switched from Bun to Node.js (2026-01-04)", "Meeting duration changed to 15 minutes (2025-11-16)").
- A *Last updated:* footer.
When you add a changelog file, also add a row to the appropriate year table and month archive in README.md, and — if your change is breaking — record it under ### Breaking Changes.
No automated changelog generator script exists in the repo (no husky hook, no
changelognpm script). The convention is maintained manually / by the contributor's own tooling. (inferred)
API surface¶
This domain has no application routes. The endpoints below are the ones the contribution/CI flow actually touches.
| Method | Path | Auth/role | Purpose |
|---|---|---|---|
| GET | /api/health |
none | Health gate the prod deploy curls for "success":true before/after switching nginx. Mounted via src/routes/index.ts (/api + health.routes). |
| — | /admin/queues |
Bull Board (UI) | BullMQ queue monitoring UI; useful when verifying a deploy's workers came up. Mounted in src/routes/index.ts. |
| webhook | GitHub push event |
GitHub | Triggers build.yml on main, development, staging. |
| webhook | GitHub workflow_run (completed) |
GitHub | Triggers deploy-development.yml (on development) and deploy-production.yml (on main). |
| webhook | GitHub issue_comment / pull_request_review / pull_request_review_comment / issues containing @claude |
GitHub App | Triggers claude.yml. |
User journeys¶
Journey 1: Standard feature contribution (dev path)¶
The everyday path: branch from development, commit with a changelog entry, open a PR, get it reviewed, merge — which auto-deploys to the dev server.
sequenceDiagram
participant Dev as Developer
participant Git as Local git
participant GH as GitHub
participant Rev as Reviewer
participant Bot as claude.yml bot
participant CI as build.yml
participant DD as deploy-development.yml
participant Srv as Dev EC2
Dev->>Git: branch feature-slug off development
Dev->>Git: commit code plus changelog entry file
Dev->>GH: push feature branch and open PR into development
Note over Dev,Rev: PR diff includes a new changelog file
Rev->>GH: review the diff
opt automated review
Rev->>GH: comment with at-claude please review
GH->>Bot: dispatch on at-claude mention
Bot-->>GH: posts review comments
end
Rev->>GH: approve and merge into development
GH->>CI: push event on development
CI->>CI: docker build target prod
CI-->>GH: push image to GHCR and emit workflow_run success
GH->>DD: workflow_run completed on development
DD->>DD: fetch env from AWS Secrets Manager mr-mentor-backend slash development
DD->>Srv: scp docker-compose.prod.yml and .env then SSH
Srv->>Srv: docker compose pull then up -d
Srv-->>DD: container status and logs
DD-->>GH: deployment summary
Journey 2: Graduating to production (blue-green deploy)¶
When development is verified, the changes are merged/promoted to main. A push to main builds a fresh image and triggers the zero-downtime blue-green deploy.
sequenceDiagram
participant Rel as Release owner
participant GH as GitHub
participant CI as build.yml
participant DP as deploy-production.yml
participant Srv as Prod EC2
participant NG as nginx
Rel->>GH: merge development into main
GH->>CI: push event on main
CI->>CI: docker build and tag main and main-sha and latest
CI-->>GH: push to GHCR and emit workflow_run success on main
GH->>DP: workflow_run completed head_branch main conclusion success
DP->>DP: fetch env from AWS Secrets Manager mr-mentor-backend slash production
DP->>Srv: scp .env.original and SSH login to GHCR
DP->>Srv: pre-deployment health check nginx postgres redis
alt pre-check fails
Srv-->>DP: error and exit
DP-->>GH: deployment failed
else pre-check passes
DP->>Srv: run deploy.sh with image url
Srv->>Srv: start standby container green if blue active
Srv->>Srv: health-check.sh waits 30 to 40 seconds
alt deploy.sh non-zero exit
Srv->>Srv: dump container logs then rollback.sh
DP-->>GH: failed and rolled back
else healthy
Srv->>NG: switch traffic to new container zero downtime
DP->>Srv: post-deploy verify /api/health success true
Srv-->>DP: db users count and redis PONG and nginx port match
DP-->>GH: production deployment summary success
end
end
Journey 3: Adding the changelog entry alongside a commit¶
The changelog file is part of the same PR as the code. This is the micro-flow a contributor follows per significant change.
sequenceDiagram
participant Dev as Developer
participant Repo as Working tree
participant Idx as changelog README.md
Dev->>Repo: implement change and stage files
Dev->>Repo: create changelog YYYY-MM-DD-sha-slug.md
Note over Dev,Repo: title with short sha plus Date plus Commit hash
Dev->>Repo: fill Files Changed and Description and Breaking Changes
Dev->>Idx: add row to year table and month archive
opt breaking change
Dev->>Idx: add bullet under Breaking Changes with date
end
Dev->>Repo: commit everything together
Note over Dev,Repo: commit slug matches changelog slug
Journey 4: Invoking the @claude automated reviewer¶
Any teammate can pull the Claude Code Action into a thread by mentioning @claude in an issue body/title, a PR review, or a comment.
sequenceDiagram
participant User as Teammate
participant GH as GitHub
participant WF as claude.yml job
participant Act as claude-code-action v1
User->>GH: write at-claude in issue or PR review or comment
GH->>WF: event fires issue_comment or pull_request_review etc
WF->>WF: if condition checks body contains at-claude
WF->>Act: run with CLAUDE_CODE_OAUTH_TOKEN model sonnet
Act->>GH: checkout repo fetch-depth 1
Act-->>GH: post review or changes with contents and PR and issues write
Journey 5: Manual deploy / rollback (break-glass)¶
Both deploy workflows expose workflow_dispatch, and the prod box keeps the previous container for instant rollback.
sequenceDiagram
participant Op as Operator
participant GH as GitHub Actions
participant DP as deploy workflow
participant Srv as Server
alt manual redeploy
Op->>GH: run workflow_dispatch with branch input
GH->>DP: dispatch
DP->>Srv: deploy image branch-sha
else rollback after bad prod deploy
Op->>Srv: SSH into blue-green-deployment dir
Op->>Srv: run rollback.sh
Srv->>Srv: switch nginx back to previous container
Srv-->>Op: previous version live
end
Background jobs & async¶
The workflows are event-chained rather than scheduled:
build.yml— trigger:pushtomain/development/staging, plusworkflow_dispatch. Hasconcurrency: group docker-build, cancel-in-progress: trueso a newer push cancels an in-flight build. Builds theprodDocker stage, pushes to GHCR with GHA layer cache (type=gha, mode=max).deploy-development.yml— trigger:workflow_runof "Build and Push Docker Image" completing ondevelopment, plusworkflow_dispatch. Runs only ifconclusion == success.deploy-production.yml— trigger:workflow_runcompleting onmainwithconclusion == success, plusworkflow_dispatch. Uses GitHub Environmentproduction.claude.yml— trigger:@claudementions across issue/PR events.
There is no schedule:/cron trigger and no queue involved in CI. (The app's own BullMQ workers — email, database, cleanup, kpi, resumeAnalysis — are runtime concerns, surfaced post-deploy at /admin/queues, not part of the git workflow.)
External integrations¶
| Integration | Used by | Env / secret | Failure / fallback |
|---|---|---|---|
| GHCR (GitHub Container Registry) | build.yml push, both deploys pull |
GITHUB_TOKEN for push; GHCR_PAT (user MAS-intern) or GHCR_PULL_TOKEN (user mas-mr-mentor) for server-side pull login |
Dev workflow prefers long-lived GHCR_PAT so the server's docker login survives after the run; the ephemeral GITHUB_TOKEN fallback dies with the run and leaves dead creds. |
| AWS Secrets Manager | both deploys build .env |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION (default ap-south-1); secret IDs mr-mentor-backend/development and mr-mentor-backend/production |
Workflow jq -e 'type == "object"' validates the secret is a JSON object before writing .env; aborts otherwise. |
| Dev/Prod EC2 over SSH | appleboy/scp-action + appleboy/ssh-action |
*_SERVER_HOST, *_SERVER_USER, *_SSH_KEY, *_SSH_PORT (default 22) |
Prod pre-check verifies nginx/postgres/redis before deploying; aborts if any down. |
| Anthropic Claude Code Action | claude.yml |
CLAUDE_CODE_OAUTH_TOKEN, model: claude-sonnet-4-6 |
Job's if: guard means it no-ops unless the body actually contains @claude. |
| nginx (prod) | blue-green traffic switch | /etc/nginx/sites-available/api.myanalyticsschool.com |
Post-deploy step warns (does not fail) on nginx/active-port mismatch. |
Feature flags / config quirks¶
- The original
CI-CD.mddescribes a legacy PM2 + Bun deploy (ci-cd.yml,ecosystem.config.js,deploy.sh). That has been superseded by the Docker pipeline (refactor: split CI/CD pipeline into separate build and deploy workflows, commit2c8d924) and the runtime switch from Bun to Node.js (f956226). TreatCI-CD.mdas historical. - The lint and unit-test CI gates were removed from the pipeline (commits
ff3c3f7"Remove linter step",5c96012"remove unit test case step"). See the gotcha below.
Status lifecycles¶
A change flows through these states from branch to live in production.
stateDiagram-v2
[*] --> Branched
Branched --> Committed: commit code plus changelog
Committed --> InReview: open PR into development
InReview --> Changes: reviewer or at-claude requests changes
Changes --> InReview: push fixes
InReview --> MergedDev: approve and merge
MergedDev --> BuildingDev: build.yml on development
BuildingDev --> DeployedDev: deploy-development success
BuildingDev --> BuildFailed: docker build fails
DeployedDev --> PromotedMain: merge development into main
PromotedMain --> BuildingProd: build.yml on main
BuildingProd --> PreCheck: deploy-production pre-check
PreCheck --> DeployingProd: nginx postgres redis healthy
PreCheck --> Aborted: dependency down
DeployingProd --> LiveProd: health check passes nginx switched
DeployingProd --> RolledBack: deploy.sh fails so rollback.sh runs
RolledBack --> DeployedDev: previous version restored
LiveProd --> [*]
BuildFailed --> Committed: fix and recommit
Aborted --> [*]
Edge cases, limits & gotchas¶
- Only
claude-code-indiacan push. Per project memory, the only GitHub account with push access toMAS-Mr-Mentor/mr-mentor-backendisclaude-code-india. Contributors from personal forks (e.g.shubham21155102) land via PRs; the actual merge/push that ships code is performed by that account. - Pushing to
mainships to production immediately. There is no manual approval gate between themainbuild and the blue-green deploy beyond the GitHub Environmentproduction(which may carry required reviewers — verify in repo settings). A merge tomainauto-builds and auto-deploys. Be deliberate. - No CI test/lint gate. The lint step and unit-test step were explicitly removed from CI.
npm test(Bun),npm run test:unit,npm run test:integration, andnpm run lintexist inpackage.jsonbut are not enforced by the pipeline — run them locally before you push. The only enforced gate is "the Dockerprodimage builds successfully," plus the prod pre/post health checks. - The deploy is gated on the build, by branch.
deploy-development.ymlonly fires onworkflow_runfor branchdevelopment;deploy-production.ymlonly formainwithhead_branch == 'main'andconclusion == 'success'. A failed build never triggers a deploy. stagingbuilds but never deploys.build.ymlwill produce astagingimage, but no deploy workflow consumes it. (inferred)- Concurrency cancels in-flight builds.
build.ymluses a singledocker-buildconcurrency group withcancel-in-progress: true— rapid successive pushes mean only the latest build survives. - Image tags. Every build pushes
:<branch>and:<branch>-<shortsha>;mainadditionally gets:latest. The dev deploy pulls:<branch>; the prod deploy pulls:<branch>-<shortsha>(reconstructed fromhead_sha). - GHCR login longevity. Use the long-lived
GHCR_PAT/GHCR_PULL_TOKENpaths; the ephemeralGITHUB_TOKENleaves dead credentials in~/.docker/config.jsonon the server after the run. - Secrets never live in the repo.
.envis built at deploy time from AWS Secrets Manager (mr-mentor-backend/{development,production}). Add new env vars there (see theadd-env-varskill), not in code. TypeORMsynchronize: truemeans no migration files — schema changes apply on boot, so a bad entity change ships to the DB on deploy. - Changelog is manual. No generator script is checked in; if you skip the changelog entry, nothing fails CI, but you break the convention and the
changelog/README.mdindex drifts. - Commit/branch hygiene is loose historically. Don't model new work on old typo commits (
db chnages,add socker) or LLM-generated subjects; follow the recommendedtype: summaryform. @claudeonly acts on an explicit mention. The workflow'sif:requires the literal string@claudein the relevant body/title; otherwise the job is a no-op.
Related docs¶
- CI/CD Pipelines — deep dive on
build.ymland the two deploy workflows. - Deployment Architecture — the EC2 hosts, blue-green topology, nginx, GHCR.
- Environment & Secrets — AWS Secrets Manager layout and the
add-env-varpropagation pattern. (inferred path) - Architecture Overview — where this backend sits in the MAS suite. (inferred path)