Skip to content

[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, and src/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:

txt
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 CSS

src/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:

jsx
<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.md
  • docs/contracts/workout-screen-props.md

Data Contract

Session data should keep the hierarchy explicit:

js
{
  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).