


코딩 에이전트가 대규모 풀스택 리포지토리의 규칙을 지키게 한다
타입이 적용된 프론트엔드와 백엔드가 있는 대규모 리포지토리에서 AI 에이전트에게 작업을 맡길 때 쓴다. 푸시 전에 프리커밋 검사를 통과하고, 리포지토리가 옮겨 가는 새 방식으로 코드를 쓰며, 보안 문제는 역할마다 허용된 일로 판단하고, 테스트·문서·풀 리퀘스트를 프로젝트 형식대로 마무리한다.
이 AI 규칙을 사용하려면
## 푸시할 때마다 먼저 프리커밋 검사를 통과한다
커밋을 푸시하기 전에는 항상 리포지토리의 프리커밋 검사 모음을 모든 파일에 대해 실행한다. 프리커밋 검사가 실패하면 지속적 통합(CI)도 실패하므로, 이것은 취향이 아니라 협상 불가능한 게이트다.
효율적으로 실행하는 방법:
- 변경 사항을 먼저 스테이징한다. 프리커밋은 스테이징된 파일만 검사하므로, 스테이징되지 않은 수정은 조용히 건너뛴다.
- 빠른 내부 반복을 원한다면 스테이징된 파일에만 검사 모음을 실행하거나, 이름을 지정한 훅 하나(타입 체커, 포매터, 린터)만 실행한다. 풀 리퀘스트를 새로 열거나 갱신하는 푸시 직전에는 전체 파일 대상 검사를 실행한다.
- 실행 전에 프로젝트의 가상 환경이나 툴체인 셸을 활성화한다. 흔히 쓰이는 위치는 개발자마다 다르므로, 명령을 찾을 수 없다면 경로를 추측하지 말고 어떤 환경을 활성화해야 하는지 사용자에게 묻는다.
- 일부 훅은 자동으로 수정한다(포매터, 줄 끝 공백 제거 등). 수정된 파일을 다시 스테이징하고 재실행한다. 첫 실행은 이미 스스로 고친 문제도 실패로 보고하기 때문이다.
세 가지 실패 유형을 예상하라: 자동으로 고쳐지는 포매팅 문제, 수동 수정이 필요한 타입 체커 오류, 그리고 수동 수정이 필요한 린트 오류.
## 새 코드는 옛 방식이 아니라 옮겨 가는 새 방식으로 쓴다
여러 마이그레이션이 현재 진행 중이다. 옛 패턴과 일치하는 코드가 아직 남아 있지만, 그 존재가 같은 코드를 더 써도 된다는 허락은 아니다. 새 코드와 수정한 코드는 목표 패턴을 따른다.
- 타입이 적용된 프론트엔드: 회피 수단인 `any` 타입을 쓰지 않고, 타입이 없는 새 스크립트 파일도 만들지 않는다 — 타입이 적용된 언어로 작성하고 기존 타입 정의를 재사용한다.
- 공유 컴포넌트 계층: UI 컴포넌트를 서드파티 라이브러리에서 직접 가져오지 말고 프로젝트 자체의 디자인 시스템 패키지에서 가져오며, 레거시 토큰보다 디자인 시스템의 테마 토큰을 선호하고, 맞춤 CSS 대신 컴포넌트 라이브러리가 지원하는 스타일링을 사용한다.
- 테스트 피라미드: 통합 테스트보다 단위 테스트를, 엔드투엔드 테스트보다 통합 테스트를 선호한다. 새 엔드투엔드 테스트는 채택된 프레임워크로 작성한다. 대체된 옛 엔드투엔드 프레임워크는 더 이상 사용되지 않으며 마이그레이션이 끝나면 제거된다.
- 백엔드 타이핑: 모든 새 코드에는 타입 힌트를 붙이고, 모델은 적절한 애너테이션을 사용하며, 타입 체커를 반드시 통과해야 한다.
- 식별자 마이그레이션: 새 모델은 불투명한 고유 식별자를 기본 키로 사용하고, 공개 API는 내부의 순차 정수 대신 그 식별자를 노출하며, 기존 모델은 점진적 전환을 위해 정수 키와 함께 새 식별자를 추가로 갖는다.
## 보안 문제를 역할마다 허용된 일로 판단한다
어떤 코드 경로든 보안 문제를 평가하기 전에, 리포지토리의 정본 보안 정책 문서를 읽는다. 이 문서는 보안 모델의 권위 있는 출처이며, 사람이 보고한 내용과 자동 스캐너의 결과 모두를 판단하는 기준이다.
발견 사항이 범위 안에 있는지 판단하는 단일 기준은 이것이다: 보안 정책의 역할·권한 매트릭스가 허용하지 않은 행위를 어떤 주체가 수행할 수 있게 하는가? 그렇다면 범위 안이고, 아니라면 범위 밖이다.
그 기준을 규정하는 세 가지 신뢰 경계가 있다:
1. 관리자 역할은 완전히 신뢰되는 운영 주체다. 관리자가 문서화된 설정, API, UI를 통해 할 수 있는 일은 모두 의도된 기능이지 취약점이 아니다.
2. 운영자는 배포 시점의 결정을 소유한다: 시크릿, 네트워크 노출, 기능 플래그 선택, 커넥터와 코덱 선택, 알림 대상, 서드파티 플러그인. 이 계층에서의 설정 오류는 배포상의 결함이지 제품의 취약점이 아니다.
3. 코드베이스는 주체에게 기능을 노출하는 모든 곳 — API 라우트, 커맨드 및 데이터 접근 계층, UI 핸들러, 백그라운드 작업, 그 밖의 모든 진입점 — 에서 역할·권한 매트릭스를 강제할 책임이 있다. 강제 검사가 빠졌거나 잘못되어 있다면, 그것이 어디에 있든 범위 안이다.
이 모델은 운영자가 통제하는 인프라 — 메타데이터 데이터베이스, 캐시, 메시지 브로커, 시크릿 저장소, 배포 환경 — 가 운영자의 신뢰 경계 안에 머문다고 가정한다. 유효한 발견 사항이라면, 그러한 시스템을 이미 장악하지 않은 공격자가 경계를 침범할 수 있음을 입증해야 한다.
## 라우트와 데이터 종류마다 알맞은 권한 검사를 쓴다
라우트 수준 인가는 라우트 종류마다 하나의 데코레이터를 사용하며, 어떤 것을 쓸지는 라우트의 종류에 달려 있다: 현대적인 REST API 영역용 하나, 레거시 JSON 뷰 라우트용 하나, 레거시 HTML 뷰 라우트용 하나. 이들을 뒤섞어 쓰면 검사가 있어 보이더라도 강제 오류다.
객체 수준 인가는 그와 별개인 두 번째 게이트다. 이것은 데이터를 담고 있는 리소스 — 대시보드, 차트, 데이터셋과 데이터 소스, 쿼리, 데이터베이스 및 테이블 접근, 쿼리 컨텍스트 — 에 적용되며, 보안 관리자의 접근 검사를 통해 객체마다 호출된다. 특정한 데이터 보유 객체를 반환하거나 변경하는 라우트에서 객체별 게이트를 빠뜨린 코드는 범위 안이다.
그 밖의 리소스 — 주석(annotation), 태그, 스타일 템플릿, 리포트, 행 수준 보안 규칙 등 — 는 의도적으로 라우트 수준 데코레이터와 데이터 접근 계층 기본 필터의 소유권 범위 지정에 의존한다. 이런 리소스에 객체별 검사가 없는 것은 설계된 바이며 발견 사항이 아니다.
리소스 종류에 맞는 인가 패턴을 따랐다고 해서 그 코드에 다른 문제가 없다는 뜻은 아니다. 인젝션, 서버 측 요청 위조(SSRF), 크로스 사이트 스크립팅 등의 유형은 인가와 무관하며 별도로 평가한다.
## 자동 스캐너가 어긴 규칙과 공격자의 역할을 적게 한다
자동 스캐너 — 모델 기반 코드 스캐너, 정적 분석기, 의존성 도구 — 는 이 코드베이스에 대해 제출하는 모든 발견 사항에서 다음 두 가지를 명시해야 한다:
1. 보안 정책의 역할·권한 매트릭스에서 위반되었다고 보는 구체적인 행.
2. 공격자가 보유한다고 가정하는 주체: 익명 또는 공개 주체, 낮은 권한의 인증된 역할, 쿼리 도구 역할, 상승된 저작 역할, 관리자 역할, 임베드된 게스트 토큰, 또는 명시적 권한이 부여된 이름 있는 커스텀 역할.
이 둘을 특정할 수 없는 발견 사항은 취약점이 아니라 질문으로 제출해야 한다. 이 요건은 보고된 모든 이슈가 공개된 보안 모델에 비추어 검증 가능하도록 하고, 추측성이거나 패턴 일치에만 근거한 보고가 분류 대기열에 들어오지 않도록 하기 위해 존재한다.
## 프론트엔드와 백엔드의 코드 표준을 따른다
프론트엔드: `any`를 피하고 기존 타입을 재사용한다. 훅을 사용하는 함수형 컴포넌트로 작성한다. UI 컴포넌트는 서드파티 라이브러리를 직접 임포트하지 말고 공유 디자인 시스템 패키지에서 가져온다. 제거된 레거시 렌더러가 아니라 프로젝트의 표준 테스트 러너와 테스팅 라이브러리를 사용한다. 전역 스토어가 이미 있는 곳에서는 그것을 쓰고, 그 외에는 로컬 훅 상태를 쓴다.
백엔드: 모든 새 코드에 타입 힌트가 필요하고, 정적 타입 체커를 반드시 통과해야 하며, 데이터 모델에는 적절한 타이핑을 붙이고, 테스트에는 프로젝트의 표준 테스트 프레임워크를 사용한다. 쿼리를 작성할 때는 불리언 컬럼을 거짓 리터럴과 비교하지 말고 ORM의 부정 연산자를 사용한다. 리터럴 비교는 린터가 지적한다.
라이선스 헤더: 새 소스 파일에는 프로젝트의 표준 라이선스 헤더가 필요하다. 에이전트 지시 파일(이 파일과 벤더별 형제 파일들)은 헤더에 토큰을 쓰지 않도록 의도적으로 이 요건에서 제외된다.
주석: "now", "currently", "today" 같은 시점에 종속된 표현은 시간이 지나면 낡아지므로 피한다. 언제 읽어도 정확한 주석을 쓴다.
## 코드를 바꿀 때 문서와 호환성 파괴 변경 기록도 고친다
문서 작업은 변경의 일부이지 나중에 할 일이 아니다:
- 사용자에게 보이는 변경이 있으면 문서 트리를 갱신한다.
- 호환성을 깨는 변경은 전용 업그레이드 노트 파일에 기록해, 운영자가 한곳에서 찾을 수 있게 한다.
- 새로 만든 모든 함수와 클래스에 독스트링을 작성한다.
운영자나 최종 사용자가 관찰할 수 있는 동작을 건드리는 변경이라면, 그에 맞는 문서 수정이 없는 풀 리퀘스트는 미완성이다.
## 자동 생성되는 컴포넌트 문서는 생성기가 아니라 스토리 파일에서 고친다
개발자 포털은 컴포넌트 카탈로그의 스토리로부터 컴포넌트 문서를 자동 생성한다. 스토리가 단일 진실 공급원이며, 여기서 두 가지 규칙이 나온다. 무언가가 잘못 렌더링되면 생성기가 아니라 스토리 파일을 먼저 고칠 것, 그리고 생성기는 가볍게 유지할 것 — 생성기는 스토리 데이터를 추출해 그대로 넘기는 역할이므로, 컴포넌트별 예외 처리를 생성기에 추가하고 싶은 유혹을 참는다.
컴포넌트의 문서가 올바르게 생성되려면 그 스토리 파일이 다음을 지켜야 한다:
- 메타데이터 객체를 변수에 할당한 뒤 그 변수를 내보내지 말고, 인라인으로 기본 내보내기(default export)한다.
- 상호작용 스토리의 이름은 일관된 접두사에 컴포넌트 이름을 붙여 짓는다.
- 기본 prop 값은 스토리의 인자에 정의한다.
- 인자 타입은 메타데이터 수준이 아니라 스토리 수준에 정의하며, 컨트롤 타입과 설명을 포함한다.
- 변형(variant) 그리드, 자식 요소가 필요한 컴포넌트를 위한 샘플 자식, 커스텀 라이브 코드 블록, 인라인으로 파싱할 수 없는 복잡한 객체 prop에는 문서화된 파라미터 키를 사용한다.
문서 문제를 진단할 때는 생성기 스크립트, 그 래퍼 컴포넌트, 생성 결과 출력 디렉터리 — 이 세 가지 움직이는 부품을 염두에 둔다.
## 테스트 준비를 직접 만들지 말고 제공된 테스트 헬퍼를 쓴다
리포지토리는 헬퍼를 함께 제공한다. 셋업을 직접 짜지 말고 이를 사용한다. 백엔드에서는 공유 테스트 기반 클래스, 설정을 모킹하고 기능 플래그를 전환하는 데코레이터, 특정 역할로 로그인하기 위한 인증 헬퍼, 테스트에 필요한 픽스처를 만드는 팩토리 헬퍼가 여기에 해당한다. 프론트엔드에서는 표준 프로바이더를 설치해 주는 커스텀 렌더 헬퍼, 스토어·라우터·테마용 래퍼 팩토리, 그리고 셀렉트 상호작용 헬퍼가 해당한다.
모킹 규칙: 설정 객체에는 일반 목(mock)을 사용하고, 테스트 대상 코드가 동기 코드일 때는 비동기 목에 손대지 않는다. 모델에 새 필드가 추가되면 API 테스트의 예상 컬럼 목록을 갱신한다.
각 테스트 모음을 실행하는 방법을 알아 둔다: 프론트엔드 전체, 프론트엔드 단일 테스트 파일, 백엔드 전체, 백엔드 단일 테스트 파일, 백엔드 테스트 디렉터리, 그리고 헤드리스·인터랙티브·헤디드·디버그 모드의 엔드투엔드 모음.
백엔드 테스트가 테스트 대상 코드 때문이 아니라 데이터베이스나 환경 설정 때문에 실패한다면, 사용자의 환경을 임기응변으로 고치려 하지 말고 사용자에게 테스트 환경 셋업을 실행해 달라고 요청한다.
## 디버깅 전에 헬스 엔드포인트로 환경을 확인한다
먼저 빠른 셋업 점검을 실행한다. 애플리케이션의 헬스 엔드포인트를 호출해 응답하는지 확인한 뒤에 버그 리포트에 시간을 쓴다. 헬스 체크 실패는 대개 코드가 망가졌다는 뜻이 아니라 작업 공간이 애초에 설정되지 않았다는 뜻이다.
헬스 체크가 실패하면, 환경이 설정되지 않은 것으로 보인다고 사용자에게 알리고, 직접 환경을 고치려 하지 말고 에이전트 작업을 위한 프로젝트의 문서화된 셋업 안내로 안내한다.
방향을 잡을 때 알아 둘 핵심 프로젝트 파일: 빌드·테스트·린트 스크립트와 개발 서버 포트가 담긴 프론트엔드 패키지 매니페스트, 린터와 타입 체커 설정이 담긴 Python 프로젝트 파일, 그리고 기본용과 개발용으로 나뉜 의존성 요구사항 폴더.
## 풀 리퀘스트 템플릿을 모두 채우고 conventional commits 형식의 제목을 단다
풀 리퀘스트를 열 때:
1. 초안을 쓰기 전에 리포지토리에 있는 현재 풀 리퀘스트 템플릿 파일을 읽는다. 템플릿은 시간이 지나면서 바뀌므로, 캐시된 내용을 재사용하지 말고 항상 실제 파일을 읽는다.
2. 템플릿이 정의한 모든 섹션을 채운다 — 요약, 변경 전후 증거, 테스트 방법, 추가 정보.
3. 풀 리퀘스트 제목은 컨벤셔널 커밋 형식 `type(scope): description` 으로 짓는다. 예: `fix(dashboard): load charts correctly`. 유효한 타입은 `fix`, `feat`, `docs`, `style`, `refactor`, `perf`, `test`, `chore` 이다.
## 낯선 영역을 고치기 전에 폴더 구조와 파일 패턴을 익힌다
큰 리포지토리에서 변경을 올바른 자리에 두려면 두 가지 습관이 필요하다. 첫째, 수정 전에 디렉터리 지도를 익힌다: 백엔드 애플리케이션과 그 API 엔드포인트, 데이터 모델, 커넥터가 어느 트리에 있는지. 프론트엔드 소스와 그 컴포넌트, 차트 빌더, 대시보드, 쿼리 에디터 영역이 어느 트리에 있는지. 공유 디자인 시스템 패키지가 어디에 있는지. 그리고 테스트, 문서, 호환성 파괴 변경 로그가 어디에 자리하는지.
둘째, 새 기능이 관례적인 파일에 놓이도록 반복되는 파일 패턴을 익힌다: 데코레이터와 스키마를 생성하는 독스트링이 붙은 엔드포인트가 있는 API 모듈, 생성되는 API 명세에 반영되는 요청·응답 검증용 스키마 모듈, 트랜잭션으로 감싼 비즈니스 로직이 있는 커맨드 계층, 그리고 영속성을 담당하는 모델 계층. 생성되는 API 문서는 그 독스트링과 스키마에서 파생되므로, 독스트링을 갱신하지 않은 엔드포인트 변경은 조용히 문서 품질을 떨어뜨린다.
데이터베이스 마이그레이션에는 그들만의 관례가 있다: 마이그레이션 버전 디렉터리에 두고, 타임스탬프·리비전 해시·설명으로 이름을 지으며, 데이터베이스 엔진이 달라도 호환되도록 원시 ORM 연산 대신 공유 마이그레이션 유틸리티 헬퍼를 호출해야 한다.
끝으로, 이 리포지토리는 서로 다른 에이전트 벤더를 위한 병렬 지시 파일들을 유지한다는 점에 유의한다. 그 모두에 적용되는 규칙을 변경할 때는 이들을 일관되게 유지한다.
