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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Expand this file when more maintainers join the project.
* @learncold
34 changes: 34 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Summary

-

## Related Issue

- Closes #

## Area

- [ ] Engine
- [ ] Domain
- [ ] Application
- [ ] Docs
- [ ] Build
- [ ] Analysis
- [ ] Chore

## Architecture Check

- [ ] I kept the dependency direction `application -> domain -> engine`.
- [ ] I did not add Qt UI code to `src/domain`.
- [ ] I did not add `domain` or `application` dependencies to `src/engine`.
- [ ] I used `src/` as the include root.

## Verification

- [ ] `cmake --preset windows-debug`
- [ ] `cmake --build --preset build-debug`
- [ ] Not run (reason below)

## Risks / Follow-up

-
77 changes: 77 additions & 0 deletions .github/workflows/pr-policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: PR Policy

on:
pull_request:
types:
- opened
- edited
- synchronize
- reopened
- ready_for_review

permissions:
contents: read
pull-requests: read

jobs:
validate-pr:
name: Validate PR
runs-on: ubuntu-latest
steps:
- name: Check title and body
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const title = pr.title || "";
const body = pr.body || "";
const errors = [];

const titlePattern = /^\[(Engine|Domain|Application|Docs|Build|Analysis|Chore)\]\s.+$/;
if (!titlePattern.test(title)) {
errors.push("PR title must match `[Area] short summary`.");
}

const requiredHeadings = [
"## Summary",
"## Related Issue",
"## Area",
"## Architecture Check",
"## Verification",
];

for (const heading of requiredHeadings) {
if (!body.includes(heading)) {
errors.push(`Missing section: ${heading}`);
}
}

const section = (heading) => {
const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const pattern = new RegExp(`${escaped}\\s*([\\s\\S]*?)(?=\\n## |$)`, "i");
const match = body.match(pattern);
return match ? match[1] : "";
};

const relatedIssueSection = section("## Related Issue");
const areaSection = section("## Area");
const verificationSection = section("## Verification");

const issuePattern = /\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?|refs?)\s+#\d+\b/i;
if (!issuePattern.test(relatedIssueSection)) {
errors.push("`## Related Issue` must include an issue reference such as `Closes #12`.");
}

if (!/- \[[xX]\] /.test(areaSection)) {
errors.push("Select at least one checkbox in `## Area`.");
}

if (!/- \[[xX]\] /.test(verificationSection)) {
errors.push("Select at least one checkbox in `## Verification`.");
}

if (errors.length > 0) {
core.setFailed(errors.join("\n"));
} else {
core.info("PR policy checks passed.");
}
73 changes: 73 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# SafeCrowd PR Rules

이 저장소는 `application -> domain -> engine` 계층을 유지하는 것을 가장 중요한 규칙으로 둡니다.
PR은 작은 단위로 나누고, 어떤 issue를 해결하는지 분명하게 남겨 주세요.

## 기본 원칙

- 기본 작업 흐름은 `issue -> branch -> PR -> merge`입니다.
- 가능하면 하나의 PR은 하나의 issue만 해결합니다.
- 서로 다른 계층을 동시에 크게 건드리는 PR은 피합니다.
- 구조, 빌드, 의존성 규칙이 바뀌면 관련 문서를 함께 업데이트합니다.

## PR 제목 규칙

PR 제목은 아래 형식을 따릅니다.

```text
[Area] short summary
```

허용되는 `Area` 값:

- `Engine`
- `Domain`
- `Application`
- `Docs`
- `Build`
- `Analysis`
- `Chore`

예시:

```text
[Engine] implement generation-safe entity registry
[Docs] clarify build presets and architecture notes
```

## PR 본문 규칙

모든 PR은 아래 내용을 포함해야 합니다.

- 변경 요약
- 연결된 issue
- 변경이 속한 영역
- 아키텍처 규칙 점검 결과
- 빌드/검증 결과 또는 미실행 사유
- 남은 리스크나 후속 작업

## 아키텍처 체크

PR 작성 시 아래 항목을 항상 점검합니다.

- `engine`에 `domain` 또는 `application` 의존성을 추가하지 않았는가
- `domain`에 Qt UI 코드를 추가하지 않았는가
- `application`이 UI와 도메인 조립 책임을 벗어나지 않았는가
- include 경로가 `src/` 루트 기준(`application/...`, `domain/...`, `engine/...`)을 따르는가

## 검증 규칙

가능하면 아래 명령으로 검증합니다.

```powershell
cmake --preset windows-debug
cmake --build --preset build-debug
```

실행하지 못했다면 PR 본문에 이유를 남깁니다.

## 머지 규칙

- `main`에는 직접 push하지 않고 PR로 반영합니다.
- 머지는 squash merge를 기본으로 사용합니다.
- PR 체크가 실패한 상태에서는 머지하지 않습니다.
Loading