규칙
클라이언트
클라이언트
모든 앱이 같이 따르는 것. 앱마다의 구조 · 명령 · 서버 부르는 방식은 그 앱의 AGENTS.md(clients/apps/<앱>/).
clients/폴더 구조
- React · Vue · Next · 순수 TS · Expo · Tauri
- 각 앱이 서버의 타입으로 API 를 호출하는 공통 클라이언트입니다.
- 클라이언트 앱과 패키지가 공유하는 린트 · 포맷 설정입니다.
- 정적 웹 파일을 제공하고 /api 요청을 서버로 전달합니다.
선택한 경로
서버 부르기
TS 앱은 부를 서버마다 클라이언트를 하나 만든다. 모든 서버의 타입이 열려 있지만 경로마다 생기는 코드는 없어서
API 가 늘어도 번들은 그대로다. 다른 언어 앱은 contract/openapi/<서버>.json 에서 클라이언트를 생성한다 (contracts.md).
import { createClient, type notes } from '@app/client'
const api = createClient<notes.paths>({ name: 'notes', base: 'http://127.0.0.1:8003' }) // name · base(gateway) · fetch 는 선택
await api.get('/api/notes') // 경로 · 응답 타입은 notes 서버 문서에서
await api.post('/api/notes', { text }) // 201 본문(만든 메모)을 돌려준다. put 은 (경로, 본문, { params })
await api.delete('/api/notes/{id}', { params: { id } }) // 경로 변수가 있으면 params 가 필수(빼면 타입 오류), 204 는 void
useQuery(api.query('/api/notes')) // TanStack Query (React · Vue). 키 = [name, 경로, params, query]
name: 쿼리 키의 첫 칸. 경로가 같은 서버가 둘이어도 캐시가 섞이지 않게. 주소가 아니라 이름이라 서버 렌더링(절대 주소)과 브라우저(상대 경로)의 키가 같다.base: 같은 출처(프록시)면 생략, 네이티브 앱 · 서버 렌더링은 서버 주소.fetch: CORS 없는 fetch 가 필요할 때(Tauri).- 주소는 gateway 하나다(
servers/gateway). 같은 출처 프록시 · nginx 는/api를API_URL(gateway)로 넘기고, gateway 가 경로 접두사로 서버를 고른다. 네이티브 앱의base도 gateway 주소다. - 서버를 둘 이상 부르면 서버마다 클라이언트를 하나씩 만든다(타입이 서버마다라서). admin 은
createClient<tags.paths>({ name: 'tags' })·createClient<activity.paths>({ name: 'activity' }).
서버 데이터
- TanStack Query (
@tanstack/react-query·@tanstack/vue-query). 쿼리 옵션은 손으로 짜지 않고api.query()를 쓴다. - 만들기 · 고치기 · 지우기 뒤에는
invalidateQueries({ queryKey: api.query('/api/notes').queryKey })로 목록을 다시 받는다. - 프레임워크가 없는 앱(lite · desktop)은
api.get·post·put·delete그대로. - API 응답 문자열은 텍스트로만 렌더한다 (
innerHTML·v-html·dangerouslySetInnerHTML금지, hook 이 막는다).
의존성 · 도구
- 버전은
pnpm-workspace.yaml카탈로그 한 곳에서 ("react": "catalog:"). Expo 가 정하는 버전은catalog:expo(올릴 때npx expo install --fix), TS 의 JS API 가 필요한 도구(admin 의 vue-tsc · site 의 next build)는catalog:ts6. 서버는 카탈로그를 쓰지 않는다. react·react-dom은 워크스페이스 전체가 정확히 같은 한 버전(Expo 가 정한 것)이다.^범위로 두면 pnpm 이 둘을 따로 골라, 테스트 · 빌드는 통과하고 브라우저에서만 화면이 빈다.- 모든 패키지에
lint(oxlint && oxfmt --check) ·format, 앱에는typecheck. 기본은 TS 7(tsc -p .). TS 의 JS API 를 쓰는 도구가 있으면 그 앱만 자기 TS 를 둔다(TS 7 에는 아직 안정된 JS API 가 없다). - 웹 앱(web · admin · site · lite)은
Dockerfile이 있다. 정적 앱은 nginx 가/api를 gateway 로 넘기고(nginx.conf.template), site(Next)는 standalone. mobile · desktop 은 네이티브 빌드라 이미지가 없다 (development.md 의 “이미지”). - 새 앱은 guides/add-app.md.
UI
색 · 글자 · 간격 · 둥글기 · 컴포넌트와 그 쓰임은 저장소 루트의 DESIGN.md 가 기준이다
(DESIGN.md 형식: 앞의 YAML 이 값, 본문이 규칙). 새 값이 필요하면 거기 먼저 더하고,
pnpm dlx @google/design.md@0.4.0 lint DESIGN.md 로 확인한다.