Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/rules/version-management-frontend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# ZERO-ONE Version Management Rule - Frontend Repository

Source of truth for this repository: `ops/version-management.md`.

This rule is a version-management rule, not a frontend coding-style rule. Do not duplicate the full rule body here; keep the durable policy in `ops/version-management.md` so Claude/Codex/project agents share the same repository-level source of truth.
10 changes: 10 additions & 0 deletions .claude/skills/zeroone-version-management/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: zeroone-version-management
description: Use when working on ZERO-ONE production release records, PR release intent labels/body, main-branch production deploy workflow, rollback metadata, or releases/prod-*.yaml in study-platform-client.
---

# ZERO-ONE Version Management Wrapper for Claude

Source of truth: `ops/agent-skills/zeroone-version-management.md`.

Immediately read that file and follow it. Do not duplicate or reinterpret the rule in this wrapper.
10 changes: 10 additions & 0 deletions .codex/skills/zeroone-version-management/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: zeroone-version-management
description: Use when working on ZERO-ONE production release records, PR release intent labels/body, main-branch production deploy workflow, rollback metadata, or releases/prod-*.yaml in study-platform-client.
---

# ZERO-ONE Version Management Wrapper for Codex

Source of truth: `ops/agent-skills/zeroone-version-management.md`.

Immediately read that file and follow it. Do not duplicate or reinterpret the rule in this wrapper.
260 changes: 225 additions & 35 deletions .github/workflows/deploy-prod.yml

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions .github/workflows/record-backend-prod-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 백엔드 prod 배포 fact(repository_dispatch)를 받아 프론트 레포 releases/에 최종 atomic release record를 남긴다.

name: Record Backend Production Release

on:
repository_dispatch:
types:
- backend-prod-deployed
workflow_dispatch:
inputs:
backend_payload_json:
description: 'Backend dispatch wrapper or client_payload JSON for validation/dry-run'
required: true
dry_run:
description: 'true면 record 생성/검증만 하고 commit/push하지 않는다'
required: true
default: 'true'

permissions:
contents: write

concurrency:
group: prod-release-record
cancel-in-progress: false

jobs:
record-backend-release:
runs-on: ubuntu-latest
env:
BACKEND_RELEASE_PAYLOAD_JSON: ${{ github.event_name == 'workflow_dispatch' && inputs.backend_payload_json || toJSON(github.event.client_payload) }}
BACKEND_RELEASE_DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || 'false' }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

Comment on lines +34 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

체크아웃 브랜치를 main으로 명시 고정하세요.

현재는 repository_dispatch 실행 시점의 기본 브랜치 기준으로 체크아웃될 수 있어, 커밋/푸시 대상(main)과 작업 베이스가 어긋날 위험이 있습니다.

수정 제안
       - name: Checkout code
         uses: actions/checkout@v4
         with:
           fetch-depth: 0
+          ref: main

Based on learnings: Main-branch production deployments must follow ops/version-management.md (ZERO-ONE Version Management Rule - Frontend Repository).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/record-backend-prod-release.yml around lines 24 - 28, 현재
Checkout step ("Checkout code" using actions/checkout@v4) can pull the default
branch for the event; explicitly pin the branch to main by adding with: ref:
main (keeping fetch-depth: 0) so the workflow always checks out the main branch
for releases; update the checkout step in the workflow to include ref: main to
enforce main-branch deployments per the ZERO-ONE rule.

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'

- name: Generate backend release record
run: |
set -euo pipefail
RECORD_PATH="$(node scripts/release/generate-backend-prod-release-record.mjs)"
node scripts/release/validate-release-record.mjs "$RECORD_PATH"
echo "RECORD_PATH=$RECORD_PATH" >> "$GITHUB_ENV"
echo "Generated $RECORD_PATH"
sed -n '1,220p' "$RECORD_PATH"

- name: Upload dry-run release record
if: ${{ env.BACKEND_RELEASE_DRY_RUN == 'true' }}
uses: actions/upload-artifact@v4
with:
name: backend-release-record-dry-run
path: ${{ env.RECORD_PATH }}
if-no-files-found: error

- name: Commit release record
if: ${{ env.BACKEND_RELEASE_DRY_RUN != 'true' }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add "$RECORD_PATH"
git commit -m "chore(release): record backend prod release [release-record]"
git pull --rebase origin main
git push origin HEAD:main
26 changes: 26 additions & 0 deletions .github/workflows/release-record-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Release Record Check

on:
pull_request:
paths:
- 'releases/**/*.yaml'
- 'scripts/release/**'
- 'ops/**'
- '.github/workflows/deploy-prod.yml'
- '.github/workflows/release-record-check.yml'
workflow_dispatch:

jobs:
validate-release-records:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Validate release records
run: node scripts/release/validate-release-record.mjs releases
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,9 @@ yarn typecheck # tsc --noEmit
- `@radix-ui/*` — headless UI primitives (Dialog, DropdownMenu, Avatar, etc.)

<!-- MANUAL: Any manually added notes below this line are preserved on regeneration -->

### Production Version Management
- Main-branch production deployments must follow `ops/version-management.md` (ZERO-ONE Version Management Rule - Frontend Repository).
- Agent skill SSOT for this workflow is `ops/agent-skills/zeroone-version-management.md`; Codex/Claude skill files are thin wrappers only.
- `releases/` is the source of truth for successful production FE/BE/DB/rollback combinations.
- Develop/test-server deployment keeps the existing flow and does not create release records.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ yarn typecheck # No type errors
- No hardcoded colors/spacing. Use only `@theme inline` tokens from `global.css`.

@.claude/rules/no-img-no-eslint-disable.md
@.claude/rules/version-management-frontend.md

---

Expand Down
60 changes: 60 additions & 0 deletions ops/agent-skills/zeroone-version-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ZERO-ONE Version Management Agent Skill SSOT

Use this skill when working on production release records, release intent labels/body, `main` production deployment workflow, rollback metadata, or `releases/prod-*.yaml` in `study-platform-client`.

This file is the shared skill source of truth. Codex and Claude wrappers must stay thin and point here instead of duplicating the workflow.

## Required reading order

1. `ops/release-record-shared-contract.md` - FE/BE shared payload and final record contract.
2. `ops/version-management.md` - frontend repository rule and release-record policy.
3. `ops/release-intent.md` - human usage for PR labels/body and bootstrap.
4. `ops/deploy-checklist.md` or `ops/rollback.md` only when deploying or rolling back.
5. Relevant scripts/workflows only after the docs above:
- `.github/workflows/deploy-prod.yml`
- `.github/workflows/release-record-check.yml`
- `scripts/release/resolve-prod-release-intent.mjs`
- `scripts/release/generate-prod-release-record.mjs`
- `scripts/release/generate-backend-prod-release-record.mjs`
- `scripts/release/validate-release-record.mjs`
- `ops/backend-release-dispatch.md`
- `ops/release-record-shared-contract.md`

## Non-negotiable rules

- This skill applies to `main` production releases only. Do not change `develop` deployment behavior unless the user explicitly asks.
- `ops/release-record-shared-contract.md` is the shared FE/BE contract; `releases/` is the frontend repository source of truth for successful production FE/BE/DB/rollback combinations.
- Frontend repo owns only the frontend version-management rule. Do not add the backend repository rule here.
- Production version metadata comes from PR intent or backend dispatch payload, not per-release repository variables.
- Exactly one release intent is allowed: `release:major`, `release:minor`, or `release:patch`. Use `N/A` for no DB migration version.
- If multiple `release:*` labels are present, or label intent conflicts with body `release`, fail instead of guessing.
- First recorded frontend production release requires explicit bootstrap approval metadata in the PR body: `bootstrap: approved`, `base_version` or `version`, backend image/commit/version, and rollback frontend/backend fixed image tags.
- `prod` and `latest-prod` are pointer tags only. They are never valid rollback targets and must fail if used as inherited or supplied backend/rollback images.
- Image dates belong in `release_id`, not image tags.

## Implementation workflow for agents

1. Inspect current branch and changed files.
2. Read the docs in the required reading order.
3. For workflow/script changes, add deterministic checks for:
- first-release bootstrap without accidental defaulting,
- duplicate release label failure,
- pointer-tag rejection,
- docs/examples matching supported script keys,
- backend dispatch schema validation,
- duplicate `metadata.backend_deploy_id` rejection.
4. Validate with targeted commands first:
- `node --check scripts/release/resolve-prod-release-intent.mjs`
- local resolver smoke cases for bootstrap, duplicate labels, pointer tags, and normal latest-release inheritance.
- `node scripts/release/validate-release-record.mjs releases`
5. Then run repository checks required by the project for the changed scope.

## Human handoff format

Report:

- changed files,
- what happens on `main` merge,
- what the PR author must put in labels/body,
- verification commands and results,
- any remaining manual setup such as optional `PROD_E2E_BASE_URL`.
97 changes: 97 additions & 0 deletions ops/backend-release-dispatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Backend Production Release Dispatch Contract

This is the frontend repository contract for backend production deployments. Backend automation is the producer of backend deploy facts. The frontend repository is the final release-record writer.

This document follows the shared FE/BE contract in `ops/release-record-shared-contract.md`.

## Trigger

Backend production deploy success must call the frontend repository with `repository_dispatch` or an equivalent API trigger.

```json
{
"event_type": "backend-prod-deployed",
"client_payload": {}
}
Comment on lines +9 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

트리거 예시의 client_payload가 필수 스키마와 충돌합니다.

Line 9-13 예시를 그대로 따르면 빈 payload가 전송되어, 같은 문서의 Required payload/fields 규칙을 즉시 위반합니다. 트리거 예시는 최소한 “필수 필드를 포함한 payload” 형태로 맞춰야 계약 오해를 막을 수 있습니다.

제안 diff
 {
   "event_type": "backend-prod-deployed",
-  "client_payload": {}
+  "client_payload": {
+    "release_id": "prod-YYYYMMDD-HHmm",
+    "env": "prod",
+    "backend": {
+      "image": "zeroone-backend:vMAJOR.MINOR.PATCH-shortCommit",
+      "commit": "shortCommit",
+      "version": "vMAJOR.MINOR.PATCH",
+      "changed": true
+    },
+    "database": {
+      "changed": false,
+      "migration_version": "none",
+      "migration_files": []
+    },
+    "rollback": {
+      "backend": "zeroone-backend:vMAJOR.MINOR.PATCH-shortCommit"
+    },
+    "metadata": {
+      "release_intent": "patch",
+      "bootstrap_mode": false,
+      "backend_deploy_id": "backend-prod-unique-id"
+    }
+  }
 }

Also applies to: 22-55

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ops/backend-release-dispatch.md` around lines 7 - 13, The example trigger
payload for event_type "backend-prod-deployed" currently shows an empty
client_payload which violates the document's Required payload/fields rules;
update the example JSON so client_payload includes the actual required fields
(e.g., service, version, environment, deploy_id or whatever the "Required
payload/fields" section mandates) and show sample values, ensuring consistency
with the document's Required payload/fields schema; apply the same correction to
the other example occurrences referenced in the document.

```

The frontend workflow that receives this event is:

```txt
.github/workflows/record-backend-prod-release.yml
```

## Required payload

```json
{
"release_id": "prod-20260517-2100",
"env": "prod",
"summary": "backend patch release",
"backend": {
"repo": "study-platform-mvp",
"image": "zeroone-backend:v1.4.3-b7c8d9e",
"commit": "b7c8d9e",
"version": "v1.4.3",
"changed": true
},
"database": {
"changed": true,
"migration_version": "V45",
"migration_files": [
"src/main/resources/db/migration/V45__create_course_refund.sql"
]
},
"rollback": {
"backend": "zeroone-backend:v1.4.2-a1b2c3d"
},
"metadata": {
"release_intent": "patch",
"bootstrap_mode": false,
"previous_deploy_image": "zeroone-backend:v1.4.2-a1b2c3d",
"pull_request_number": 1234,
"pull_request_labels": ["release:patch", "db:backup-confirmed"],
"backend_deploy_id": "backend-prod-123"
}
}
```

## Required fields

- `release_id` - `prod-YYYYMMDD-HHmm`
- `env` - must be `prod`
- `backend.image` - fixed immutable backend image tag
- `backend.commit` - backend short commit
- `backend.version` - `vMAJOR.MINOR.PATCH`
- `backend.changed` - must be `true`
- `database.changed` - boolean
- `database.migration_version` - migration version or `N/A`
- `database.migration_files` - array
- `rollback.backend` - fixed immutable backend rollback image tag
- `metadata.release_intent` - `patch`, `minor`, or `major`
- `metadata.bootstrap_mode` - boolean
- `metadata.backend_deploy_id` - unique backend deployment id

## Optional fields

- `summary`
- `metadata.previous_deploy_image`
- `metadata.pull_request_number`
- `metadata.pull_request_labels`

## Frontend behavior

When the dispatch arrives, the frontend repository workflow:

1. validates the payload strictly,
2. reads the latest `releases/prod-*.yaml` to identify current frontend production state,
3. creates a new release record with `frontend.changed=false` and `backend.changed=true`,
4. writes `metadata.backend_deploy_id`,
5. fails if the same `backend_deploy_id` is already recorded,
6. fails if image tags use `prod`, `latest-prod`, dates, or non-canonical versions.

The workflow does not deploy frontend code. It only records the new atomic production combination `FE(current) + BE(new)`.

## Failure principle

Do not guess. If the payload is missing, invalid, duplicated, or the frontend repository has no previous release record to identify current frontend production state, the workflow must fail instead of writing a wrong release record.
28 changes: 28 additions & 0 deletions ops/deploy-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Production Deploy Checklist

This checklist applies to `main` production deployments only. `develop` test-server deployment keeps the existing lightweight pointer-tag flow.

This document follows the shared FE/BE contract in `ops/release-record-shared-contract.md`.

## Before production deploy

- Confirm PR CI is green before merging to `main`.
- Confirm the PR has exactly one release intent: `release:patch`, `release:minor`, `release:major`, or a `release: ...` line in the PR body.
- Confirm `ops/release-intent.md` bootstrap approval fields are present if this is the first recorded frontend production release.
- For frontend-only deploys, confirm latest `releases/` backend image matches current production backend; if not, record the backend dispatch first.
- Confirm rollback targets and inherited/supplied backend images are fixed image tags, not `prod` or `latest-prod`.

## Deployment order

1. DB migration
2. Backend
3. Backend health check
4. Frontend
5. E2E/smoke check

## After production deploy

- Confirm frontend container is running with the fixed frontend image tag.
- Confirm backend health/API compatibility.
- Confirm `releases/prod-YYYYMMDD-HHmm.yaml` was committed to `main`.
- Confirm the release record includes frontend, backend, database, rollback, deploy order, deployed time, actor, and `status: success`.
Loading
Loading