diff --git a/.claude/skills/yakcloud-deploy/SKILL.md b/.claude/skills/yakcloud-deploy/SKILL.md index 53e2087..ab48748 100644 --- a/.claude/skills/yakcloud-deploy/SKILL.md +++ b/.claude/skills/yakcloud-deploy/SKILL.md @@ -1,6 +1,6 @@ --- name: yakcloud-deploy -description: Deploy a project to YakCloud — yakcloud CLI (local kind dev → managed val/prod) or Gitea Actions (v* tag push) → build/push image → reconcile data sources → deploy workloads → bind env → custom domain. Use when deploying this project to YakCloud, editing yakcloud.yaml, binding data sources, adding a domain, or starting a new project. +description: Develop, verify, and deploy this project via the yakcloud CLI (local kind dev → managed val/prod) — never docker-compose. Build/push image → reconcile data sources → deploy workloads → bind env → custom domain. Use when running/testing/verifying the app locally, setting up a local dev environment, deploying to YakCloud, editing yakcloud.yaml, binding data sources, adding a domain, or starting a new project. If tempted to use docker-compose / docker run to run this app, use `yakcloud project deploy` (local kind) instead. --- # YakCloud 배포 스킬 @@ -8,6 +8,14 @@ description: Deploy a project to YakCloud — yakcloud CLI (local kind dev → m `yakcloud` CLI 로 **로컬 kind 개발 → 관리형 검증/운영**을 한 줄기로 배포한다. 또는 `v*` 태그 push → Gitea Actions 가 이미지 빌드/푸시 + 콘솔 API 로 데이터소스 리컨실·워크로드 배포·바인딩을 자동 처리. +## 개발·검증도 yakcloud — docker-compose 금지 (원칙) +이 프로젝트의 앱은 **로컬 개발·검증부터 운영까지 전 구간을 yakcloud 로** 진행한다. +- **로컬 실행·검증 = `yakcloud project deploy`** (로컬 kind 자동 생성, 오프라인·무료, 운영과 동일한 바인딩 env·데이터소스). +- **`docker compose` / `docker-compose` / `docker run` 으로 앱을 띄우지 마라** — 프로젝트 `.claude/settings.json` 이 이를 차단하고, + `Dockerfile` 은 yakcloud 의 이미지 빌드 전용이다. compose 스택은 운영과 환경이 달라져 파리티가 깨진다. +- 데이터소스는 손으로 컨테이너를 띄우지 말고 `yakcloud.yaml` 의 `requires` 로 선언한다. +(각 프로젝트 루트 `CLAUDE.md` 에 같은 규칙이 항상 로드되도록 심겨 있다 — `yakcloud project init` 이 생성.) + ## 실행 규약 (패스스루) — 최우선 `/yakcloud ` 로 호출되면 **`yakcloud ` 를 Bash 로 그대로 실행하고 출력만 보여준다.** 사전점검(설치/폴더/설정 확인)·결과 재검증·부연설명을 붙이지 말 것 — 터미널에서 직접 친 것과 동일하게 동작. diff --git a/bin/yakcloud b/bin/yakcloud index 958c90a..16665ca 100755 --- a/bin/yakcloud +++ b/bin/yakcloud @@ -16,7 +16,7 @@ set -uo pipefail # -e 미사용: 'test && action' 관용구가 값 없을 때 REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}" BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}" -VERSION="0.25.0" +VERSION="0.26.0" # 로컬 개발 클러스터(kind) — 개발 후 운영까지 '직선 배포'의 dev 구간. DEV_CTX="${YAK_DEV_CONTEXT:-kind-yak-dev}" DEV_CLUSTER="${YAK_DEV_CLUSTER:-yak-dev}" @@ -152,6 +152,58 @@ _sanitize_name() { printf '%s' "${s:-app}" } +# 프로젝트에 "yakcloud 로만 개발·검증·배포" 가드레일을 심는다 — AI 에이전트가 스킬을 켜기 전에도 +# 강제되도록 (1) 항상 로드되는 CLAUDE.md 지침 + (2) .claude/settings.json 의 docker-compose 차단(deny). +# $1=force: 1=덮어씀(init), 0=없을 때만 생성(update — 사용자 편집 보존). +_scaffold_yakcloud_guardrails() { + local force="${1:-0}" + if [ "$force" = 1 ] || [ ! -f CLAUDE.md ]; then + cat > CLAUDE.md <<'YCLAUDE' +# 이 프로젝트는 YakCloud 로 개발·검증·배포합니다 (AI 에이전트 필독) + +이 저장소의 앱은 **개발·검증부터 운영까지 전 구간을 `yakcloud` CLI** 로 진행합니다. 아래는 강제 규칙입니다. + +## 절대 금지 (NEVER) +- **`docker compose` / `docker-compose` / `docker run` 으로 이 앱을 로컬 실행·검증하지 마라.** (`.claude/settings.json` 이 차단) +- DB·캐시·큐 등 **데이터소스 컨테이너를 손으로 띄우지 마라** — `yakcloud.yaml` 의 `requires` 로 선언한다. +- `Dockerfile` 은 **yakcloud 의 이미지 빌드 전용**. 로컬 구동 도구가 아니다. + +## 일상 개발 루프 (ALWAYS) +1. 코드를 고친다. +2. **`yakcloud project deploy`** — 로컬 kind 클러스터에 배포(없으면 자동 생성, 오프라인·무료). + 관리형과 **동일한 바인딩 env·데이터소스** 로 뜬다. +3. 로컬 도메인 `*.localhost` 로 화면·API·WSS 확인. 반복 개발 = 2번 반복. +4. 확인되면 **`yakcloud project promote --to val|prod`** (같은 이미지, 재빌드 없이 관리형 승격). + +## 데이터소스 +- `yakcloud.yaml` 의 `requires` 에 `{ name, type }` 선언 → 워크로드 `binds` 로 연결 → `_URL` 등 자동 주입. +- type ∈ postgresql·mysql·mariadb·mongodb·redis·minio·rabbitmq·solr·oracle. 목록 = `yakcloud datasource ls`. + +## 참고 +- 상태 = `yakcloud project info` · 배포 전 dry-run = `yakcloud project check`. +- 슬래시로도 실행: `/yakcloud <명령>`. 상세 절차 = 전역 스킬 `yakcloud-deploy`. +- **왜 compose 를 안 쓰나**: compose 로컬 스택은 운영(관리형 k8s + env 주입 + 격리 소스)과 환경이 달라져 + "로컬은 되는데 운영에서 깨짐" 을 만든다. yakcloud 로컬 kind 는 운영과 **직선 파리티** 를 보장한다. +YCLAUDE + fi + mkdir -p .claude + if [ "$force" = 1 ] || [ ! -f .claude/settings.json ]; then + cat > .claude/settings.json <<'YSETTINGS' +{ + "permissions": { + "deny": [ + "Bash(docker compose:*)", + "Bash(docker-compose:*)", + "Bash(docker run:*)", + "Bash(sudo docker compose:*)", + "Bash(sudo docker-compose:*)" + ] + } +} +YSETTINGS + fi +} + cmd_project_init() { local name="" noninteractive=0 for a in "$@"; do case "$a" in -y|--yes|--no-wizard) noninteractive=1 ;; *) [ -z "$name" ] && name="$a" ;; esac; done @@ -169,11 +221,14 @@ cmd_project_init() { rm -rf "$tmp/s/.git" cp -R "$tmp/s/." . rm -rf "$tmp" - # 스캐폴드는 '앱 + 매니페스트 + 얇은 CI'만 남긴다 — 엔진·스킬·명령은 전역(프로젝트에 미포함). - # bin·install.sh=CLI · .yakcloud=엔진(전역) · .claude=스킬·명령(전역) · README/DATA-SOURCES=스타터 문서. - rm -rf bin install.sh .yakcloud .claude README.md DATA-SOURCES.md + # 스캐폴드는 '앱 + 매니페스트 + 얇은 CI + 프로젝트 가드레일'만 남긴다. 엔진·스킬·명령은 전역. + # bin·install.sh=CLI · .yakcloud=엔진(전역) · .claude/skills·commands=스킬·명령(전역) · README/DATA-SOURCES=스타터 문서. + # ⚠ .claude 는 통째로 지우지 않는다 — 프로젝트 로컬 .claude/settings.json(가드레일)은 남겨야 하므로 skills/commands 만 제거. + rm -rf bin install.sh .yakcloud .claude/skills .claude/commands README.md DATA-SOURCES.md # 전역 엔진/스킬/명령 준비(최초 init 시에도 보장). install_global_assets 2>/dev/null || true + # 프로젝트에 yakcloud 강제 가드레일 심기(CLAUDE.md 지침 + docker-compose 차단) — 에이전트가 딴 길로 새지 않게. + _scaffold_yakcloud_guardrails 1 # 프로젝트명 = 지정 이름 or 현재 폴더명 → K8s/이미지 안전하게 정규화(소문자·영숫자·하이픈). local proj; proj="$(_sanitize_name "${name:-$(basename "$(pwd)")}")" git rev-parse --git-dir >/dev/null 2>&1 || git init -q @@ -756,9 +811,12 @@ cmd_project_update() { cp "$tmp/s/.gitea/workflows/deploy.yml" .gitea/workflows/ 2>/dev/null || true # 얇은 CI(전역 엔진 받아 실행) rm -rf "$tmp" # 엔진·스킬·명령은 전역(프로젝트에 복제 안 함). 옛 per-project 잔재 제거. - rm -rf scripts .yakcloud .claude bin install.sh README.md DATA-SOURCES.md + # ⚠ .claude 를 통째로 지우지 않는다 — 프로젝트 로컬 .claude/settings.json(가드레일) 보존. skills/commands 만 제거. + rm -rf scripts .yakcloud .claude/skills .claude/commands bin install.sh README.md DATA-SOURCES.md install_global_assets # 전역 엔진(deploy/ctl/dev) + 스킬 + /yakcloud 명령 최신화 - echo "✓ 최신화 완료 — .gitea CI + 전역 엔진/스킬 갱신(app.py·yakcloud.yaml·Dockerfile 그대로)" + # 가드레일 보장(없으면 생성, 있으면 사용자 편집 보존) — 옛 프로젝트도 update 시 yakcloud 강제 지침을 얻는다. + _scaffold_yakcloud_guardrails 0 + echo "✓ 최신화 완료 — .gitea CI + 전역 엔진/스킬 갱신 + yakcloud 가드레일(app.py·yakcloud.yaml·Dockerfile 그대로)" } usage() {