4주 만에 풀스택 F1 판타지 플랫폼을 만들었습니다 — 혼자, AI 에이전트와 함께

발행: (2026년 2월 8일 오전 11:27 GMT+9)
22 분 소요
원문: Dev.to

Source: Dev.to

번역을 진행하려면 전체 텍스트를 제공해 주시겠어요?
코드 블록, URL 및 마크다운 형식은 그대로 유지하면서 본문만 한국어로 번역해 드리겠습니다.

소개

이 게시물은 원래 binaryroute.com에 게재되었습니다.

2025년 12월 말, 짧은 연휴를 맞아 노트북을 열고 간단한 아이디어를 떠올렸습니다 — 팬으로서 늘 원하던 F1 판타지 리그 플랫폼을 만들자는 생각이었습니다.

4주가 지나 Formula1.Plus가 라이브되었습니다:

  • 70 개 이상의 데이터베이스 테이블
  • 30 개 이상의 API 모듈
  • 레이스 예측, 실시간 리더보드, 개인 리그, 텔레메트리 대시보드, 뉴스 집계, 커뮤니티 기능, 그리고 완전한 관리자 패널

모두 한 명의 개발자가 직접 구축하고 배포했습니다.

이 게시물은 제가 어떻게 이를 구현했는지에 대한 기술적인 walkthrough이며, 처음 만든 프레임워크, 선택한 스택, 가능하게 만든 AI 워크플로우, 그리고 다르게 할 점들을 다룹니다.

Solo Full‑Stack 개발의 문제

혼자서 풀스택 제품을 만들려고 시도해 본 적이 있다면 그 고통을 잘 알 것입니다. 당신은 다음 역할을 모두 맡게 됩니다:

  • 아키텍트
  • 프론트‑엔드 개발자
  • 백‑엔드 개발자
  • DBA
  • DevOps 엔지니어
  • QA 테스터

한 번에 모두 말이죠.

컨텍스트 전환마다 시간이 소모됩니다. 제품보다 인프라 구축에 더 많은 시간을 쓰게 되고, 프로젝트는 지연되거나 범위가 축소되고, 중간에 번아웃이 오기도 합니다.

이러한 범위의 프로젝트—예측 엔진, 스코어링 시스템, 리더보드, 리그, 의미 검색이 포함된 뉴스 집계, 텔레메트리 대시보드, 백그라운드 작업 처리, 패스키 인증—는 6개월 간의 고된 작업이 될 것입니다. 아마도 3개월 차에 포기되었을 겁니다.

두 가지가 상황을 바꾸었습니다:

  1. 보일러플레이트를 없애기 위해 제가 만든 프레임워크.
  2. 페어 프로그래머 역할을 하는 AI 에이전트.

ProjectX – 보일러플레이트‑버스팅 프레임워크

F1 코드를 한 줄도 작성하기 전에, 나는 ProjectX를 만들었다 — CLI가 포함된 의견이 강한 풀‑스택 TypeScript 프레임워크다.

아이디어: 데이터베이스 스키마를 한 번 정의하고, 명령 하나만 실행하면 모든 것이 자동으로 생성된다.

projectx crud --models drivers,races,predictions

그 하나의 명령은 다음을 생성한다:

  • Hono를 사용한 API 라우트, Zod를 통한 입력 검증 포함
  • 비즈니스 로직 및 권한 훅을 포함한 서비스 레이어
  • Drizzle ORM 쿼리를 사용하는 리포지토리 레이어
  • 적절한 캐시 키를 가진 프론트엔드용 TanStack Query 훅
  • 서비스 레이어용 유닛‑테스트 스캐폴드

모두 타입‑안전하며, 의존성 주입으로 연결된다. 수동으로 API 타입을 정의할 필요가 없으며, 프론트엔드는 Hono의 타입드 클라이언트를 통해 백엔드에서 라우트 타입을 바로 가져온다.

아키텍처 다이어그램 (단순화)

HTTP Layer (Hono Routes)

Middleware (Auth, Rate Limiting, Logging, Caching)

DI Container

Service Layer (Business Logic + Authorization)

Repository Layer (Drizzle ORM)

PostgreSQL

모든 기능이 이 패턴을 따르며, 각 기능마다 자체 폴더를 가진다. 나중에 사용한 AI 에이전트들은 구조가 어디서든 일관적이었기 때문에 즉시 이 구조를 탐색할 수 있었다.

Repository Layout

f1plus/
├── apps/
│   ├── api/          # Hono backend
│   └── web/          # TanStack Start frontend
├── packages/
│   ├── db/           # Drizzle schemas + migrations
│   ├── db-sync/      # F1 data synchronization
│   ├── types/        # Shared TypeScript types
│   ├── ui/           # shadcn/ui component library
│   ├── emails/       # React Email templates
│   ├── env/          # Zod‑based env validation
│   └── tsconfig/     # Shared TS configs

일곱 개의 공유 패키지, 두 개의 앱, 하나의 pnpm 워크스페이스. 모든 것이 타입을 공유하므로, 흐트러짐이 없습니다.

이 구조는 가장 중요한 결정이었습니다. 새로워서가 아니라 and the AI agents와 제가 첫 날부터 예측 가능한 코드베이스를 가질 수 있었기 때문입니다.

Source:

스택 선택 및 이유

TanStack Start

  • SSR‑ready
  • TanStack Router 로 파일 기반 라우팅
  • 데이터 페칭을 위한 TanStack Query 내장

라우팅은 완전한 타입 안전성을 제공합니다 — 라우트 파라미터, 검색 파라미터, 로더 모두 타입이 지정됩니다. 백엔드의 Hono 타입드 클라이언트와 결합하면 데이터베이스부터 컴포넌트까지 수동으로 타입을 정의하지 않아도 엔드‑투‑엔드 타입 안전성을 얻을 수 있습니다.

// Frontend hook — generated by ProjectX CLI
export function useDriverStandings(seasonId: string) {
  return useQuery({
    queryKey: ['driver-standings', seasonId],
    queryFn: () => api.standings.drivers.$get({ query: { seasonId } }),
  })
}

쿼리 함수는 Hono 라우트 정의에서 타입이 추론됩니다. API 응답 형태가 바뀌면 TypeScript가 프론트엔드에서 즉시 오류를 잡아줍니다.

Tailwind v4 + CSS Custom Properties

다음과 같은 디자인 토큰을 정의했습니다:

--f1-bg-card;
--f1-bg-secondary;
--f1-border;
--f1-text;
--f1-text-muted;
--f1-red;

이 토큰들은 라이트 모드와 다크 모드에서 각각 다른 값을 가집니다. 모든 컴포넌트가 하드코딩된 색상 대신 이 토큰을 사용하므로 컴포넌트 별 오버라이드 없이 전체 UI를 테마화할 수 있습니다.

shadcn/ui

접근성을 갖춘, 스타일이 없는 프리미티브를 제공하며 직접 커스터마이징합니다. 의존성 락‑인 없이 F1 미학에 맞게 모든 컴포넌트를 수정했습니다.

Hono

15 KB 규모의 웹 프레임워크로 Node, Cloudflare Workers, Deno, Bun 어디서든 실행됩니다. 선택 이유는 세 가지입니다:

  1. Typed routeshono/client 로 런타임 오버헤드 없이 타입 추론이 가능합니다.
  2. Middleware composition — 속도 제한, 인증, 로깅, 바디 제한, CORS 등 모든 미들웨어를 조합할 수 있습니다.
  3. Performance — 실제로 측정했을 때 매우 빠릅니다.
// Rate limiting tiers
const rateLimits = {
  global:   { max: 200, window: '1m' },
  mutations:{ max: 30,  window: '1m' },
  expensive:{ max: 20, window: '1m' },
}

Drizzle ORM

Raw SQL과 무거운 ORM 사이의 최적점입니다. 타입‑안전한 쿼리, 런타임 오버헤드 제로, 스키마 정의가 순수 TypeScript로 이루어집니다.

export const drivers = pgTable('drivers', {
  id:          text('id').primaryKey(),
  name:        text('name').notNull(),
  abbreviation:varchar('abbreviation', { length: 3 }),
  nationality: text('nationality'),
  dateOfBirth: date('date_of_birth'),
  // …
})

pgvector + HuggingFace Transformers

뉴스 기사에 대한 시맨틱 검색을 구현했습니다 — Transformers 로 기사 임베딩을 만들고 유사도 기반으로 조회합니다. 이를 통해 사용자는 키워드가 아니라 의미로 F1 뉴스를 검색할 수 있습니다.

백그라운드 작업 워커

작업자책임
Scoring레이스 점수를 계산하고 리더보드를 업데이트
News SyncF1 뉴스 기사들을 가져와 처리
EmailReact Email + Resend 로 트랜잭션 이메일 전송
F1DB SyncGitHub 에서 커뮤니티가 유지하는 오픈소스 F1 데이터셋 F1DB 로부터 히스토리 데이터를 자동 동기화
Task일반 목적 비동기 작업

AI 페어‑프로그래밍 워크플로우

  1. 프롬프트 생성 – 원하는 기능을 자연어로 설명했습니다.
  2. 코드 스캐폴드 – AI가 골격(CLI 명령, 파일 레이아웃)을 만들었습니다.
  3. 반복적 정제 – 구체적인 내용(검증, 인증 훅, 테스트)을 요청했습니다.
  4. 리뷰 및 병합 – 차이를 검토하고, 테스트를 실행한 뒤 병합했습니다.

ProjectX가 일관되고 예측 가능한 구조를 강제했기 때문에, AI는 올바른 파일을 신뢰성 있게 찾고, 올바른 타입을 임포트하며, 기존 컨벤션을 준수할 수 있었습니다.

내가 다르게 할 점

영역원래 접근 방식수정된 접근 방식
Testing유닛 테스트 스캐폴드를 생성했지만, 나중에 대부분의 테스트를 수동으로 작성했습니다.서비스 레이어에 대해 처음부터 property‑based testing (fast‑check)을 도입합니다.
CI/CD간단한 GitHub Actions 워크플로우.Vercel/Cloudflare Pages를 사용해 PR당 preview deployments를 추가하여 UI 회귀를 조기에 포착합니다.
Observability기본 콘솔 로그.OpenTelemetry + Loki/Grafana를 통합하여 API 호출 및 백그라운드 작업의 분산 추적을 구현합니다.
Feature Flags하드코딩된 토글.LaunchDarkly 스타일의 플래그 라이브러리를 사용해 새로운 스코어링 알고리즘을 점진적으로 롤아웃합니다.
DocumentationREADME + 인라인 주석.typedoc + swagger-ui를 사용해 Hono 라우트 타입으로부터 API 문서를 자동 생성합니다.

마무리 생각

프로덕션 수준의 풀스택 판타지 리그 플랫폼을 혼자 구축하는 것은 벅차지만, 다음과 함께라면:

  • 의견이 강한, 코드‑생성 프레임워크(ProjectX)로 보일러플레이트를 제거하고,
  • AI 에이전트가 페어 프로그래머 역할을 하며, 그리고
  • 잘 선택된, 타입‑안전 스택(TanStack Start, Hono, Drizzle, shadcn/ui),

노력 소요 시간이 몇 달에서 몇 주로 줄어듭니다.

혼자 풀스택 모험을 시작한다면, 아키텍처를 표준화하고 반복적인 스캐폴딩에 AI를 활용하는 것부터 시작하세요. 나머지는 훨씬 원활하게 진행될 것입니다.

코딩 즐겁게!

Generic Async Tasks

Bull Board는 모든 큐를 모니터링할 수 있는 관리자 대시보드를 제공합니다.

BetterAuth는 OAuth(Google, Discord, X)와 Passkey/WebAuthn 지원을 처리합니다.
Passkey는 인증의 미래입니다 — 비밀번호가 없고, 피싱에 강하며, 생체인식이 가능합니다.
설정하는 데는 한 오후면 충분했습니다.

4주를 가능하게 만든 부분

전체 빌드 과정에서 Claude Code, OpenAI Codex, Gemini를 사용했습니다 — 자동완성이 아니라 전체 코드베이스를 컨텍스트로 유지할 수 있는 협업 파트너로서였습니다.

  • Claude Code는 핵심 개발자 역할을 했습니다 — 레포지토리 안에서 직접 코드를 작성하고, 리팩터링하고, 디버깅했습니다.
  • Claude, Codex, Gemini는 설계자 역할을 했습니다: 비트루비얼한 기능마다 여러 모델의 관점을 모아 최종 구현 계획을 확정하는 광범위한 설계 과정을 거쳤습니다. 모델마다 잡아내는 엣지 케이스가 다르고, 그 겹침이 신뢰성을 높여줍니다.

Feature Scaffolding

특정 기능을 설명하면(예: “사용자가 각 레이스마다 드라이버를 선택하고, 주간 보너스 포인트를 위한 lock‑of‑the‑week 메커니즘을 갖춘 예측 시스템 추가”) 에이전트가 다음을 생성합니다:

  • 스키마
  • 서비스
  • 라우트
  • 검증
  • 프론트엔드 훅

첫 번째 시도에서 완벽하지는 않지만 약 80 % 정도는 됩니다. 검토하고, 조정하고, 반복합니다.

Parallel Code Reviews

50개 이상의 컴포넌트 파일을 하드코딩된 bg-white/10 불투명도 패턴에서 라이트 모드 지원을 위한 CSS 커스텀 프로퍼티로 마이그레이션해야 할 때, 세 개의 AI 에이전트를 동시에 실행했습니다 — 각각 파일 배치를 담당하고 동일한 매핑 가이드를 따랐습니다. 하루가 걸릴 일련의 지루한 찾기‑바꾸기가 몇 분 안에 일관된 결과로 완료되었습니다.

Debugging

예시: 트랙‑서킷 SVG 컴포넌트에 8개의 중첩 CSS drop-shadow 필터가 겹쳐져 블러 효과가 발생했습니다. 에이전트는 근본 원인(각 필터가 이전 모든 필터의 누적 결과에 적용됨)을 찾아내고, 아웃라인 시스템을 제거하고, 스트로크 두께를 조정했습니다 — 이 작업을 제가 직접 하면 한 시간이 걸렸을 수도 있습니다.

Consistency

코드베이스가 50개 이상의 컴포넌트를 넘어가면서 AI는 패턴을 일관되게 유지했습니다:

  • 동일한 네이밍 규칙
  • 동일한 파일 구조
  • 동일한 검증 방식

보통 솔로 개발자는 여기서 코너를 자르기 시작하지만, AI는 그렇지 않았습니다.

핵심 인사이트: AI 에이전트는 여러분이 제공하는 패턴만큼만 좋습니다.

ProjectX의 의견이 반영된 아키텍처는 AI에게 가드레일을 제공했습니다:

  • 서비스는 features/<name>/<name>.service.ts에 위치
  • 검증은 features/<name>/validations.tsZod 스키마 사용
  • 라우트는 얇게 – 서비스에 위임
  • 프론트엔드 훅은 TanStack Query 규칙을 따름

그 일관성이 없었다면, 여러분은 단지 스파게티 코드를 더 빠르게 생성하고 있었을 겁니다. 이 프레임워크는 저만을 위한 것이 아니라 AI를 위한 것이기도 했습니다.

배포 스토리

TanStack Start는 Vite 플러그인을 통해 Cloudflare Workers에 빌드됩니다. 프론트엔드는 엣지에서 실행되며 전 세계에 배포되어 거의 제로에 가까운 콜드 스타트를 가집니다.

  • 비용: 이 규모에서는 사실상 무료이며, Cloudflare의 무료 티어가 관대합니다.

Railway는 Hono API, PostgreSQL, Redis를 실행합니다. Docker 멀티‑스테이지 빌드로 이미지가 가볍게 유지됩니다. 헬스 체크, 자동 재시작, 배포 프리뷰가 기본 제공됩니다.

railway.toml

[deploy]
healthcheckPath = "/health/ready"
healthcheckTimeout = 30
restartPolicyType = "on_failure"
restartPolicyMaxRetries = 5

두 가지 워크플로

  1. CI – 모든 PR마다 린트, 타입‑체크, 빌드, 테스트 수행
  2. Deploy – 수동 트리거, 먼저 마이그레이션을 실행하고, 그 다음 API를 Railway에, 프론트엔드를 Cloudflare에 배포
Push to main → CI passes → Trigger deploy →
  Run migrations → Deploy API (Railway) → Deploy Web (Cloudflare)

전체 프로덕션 인프라스트럭처 — API 서버, PostgreSQL, Redis, 엣지에 배포된 프론트엔드, CI/CD —는 약 $20 / 월(또는 서버리스 데이터베이스와 Redis 옵션을 사용할 경우 약 $10 / 월) 정도의 비용이 듭니다. Kubernetes도 없습니다. Terraform도 없습니다. DevOps 엔지니어도 필요 없습니다.

4주 동안 출시된 내용

예측 및 점수 매기기

  • 드라이버와 팀 선택이 포함된 레이스 예측
  • 대담한 예측을 위한 Lock‑of‑the‑week 메커니즘(보너스 포인트)
  • 최하위 선택, 팀 상위 3위, 보너스 선택
  • 백그라운드 워커를 통한 자동 점수 엔진

리더보드 및 리그

  • 전체 기간 및 챔피언십 별 순위가 포함된 실시간 리더보드
  • 초대 코드로 참여하는 비공개 리그
  • 리그별 리더보드 및 순위표

텔레메트리 및 데이터

  • 드라이버 DNA 분석 및 퍼포먼스 분석
  • F1DB(커뮤니티가 유지하는 오픈소스 데이터셋)에서 자동 동기화되는 히스토리 데이터
  • 과거 결과와 통계가 포함된 서킷 프로필
  • Recharts 기반 시각화

커뮤니티

  • Grand Stand — 설문, 토론, 커뮤니티 참여
  • 의미 검색(pgvector)이 적용된 뉴스 집계
  • 활동 피드 및 소셜 기능

관리자

  • 이벤트 관리 및 예측 설정
  • Bull Board를 통한 큐 모니터링
  • 감사 로그, 연락처 관리, 설문 템플릿

인증 및 인프라

  • OAuth(Google, Discord, X) + Passkey/WebAuthn
  • 레이트 리밋(계층형: 전역, 변이, 고비용 쿼리)
  • 분산 추적을 위한 OpenTelemetry
  • Pino를 이용한 구조화 로그

F1 시즌이 다가오고 있으며, 라운드 1 전에 초기 사용자를 확보하고 있습니다.

ProjectX – 오픈소스로 전환

ProjectX – 이 가능성을 만든 프레임워크 –가 곧 오픈소스로 공개됩니다. 단일 모노레포 CLI로 웹, 모바일, 그리고 브라우저 확장을 즉시 사용할 수 있는 전체 아키텍처와 함께 스캐폴딩합니다.

Features include:

  • Plugin system → 플러그인 시스템
0 조회
Back to Blog

관련 글

더 보기 »

Node.js와 Redis를 활용한 멱등 API

Idempotent APIs in Node.js with Redis의 커버 이미지 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2...