본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 09. 17:08

하드코딩된 운동 루틴을 Claude 생성 플랜 시스템으로 교체하기

요약

SwiftUI 운동 앱의 고정된 루틴을 Claude 기반의 AI 플래닝 시스템으로 교체하는 개발 과정을 다룹니다. 사용자의 장비, 목표, 건강 데이터를 기반으로 JSON 형태의 맞춤형 운동 플랜을 생성하고 이를 로컬 SwiftData에 저장하는 아키텍처를 설명합니다.

핵심 포인트

  • Claude를 활용해 정적 루틴을 동적 AI 플랜으로 전환
  • JSON 스키마를 강제하는 '지루한 프롬프트' 설계 전략
  • Supabase Edge Function을 통한 보안 및 비용 제어
  • 생성된 데이터는 SwiftData를 통해 온디바이스로 관리

이번 주에 저는 SwiftUI 운동 앱의 고정된 루틴 부분을 뜯어내고, 작은 AI 플래닝 시스템 (AI planning system)으로 교체하는 작업을 진행했습니다.

단순히 옆에 챗봇 (chatbot)을 붙여놓은 것이 아닙니다. 앱이 목표를 묻고, 압축된 실제 제약 조건 세트를 읽은 뒤, 백엔드 함수를 통해 Claude를 호출하고, 결과로 나온 7일간의 플랜을 SwiftData에 로컬로 저장하는 방식입니다.

이전 버전은 단순했습니다. 두 개의 하드코딩된 (hardcoded) 밀기/당기기 (push/pull) 루틴과 고정된 운동 라이브러리가 있었죠. 프로토타입으로는 괜찮았지만, 너무 경직되어 있었습니다. 만약 사용자가 25kg까지의 덤벨만 가지고 있고, 일주일에 3일만 운동하며, 지난주에 잠을 잘 못 잤다면, 앱은 무언가를 제안하기 전에 그 사실을 알아야 합니다.

새로운 흐름은 다음과 같습니다:

  1. 사용자가 장비를 한 번 설정합니다.
  2. 사용자가 300자 이내로 목표를 입력합니다.
  3. 권한이 있다면 앱이 작은 HealthKit 요약 정보를 읽습니다.
  4. Supabase Edge Function이 인증 및 구독 상태를 확인합니다.
  5. Edge Function이 Claude를 호출합니다.
  6. 앱이 반환된 JSON을 SwiftData 모델로 파싱 (parse) 합니다.
  7. watchOS 세션 트래킹 (session tracking)은 생성된 플랜의 날짜를 사용합니다.

중요한 부분은 프롬프트 (prompt)의 형태입니다. 저는 모델로부터 산문 형태의 답변을 받고 싶지 않았습니다. 앱 데이터가 필요했습니다.

const userMessage = `Goals: ${(goals as string).slice(0, 300)}
Equipment: ${(equipment as string[]).join(", ")}
Available weights (kg): ${(weights as number[]).join(", ")}${healthContext}
...

시스템 프롬프트 (system prompt)는 의도적으로 지루하게 작성했습니다:

제공된 스키마 (schema)와 일치하는 유효한 JSON만 출력하세요.
설명 금지. 마크다운 펜스 (markdown fences) 금지.
운동 설명: 최대 1문장.
...

그 지루한 프롬프트가 바로 제품 결정 (product decision)입니다. UI에는 동기 부여를 위한 미사여구가 필요하지 않습니다. 대신 렌더링할 수 있고, 나중에 편집할 수 있으며, 워치에서 추적할 수 있는 PlanDay, WarmupExercise, PlannedExercise 행(row)이 필요합니다.

응답 스키마 (response schema)는 인라인 (inline)으로 구성되어 로컬 모델에 직접 매핑됩니다:

{
  "planName": "string",
  "days": [
...

또한, iOS에서 Claude를 직접 호출하는 대신 API 호출을 서버 측 게이트웨이 (server-side gateway) 뒤에 배치했습니다. 이를 통해 세 가지 유용한 제어권을 얻을 수 있습니다:

  • 생성 전 JWT 검증 (JWT verification)
  • 토큰 소모 전 구독 확인 (subscription check)
  • 사용자별 월간 사용량 추적 (monthly usage tracking)

현재 제한은 월 10회의 플랜 생성입니다. 압축된 프롬프트 (compact prompt)를 사용하여, 생성당 목표 예산은 대략 입력 토큰 800개와 출력 토큰 600개입니다. 이를 통해 모바일 텍스트 필드가 무제한 청구서 생성기가 되는 대신, AI 비용을 예측 가능한 수준으로 유지할 수 있습니다.

여기서 온디바이스 (On-device) 방식은 여전히 중요합니다. 생성된 플랜, 세션 로그, 장비 인벤토리, 그리고 활성화된 플랜 상태는 SwiftData에 로컬로 저장됩니다. 네트워크는 오직 새로운 플랜을 생성할 때만 사용됩니다. 운동을 실행하는 것이 API의 온라인 상태 여부에 의존해서는 안 됩니다.

교훈: 모델의 응답을 단순한 콘텐츠로 취급하는 대신, 타입이 지정된 경계 (typed boundary)로 취급하기 시작하면 AI 기능을 출시하는 것이 훨씬 쉬워집니다.

프롬프트 입력. JSON 출력. 검증, 저장, 렌더링, 추적.

이는 채팅 UI보다 마법 같은 느낌은 덜하지만, 소프트웨어에 훨씬 더 가깝습니다.

출처: 최근 SwiftUI/watchOS 앱 작업: 하드코딩된 루틴을 Claude 기반의 7일 플랜 생성기, HealthKit 요약 입력, Supabase Edge Function 게이트웨이, SwiftData 로컬 저장소 및 월간 사용량 제한으로 교체함.

태그: ai, swift, ios, claude

상태: 게시됨

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0