[ARCHIVED 2026-08-19] 역사 자료 — 현행 규범이 아니다. 아카이브 사유와 대체 문서는 docs/README.md의 Archive 섹션을 참조.
소프트웨어 아키텍처
한국어 번역본
이 문서는 원문(영어)의 한국어 번역이다. 정본은 원문이며, 계약·게이트 판단이 갈리면 원문을 따른다. 원문: docs/archive/software-architecture-patterns.md
갱신: 2026-07-27
Barbelic은 이제 React 앱을 유일한 프런트엔드 소스로 사용한다.
이전의 바닐라(vanilla) 프런트엔드 계층은 제거되었다. src/app, src/core, src/features, src/mobile, src/desktop, src/dom, 최상위 css, 최상위 app.js를 구현 참조로 사용하지 않는다.
현재 런타임
index.html
-> src/react/vite/main.tsx
-> src/react/app.tsx
-> src/react/appController.tsx
-> src/react/mobileApp.tsx / src/react/desktopApp.tsx
-> src/react/services/*
-> src/react/ui/mobile/* / src/react/ui/desktop/*정적 웹 앱 래퍼는 그대로 남아 있다:
public/manifest.webmanifest- Vite dev/build 설정
api/auth/test-admin/session
오프라인 서비스 워커 지원은 현재 제거되어 있으며, 오프라인 지원 복원은 별도 작업이다. 앱 셸은 React다.
소유권 모델
Claude Design이 UI 표면을 소유한다:
- 화면 구성(composition)
- 플로우 연출(choreography)
- 프레젠테이션 컴포넌트
- CSS
- 로컬 UI 상태
- 독립 실행형 디자인 프리뷰용 fixture
Codex가 기능 브리지를 소유한다:
- Supabase 인증·데이터 접근
- 카카오, 구글, 애플 프로바이더 모듈과 공용 PKCE 콜백 배선
- 데이터 정규화와 영속화
- 앱 통합 콜백
- 계약 테스트
- 배포와 검증
의도된 분리는 컨테이너/프레젠테이셔널 React 구조다:
src/react/
app.tsx composition and current integration root
services/ data/auth/Supabase bridge
contracts/ living integration contracts
ui/ future Claude-owned presentational screens디자인 계약
src/react/contracts/designContract.ts는 의미론적 data-lg-* 마커의 살아 있는 정본(source of truth)이다.
규칙:
- Claude는 레이아웃, 클래스, 태그, 래퍼, 시각적 위계를 자유롭게 바꿀 수 있다.
- Codex는 CSS 클래스를 숨은 기능 계약으로 사용해서는 안 된다.
- DOM 수준의 통합 마커가 필요하면
data-lg-*를 통한다. - Claude가 마커를 추가하면 Codex가
designContract.ts에 등록한다. - React 소스가 미등록 마커를 사용하거나, 등록된 마커가
src/react에 더 이상 존재하지 않으면 테스트가 실패한다.
이 계약은 통합 표면을 보호한다. 디자인 시스템이 아니다.
데이터 경계
src/react/services/barbelicApi.ts는 앱 셸이 소비하는 타입 있는 데이터 파사드(facade)다. 구현은 목적이 좁은 도메인 서비스 모듈들에 위임한다:
src/react/services/supabaseAuth.ts: Supabase 클라이언트 생성, 프로바이더 중립 PKCE 완료 처리, 로그인 리다이렉트, 로그아웃src/react/services/auth/providers/*: 카카오, 구글, 애플의 독립적인 메타데이터/에러 모듈src/react/services/auth/socialAuthFlow.ts: 웹/iOS 공용 OAuth 시작과 code-only 콜백 파싱src/react/services/domains/authProfileDomain.ts: 인증 상태, 현재 프로필, 온보딩 프로필 데이터src/react/services/domains/workoutDomain.ts: 운동, 세션, 계획, 일일 컨디션 변경(mutation)src/react/services/domains/catalogDomain.ts: 종목 카탈로그, 아키타입(archetype), 상세, 별칭(alias), 외부 매핑src/react/services/domains/importDomain.ts: Wodup JSONL 업로드, 인입 시작, 인입 폴링src/react/services/domains/statsDomain.ts: 화면 RPC 패키지와 구체화된(materialized) 통계 read modelsrc/react/services/domains/adminDomain.ts: 관리자/디버그/내보내기 작업src/react/services/barbelicRepository.ts: 현행 단일 Supabase 계약을 위한 엄격한 어댑터src/react/services/barbelicMappers.ts: 현행 RPC 행 → 뷰 모델 매핑과 현행 쓰기 DTO 구성src/react/services/barbelicShared.ts: 공용 상수, 날짜 헬퍼, 표시 정규화
UI 파일은 Supabase나 리포지토리 모듈을 직접 임포트하는 대신, 여전히 props/콜백으로 데이터를 받아야 한다.
세션 위계
앱은 운동 데이터를 다음과 같이 저장하고 렌더링한다:
day
sessions[]
exercises[]
sets[]완료된 기록은 sessions > session_exercises > exercise_sets에서 온다.
계획되었거나 놓친 기록은 planned_sessions > planned_sets에서 온다.
삭제나 편집에서 어느 테이블이 그 행을 소유하는지 알아야 할 때, UI는 source: "sessions" | "planned_sessions"를 유지해야 한다.
사용 중인 패턴
- 컨테이너 / 프레젠테이셔널 컴포넌트(Container / Presentational Components):
src/react/ui/**에 대해 계획된 방향. - 도메인 서비스 / 리포지토리 어댑터(Domain Service / Repository Adapter): 앱 코드는
barbelicApi.ts를 호출하고, 이는 도메인 서비스에 위임하며, Supabase 읽기/쓰기는 엄격한 리포지토리 어댑터 뒤에 머문다. - 계약 모듈(Contract Module):
designContract.ts가data-lg-*마커를 실행 가능하고 테스트 가능한 상태로 유지한다. - fixture 주도 디자인(Fixture-Driven Design): Claude는
src/react/ui/fixtures/**아래에 프리뷰 데이터를 둘 수 있다. - 점진적 추출(Progressive Extraction): 기존
screens-*.jsx파일은 화면 단위로 하나씩 추출할 수 있다.
새 화면 추가하기
- 가능하면 Claude가
src/react/ui/screens/**아래에 프레젠테이셔널 화면을 만들거나 갱신한다. - Claude는 독립 실행형 프리뷰를 위해
src/react/ui/fixtures/**아래의 fixture를 사용한다. - Claude는 새로 필요한
data-lg-*마커를 PR 노트에서 요청한다. - Codex가
src/react/contracts/designContract.ts에 마커를 등록한다. - Codex가
src/react/app.tsx또는 목적이 좁은 컨트롤러에서 실제 데이터와 콜백을 배선한다. - Codex가 테스트를 갱신하고 Supabase 플로우를 검증한다.
Claude 핸드오프 규칙
Claude에게 작업을 넘길 때, Codex는 다음을 기술해야 한다:
- 화면의 목적
- 상태들
- 데이터 형태
- 필요한 콜백
- 스트레스 케이스
- 필요하다면 요구되는 의미론적 마커
사용자가 그 세부를 명시적으로 결정하지 않은 한, Codex는 간격, 팔레트, 카드 형태, DOM 중첩, 클래스 이름을 지정해서는 안 된다.