[ARCHIVED 2026-08-19] 역사 자료 — 현행 규범이 아니다. 아카이브 사유와 대체 문서는 docs/README.md의 Archive 섹션을 참조.
React App Source Architecture
Updated: 2026-06-14
This project now treats the React app as the single frontend source.
The old vanilla frontend folders were removed instead of archived. Claude Design and Codex should not use those paths as references.
Source Of Truth
- App entry:
index.html->src/react/vite/main.jsx - React surface:
src/react/ - Supabase/data facade:
src/react/services/barbelicApi.js - Supabase repository/auth/mapper modules:
src/react/services/barbelicRepository.js,src/react/services/supabaseAuth.js,src/react/services/barbelicMappers.js - Data loading and bootstrap strategy:
docs/architecture/data-loading-strategy.md - Design marker contract:
src/react/contracts/designContract.js - Web app manifest:
public/manifest.webmanifest - Offline service worker support: removed for now; restore separately if needed
Ownership Boundary
Claude Design owns:
src/react/ui/**when new pure UI modules are introduced- pure UI screens such as
src/react/ui/screens/HomeScreen.jsx,src/react/ui/screens/SessionScreen.jsx, andsrc/react/ui/screens/WorkoutFlow.jsx src/react/ui/styles/**- presentation markup, component hierarchy, visual state, layout, animation, and fixture previews
Codex owns:
src/react/services/**src/react/contracts/**- data hydration, Supabase reads/writes, auth, persistence, and tests
- container wiring that passes props/callbacks into pure UI screens
Target Direction
The near-term migration is container/presentational separation inside React:
src/react/
app.jsx thin compatibility export for GymApp
appController.jsx current composition root
vite/
main.jsx Vite entry and viewport shell
services/
barbelicApi.js ESM data/auth facade
barbelicRepository.js Supabase reads/writes
supabaseAuth.ts Supabase client and provider-neutral auth helpers
barbelicMappers.js DB row <-> app data mapping
barbelicShared.js shared constants and pure helpers
contracts/
designContract.js living data-lg contract
ui/
screens/
SessionScreen.jsx Claude-owned presentational screen
HomeScreen.jsx Claude-owned presentational screen
RecordsDetail.jsx Claude-owned record detail screen
PrTools.jsx Claude-owned PR management screens
ProfileScreen.jsx Claude-owned profile presentational screen
fixtures/
sessionFixture.js Claude preview data
styles/
styles.css Claude-owned app CSS
session.css future Claude-owned screen CSSsrc/react/ui/** should not import Supabase, barbelicApi, or persistent storage. It may keep local UI-only state such as open panels, inline editors, swipe position, drag state, modal state, and transient toast display.
Server data changes move through props/callbacks:
<SessionScreen
today={today}
visibleMonth={visibleMonth}
sessionsByDate={sessionsByDate}
selectedDate={selectedDate}
selectedDateSessions={selectedDateSessions}
selectedSession={selectedSession}
conditionByDate={conditionByDate}
monthSummary={monthSummary}
onSelectDate={handleSelectDate}
onChangeMonth={handleChangeMonth}
onGoToday={handleGoToday}
onOpenSession={handleOpenSession}
onCloseSession={handleCloseSession}
onCreatePlan={handleCreatePlan}
onEditPlan={handleEditPlan}
onStartWorkout={handleStartWorkout}
onUpdateSession={handleUpdateSession}
onDeleteSession={handleDeleteSession}
onSetCondition={handleSetCondition}
/>Frozen screen props contracts are documented in:
docs/contracts/session-screen-props.mddocs/contracts/workout-screen-props.md
Data Contract
Session data should keep the hierarchy explicit:
{
id: "uuid",
source: "sessions",
status: "completed",
date: "2026-06-09",
title: "벤치프레스 외 1종목",
summary: "2종목 · 5세트",
exercises: [
{
id: "exercise-id",
name: "벤치프레스",
review: "오늘은 락아웃이 안정적이었음",
sets: [
{ id: "set-id", reps: 5, load: 60, difficulty: null, memo: "" }
]
}
]
}Use source: "sessions" for completed workout records and source: "planned_sessions" for planned or missed records when that distinction matters.
Design Contract
src/react/contracts/designContract.js is the source of truth for data-lg-* markers.
Claude may request new markers in a PR description, but Codex registers them in the contract and keeps the tests passing. The marker contract is a functional integration surface, not a layout or visual constraint.
For the SessionScreen pilot, Claude should keep source: "sessions" | "planned_sessions" in session objects and call onDeleteSession(session), not onDeleteSession(sessionId).