
명세 기반 개발 (SDD)을 통한 방치된 사이드 프로젝트의 부활
요약
방치된 사이드 프로젝트를 명세 기반 개발(SDD) 방식을 통해 현대적인 기술 스택으로 재구축한 경험을 공유합니다. 기존 Prismic CMS 기반의 Next.js 앱을 Supabase와 App Router로 마이그레이션하며 얻은 실무 가이드를 제공합니다.
핵심 포인트
- 명세 기반 개발(SDD)을 통한 프로젝트 재구축 방법론
- Prismic CMS에서 Supabase(PostgreSQL)로의 백엔드 마이그레이션
- Next.js Pages Router에서 App Router로의 스택 현대화
- 데이터 자동화를 위한 PDF 파싱 및 API 통합 계획
이 글은 GitHub Finish-Up-A-Thon Challenge를 위한 제출물입니다.
제가 Finish-Up-A-Thon에 참여하기로 결정했을 때 두 가지 목표가 있었습니다. 바로 여전히 애착을 가지고 있는 방치된 사이드 프로젝트를 부활시키는 것과, 이를 명세 기반 개발 (Spec-Driven Development, SDD)을 배우는 기회로 삼는 것이었습니다.
이 포스트는 프로젝트 회고이자 SDD에 대한 실무 가이드이기도 하며, 현대화된 스택으로 애플리케이션을 어떻게 재구축하고 수년간 미완성 상태로 남겨두었던 아이디어들을 어떻게 구현했는지 공유할 예정입니다.
내가 만든 것
이전 프로젝트 링크: https://recipe-library-prismic.vercel.app
이 프로젝트는 제가 2020년에 만든 개인용 레시피 웹사이트였습니다. 레시피 콘텐츠를 저장하고 표시하기 위해 Prismic 헤드리스 CMS (headless CMS)를 백엔드로 사용하는 간단한 Next.js 앱이었습니다. 수년 동안 이 앱은 큐레이션된 목록(다음에 요리할 것, 즐겨찾기, 최근 추가됨, 랜덤 추천), 레시피 검색, 태그 필터링 기능을 갖춘 레시피 라이브러리 역할을 했습니다. 그러다 점차 매주 무엇을 요리할지 결정하고, 식료품 쇼핑 계획을 세우며, 좋아하는 레시피를 기록하는 데 제가 의존하는 도구가 되었습니다. 개인적으로 제가 가장 좋아하는 기능은 식재료를 통로(aisle)별로 정리해 주는 식료품 쇼핑 목록인데, 이 기능 덕분에 식료품점에서 생활이 훨씬 편리해집니다.
앱을 계속 사용했음에도 불구하고, 저는 수년 전 코드베이스와 CMS의 유지보수를 중단했습니다. 새로운 레시피를 추가할 때마다 재료, 조리법, 메타데이터를 CMS에 수동으로 복사해야 했습니다. 결국 라이브러리를 유지하는 것이 새로운 레시피를 추가함으로써 얻는 가치보다 더 많은 수고를 필요로 하게 되었습니다.
"이전" 스택
- Next.js 13 (Pages Router)
- Prismic API
잃어버린 로드맵
저는 앱을 유지보수하며 느꼈던 가장 큰 답답함들을 해결하기 위한 개선 사항들을 수년 동안 머릿속에 목록으로 간직해 왔습니다:
- 더 많은 제어권과 유연성을 확보하기 위해 백엔드를 Prismic (호스팅형 헤드리스 CMS)에서 Supabase (PostgreSQL 플랫폼)로 마이그레이션 (Migrate) 하기.
- 레시피를 가져오고 PDF에서 텍스트를 직접 파싱 (Parsing) 하여 데이터베이스 입력을 자동화하기.
- 지역 상점 간의 식재료 비용을 비교하기 위해 식료품 가격 API 통합하기. (네, 이것은 유지보수 기능이라기보다는 '있으면 좋은' 아이디어에 가까웠습니다... 하지만 꿈을 꿀 수는 있으니까요.)
이것들은 제가 구현할 시간이나 에너지가 없을 것이라고 생각했던 개선 사항들이었습니다. 하지만 이제는 다릅니다!
데모 (Demo)
아래에서 프로젝트 링크와 GitHub 리포지토리 (Repository)를 확인하실 수 있습니다. 포스트 후반부에서 각 구현 사항과 관련된 풀 리퀘스트 (Pull Request) 및 비디오 데모를 제공하겠습니다.
새 프로젝트 링크: https://recipe-library-nextjs-supabase.vercel.app
리포지토리 (Repository): https://github.com/karlyhoffman/recipe-website
변경된 기술 스택 (The "After" Stack)
- Next.js 16 (App Router)
- Supabase (PostgreSQL)
- JSON Web Tokens (JWT)
- PDF Parser
- Anthropic AI SDK
- Kroger Pricing API
컴백 스토리 (The Comeback Story)
명세 기반 개발 (SDD)의 구원
저는 최근 명세 기반 개발 (Spec-Driven Development, SDD)에 대해 알게 되었고, 그 이후로 완전히 매료되었습니다. Finish-Up-A-Thon에 대해 듣자마자, 이 챌린지를 완수하기 위해 SDD 방법론을 사용할 것이라는 확신이 들었습니다. SDD는 상세하고 구조화된 명세 (Specification)가 주요 산출물이자 절대적인 진실의 원천 (Source of Truth) 역할을 하는 AI 보조 개발 접근 방식입니다. 이러한 명세로부터 문서가 도출되며, 코드 샘플이나 지침이 생성됩니다.
Copilot과 결합된 GitHub의 SpecKit과 같은 SDD 도구를 사용하면 작업량이 덜 위협적으로 느껴지며, 몇 년 된 프로젝트를 부활시키는 것이 갑자기 완전히 관리 가능한 일처럼 느껴졌습니다.
다시 시작하기 (Getting Started (again))
SpecKit 툴킷을 구현하기 전에, Next.js 애플리케이션을 최신 버전으로 업그레이드해야 하는 상황이었습니다. 하지만 이 애플리케이션을 업그레이드한 것이 이번이 처음은 아니었습니다. 사실, 저는 모든 리디자인(redesign) 사례를 폴더 디렉토리로 만들어 두었습니다:
/
├── 2020-recipe-website/
├── 2021-recipe-website/
...
그래서 저는 새로운 2026-recipe-website/ 디렉토리와 새로운 Next.js 앱(이번에는 Pages Router 대신 App Router를 사용)을 만들어 이 패턴을 이어갔고, 2023년 인스턴스에서 글로벌 스타일(global styles)을 옮겨왔습니다.
구조와 스타일이 갖춰지자, 이제 Copilot을 사용하고 프로젝트에 SpecKit을 추가할 차례가 되었습니다.
Copilot으로 SpecKit 초기화하기 (Initializing SpecKit with Copilot)
프로젝트에 툴킷을 추가하기 위해, 루트(root)에서 다음 명령어를 실행했습니다:
specify init --here --integration copilot
이 초기화 과정을 통해, 이제 VS Code의 Copilot 채팅창에서 작업할 때 SpecKit 명령어인 /speckit.*를 인식할 수 있게 됩니다.
헌법 생성하기 (Generating a Constitution)
어떠한 명세(spec)를 작성하기 전에, SpecKit은 constitution.md를 필요로 합니다. 이는 프로젝트 전반의 원칙, 요구사항 및 기술 표준을 설정하는 문서입니다. 이 문서는 의도적으로 상위 수준(high-level)을 유지하며,
-
/speckit.specify→ 새로운 명세(specification)를 생성합니다. 설명을 제공하는 경우, 무엇을 만들고 싶은지, 즉 오직 **무엇(what)**과 **왜(why)**에 대해서만 기술해야 합니다. 어떠한 기술 스택(tech stack) 세부 사항도 포함하지 마십시오. 설명이 제공되지 않으면, 에이전트(agent)가 코드베이스 파일을 분석하여 문맥(context)을 파악합니다. -
[선택 사항]
/speckit.clarify→ 새로운 명세 문서의 모호함을 드러내고 사각지대를 찾아내는 선택적 명령입니다. 이 명령은 두 가지 유형의 인자(argument)를 받을 수 있습니다: 에이전트가 스캔하는 범위를 좁히기 위해 파일이나 폴더를 직접 가리키는 경로 인자(path argument) (예:@접두사 사용), 그리고 특정 영역을 명확히 하는 범위 인자(scope argument) (예: "성능(performance)", "데이터 모델(data model)", "보안(security)"). 두 인자가 모두 생략되면, 에이전트는 명세 전체를 스캔하여 모호함을 찾고 최대 5개의 확인 질문을 던집니다. -
[선택 사항]
/speckit.checklist→ 요구사항이 완전하고, 명확하며, 일관된지 검증하기 위한 맞춤형 품질 체크리스트(quality checklists)를 생성합니다. (이 명령은 인자를 받지 않습니다.) -
/speckit.plan→ 완전히 명확해진 명세를 바탕으로 구체적인 기술 구현 계획을 생성합니다. 본질적으로 이는 명세 기반 개발(Spec-Driven Development)의 "설계 단계(design phase)"이며, **무엇(what)**이 상세한 **어떻게(how)**로 변하는 시점입니다. 이 단계에서는 아키텍처(architecture), 스택 선택(stack choices), 컴포넌트 경계(component boundaries), 데이터 흐름(data flow) 및 통합(integrations)을 결정합니다. 인자(예: "Next.js와 Supabase 사용", "HIPAA 준수 필수", "낮은 지연 시간(<50ms) 최적화")를 전달하면, 이는 플래너(planner)가 진행하기 전에 반드시 고려해야 할 제약 조건(constraints)이 됩니다. -
/speckit.tasks→ 실행 가능한 항목으로 세분화된 작업 목록을 생성합니다.tasks.md가 추가되면, 명세는 구현 단계(implementation phase)로 넘어갈 준비가 된 것입니다. -
[선택 사항]
/speckit.analyze→ 모든 명세 문서를 감사(audit)하여 불일치와 모호함을 식별하는 심층 기술 분석 보고서를 제공합니다. -
/speckit.implement→ 구현 계획을 실행하고 스타터 코드(starter code), 파일 구조, 그리고 기능을 완성하기 위한 정밀한 지침을 생성합니다.
GitHub Copilot 사용 경험
이번 챌린지 동안 가장 놀라웠던 점 중 하나는 SpecKit이 나의 개발 접근 방식을 얼마나 크게 변화시켰는가 하는 점입니다.
코드 작성으로 바로 뛰어드는 대신, 구현이 시작되기도 전에 명세(specifications)와 계획을 검토하고 작업을 생성하는 데 대부분의 시간을 보냈습니다. 이러한 변화는 내가 요구사항과 설계 결정에 대해 더 신중하게 생각하도록 강제했습니다. 마치 나의 역할이 빌더(builder)에서 감독관(supervisor)으로 바뀐 것 같은 기분이었습니다.
아이러니하게도, 모든 계획과 검토 과정을 거치다 보니 프로젝트 중간에 Copilot의 무료 티어 사용 제한에 걸려 다른 AI 에이전트(AI agent)로 전환해야 했습니다. 다행히 SpecKit 덕분에 AI 에이전트를 전환하는 과정이 매우 매끄러웠기에 이는 문제가 되지 않았습니다. 플러그인이 설치되어 있는 한, 모든 /speckit.* 명령어가 동일하게 작동했습니다. 워크플로우는 그대로 유지되었고, 중단 없이 계속 진행할 수 있었습니다. 전환 과정은 최소한의 노력만 필요했습니다.
투명성을 유지하기 위해, 각 커밋 설명(commit description)에 사용된 정확한 SpecKit 명령어를 포함했으며, 이는 각 풀 리퀘스트(pull request)에서 확인할 수 있습니다.
새로운 명세: 백엔드를 Prismic에서 Supabase로 마이그레이션
풀 리퀘스트 (Pull Request): https://github.com/karlyhoffman/recipe-website/pull/8
Supabase로의 마이그레이션은 내 위시리스트의 첫 번째 주요 항목이었습니다. 결과적으로 이는 데이터 구조에 대한 세밀한 제어권을 제공하며, 내 레시피 아카이브는 매일 콘텐츠를 관리할 필요가 없기 때문에 호스팅된 헤드리스 CMS(headless CMS)는 과한 느낌이었습니다. 또한 항상 Supabase를 써보고 싶었기에 지금보다 더 좋은 시기는 없다고 생각했습니다. (게다가 만약 정말로 CMS가 필요해지더라도, 나중에 Supabase 데이터베이스를 Directus나 PayloadCMS에 연결하면 됩니다.)
마이그레이션 프로세스를 시작하기 위해, 다음과 같은 세부 사항과 함께 /speckit.specify 명령어를 실행했습니다:
/speckit.specify --text "@2023-recipe-website/의 Prismic 백엔드를 @2026-recipe-website/의 Supabase로 마이그레이션"
저는 이 명세 (spec)에 더 많은 맥락을 추가하기 위해 선택 사항인 --text 플래그를 사용했습니다 (아래 명세들에서는 명령어가 호출될 수 있는 다양한 방식들을 확인하실 수 있습니다).
해당 명령어를 실행한 후, 다음과 같은 파일들이 생성되었습니다:
specs/001-prismic-to-supabase/spec.mdspecs/001-prismic-to-supabase/checklists/requirements.md
spec.md에는 사용자 스토리 (user stories), 기능적 요구사항 (functional requirements, 시스템이 수행해야 하는 작업), 비기능적 요구사항 (non-functional requirements, 즉 성능, UX, 제약 사항), 성공 기준 (success criteria), 그리고 예외 케이스 (edge cases)가 포함되어 있습니다. requirements.md에는 나중에 공식적인 명세로 변환될 실행 가능한 제품 및 기술 요구사항 (product and technical requirements)이 포함되어 있습니다.
이 단계는 또한 심도 있는 검토 (deep review)가 시작되는 단계이기도 합니다. 새로운 명세 문서가 생성될 때마다, 그 내용을 전체적으로 이해하고 그것이 애플리케이션에 어떤 영향을 미치는지 파악하는 것이 매우 중요합니다. 저는 에이전트 (agent)가 무엇을 구현하려 하는지 알 수 있도록 각 새 파일을 주의 깊게 읽으며, 불분명하거나, 일관성이 없거나, 혹은 틀린 부분(자주 발생합니다)이 있다면 의문을 제기합니다.
예를 들어, 명세와 요구사항을 검토하는 동안 저는 저장 비용을 줄이기 위해 hero_image_url 필드를 마이그레이션하지 않기로 결정했습니다. 흥미롭게도, 에이전트는 변경 사항을 어디에도 기록하지 않은 채 코드베이스와 문서에서 해당 필드를 완전히 삭제해 버렸습니다. 특히 이 방법론에서 문서화 (documentation)가 핵심적인 역할을 한다는 점을 고려할 때, 이러한 불일치는 놀라운 발견이었습니다.
명세를 다듬은 후, 다음 단계로 넘어가 계획 문서 (planning documents)를 생성할 차례였습니다:
/speckit.plan
이 명령어는 기능 명세 (feature specification)와 헌법 (constitution)을 읽은 다음, 아키텍처 (architecture), 프로젝트 구조 (project structure), 설계 결정 (design decisions), 리스크 (risks), 그리고 지원 설계 문서 (supporting design docs)를 다루는 기술적 구현 계획 (technical implementation plan)을 생성하며, 이는 기능 디렉토리 내에 plan.md로 저장됩니다.
*팁: 이 명세(spec)의 시작 단계부터 Supabase가 기술 스택(tech stack)의 일부가 될 것임을 알고 있었기 때문에, 구현되는 코드가 베스트 프랙티스(best practices)를 따를 수 있도록 이 단계 이전에 supabase-best-practice 플러그인을 반드시 설치해 두었습니다. 일반적으로 기술 스택을 미리 알고 있다면, 계획(planning) 단계 이전에 관련 MCP 및 플러그인을 설치했는지 확인하십시오. 이를 통해 에이전트가 생성하는 코드 스니펫(snippets)과 지침이 정확하고 베스트 프랙티스를 따르도록 보장할 수 있습니다.
모든 새로운 계획 문서(planning documents)에 대한 검토를 마친 후, /speckit.analyze와 /speckit.tasks를 실행하여 계획을 감사(audit)하고 실행 가능한 항목(actionable items)을 생성했습니다.
그다음은 구현(implementation) 단계였습니다. 여전히 출력물을 검토하고, 마이그레이션(migrations)을 검증하며, 생성된 코드를 테스트해야 했지만, 힘든 작업들은 이미 명세(specification)와 계획(planning) 과정을 통해 모두 계획되어 있었습니다. 마이그레이션 스크립트(migration scripts)는 원활하게 실행되었고, 단위 테스트(unit tests)를 통과했으며, 데이터는 Supabase PostgreSQL로 성공적으로 마이그레이션되었습니다. 수동으로 스키마 매핑(schema mapping)을 했다면 아마 일주일 이상 걸렸을 작업이 48시간 이내에 마무리되었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기