본문으로 건너뛰기
144BPM 로고

144BPM

AI와 요구사항·설계 문서를 작성하고, 이를 구현 기준으로 활용해 혼자 기획·개발·배포한 리듬 연습 서비스

담당
  • 요구사항 정리 · 데이터 모델 · 화면 흐름 설계
  • AI Coding Agent를 활용한 구현 · 배포
기간
2026.03
개인 프로젝트
144BPM 대표 화면

Overview

프로젝트 한눈에 보기

배경
실제 사용자 1명의 요청에서 시작해 리듬 패턴과 BPM을 직접 구성하고 반복 연습할 수 있도록 만든 개인 프로젝트입니다. 요청한 사용자가 현재도 이용하고 있습니다.
구현 범위
AI와 PRD·정보 구조·기능 명세·데이터 모델·인터랙션 명세를 공동 작성했습니다. 문서를 기준으로 AI Coding Agent에 구현을 요청하여 연습 세트 편집, 메트로놈·카운트인, 단계별 BPM, 공개 공유 기능을 구현 후 배포했습니다.

주요 기능

  1. 01

    커스텀 연습 관리

    사용자 정의 연습 세트 생성 및 레벨별 리듬 패턴 편집

  2. 02

    연습 인터페이스

    메트로놈, 박자 하이라이트 기반의 실전 연습 환경

  3. 03

    공개 & 링크 공유

    연습 세트의 공개 전환 및 고유 링크를 통한 외부 공유 기능

Technology

기술 선택 이유

핵심 사용 기술

  • AI Coding Agent(Codex, Claude Code)

    기획·개발·배포를 혼자 맡는 조건이라 요구사항을 머릿속에 두면 기능 범위와 데이터 규칙이 구현 중에 흔들릴 수 있었습니다. AI와 함께 기능 범위·데이터 제약·화면별 동작을 문서로 정리해 검증 가능한 상태로 만들고, 확정된 문서를 기준으로 구현을 요청·검토하기 위해 선택했습니다.

  • Next.js

    인증 정보와 사용자 데이터를 클라이언트에 노출하지 않으면서도 편집·재생 화면의 반응성은 유지해야 했습니다. 세트 조회·저장은 Server Actions로 서버에서 처리하고, 입력과 상태 변화가 잦은 편집·재생 영역만 클라이언트에서 구현하도록 경계를 나누기 위해 선택했습니다.

  • NextAuth

    개인 데이터를 다루는 서비스지만 이 규모에서 자체 인증을 구축하는 것은 비용 대비 이득이 없다고 판단했습니다. Google 로그인과 세션 관리는 라이브러리에 맡기고, 서버 세션의 사용자 식별값으로 데이터 조회 권한을 확인하기 위해 선택했습니다.

사용 기술

  • TypeScript

    리듬 세트 안에 레벨별 BPM과 패턴이 존재하고, 패턴 역시 음표·쉼표의 종류와 길이처럼 정해진 데이터 구조를 가져 잘못된 값이 전달되면 편집과 재생 로직까지 영향을 받을 수 있었습니다. 리듬·레벨·패턴 등 도메인 데이터의 구조와 컴포넌트 간 전달 값을 타입으로 정의해 잘못된 데이터 사용과 필수 값 누락을 개발 단계에서 확인하기 위해 선택했습니다.

  • Tailwind CSS

    리듬 편집기, 사이드바, 재생 화면처럼 상태에 따라 UI가 자주 달라지고 동일한 디자인 규칙을 여러 화면에 반복 적용해야 했습니다. 유틸리티 클래스를 중심으로 스타일을 구성해 상태별 스타일을 컴포넌트 가까이에서 관리하고, 공통된 간격·색상·타이포그래피 규칙을 일관되게 적용하기 위해 선택했습니다.

  • Zustand

    제목·레벨·패턴·커서처럼 여러 편집 UI가 상태를 공유하면서 하나의 Context에 서로 다른 관심사가 모이는 문제가 있었습니다. 저장된 세트 목록과 현재 선택, 생성·수정 중인 데이터, BPM·박자를 책임별 스토어로 분리해 관리하기 위해 선택했습니다.

  • Firebase Admin SDK · Firestore

    사용자가 만든 리듬을 계정별로 저장·수정·삭제하고 공개 설정에 따라 링크로 공유해야 했으며, 서버에서는 로그인한 사용자의 권한을 확인한 뒤 데이터에 접근할 필요가 있었습니다. 리듬과 레벨별 패턴처럼 함께 다루는 데이터를 Firestore에 저장하고, Firebase Admin SDK를 통해 서버에서 인증된 사용자의 데이터 조회·저장 작업을 처리하기 위해 선택했습니다.

Key Points

주요 경험 및 설계 결정

  1. 01

    요구사항과 설계 문서를 AI의 구현 기준으로 활용

    배경

    실제 사용자가 리듬 패턴과 BPM을 직접 구성할 수 있는 연습 도구를 요청했습니다. AI에 구현을 요청하기 위해 기능 범위뿐 아니라, 패턴의 유효 조건과 화면별 동작을 구체적으로 정의할 필요가 있었습니다.

    진행

    AI와 요구사항·데이터 모델·인터랙션 명세를 공동 작성했습니다.

    생성·편집·재생·공유 흐름과 한 마디당 4박, 레벨 1–10개, BPM 40–200의 제약을 정의했습니다.

    작성한 문서를 AI Coding Agent의 구현 기준으로 제공했습니다.

    결과

    요구사항·설계 문서를 기준으로 AI를 활용해 개발하고, 5일 만에 서비스를 배포했습니다.

    요청한 사용자가 실제 연습에 사용하는 서비스로 완성했습니다.

  2. 02

    16칸 그리드와 입력 제약으로 마디 길이 초과 방지

    문제

    4/4박자 안에서 길이가 서로 다른 음표와 쉼표를 조합해야 했습니다. 음표를 자유롭게 추가하면 한 마디의 길이를 초과하는 유효하지 않은 리듬 패턴이 만들어질 수 있었습니다.

    저장 시점에만 검증할 경우, 사용자가 편집을 마친 뒤 패턴을 다시 수정해야 할 수 있었습니다.

    해결

    16분음표를 최소 단위로 설정하고 4/4박자 한 마디를 16칸 그리드로 표현했습니다.

    음표·쉼표의 박자 길이를 span으로 정의하고, 선택 위치부터 이어지는 빈 공간에 들어갈 수 있는 항목만 선택하도록 제한했습니다.

    같은 span을 CSS Grid의 열 점유 수로 변환해 데이터의 박자 길이와 화면의 표시 너비를 일치시켰습니다.

    src/entities/note/model/constants.ts
    export interface NoteDefinition {
      span: number;      // 박자 점유 수 (4분=1, 8분=0.5, 16분=0.25)
      offsets: number[]; // span 내 각 타격의 절대 오프셋
      bg: string;
    }
    
    export const toGridSpan = (span: number) => Math.round(span * 4);
    
    export const NOTE_MAP: Record<NoteId, NoteDefinition> = {
      NOTE_16: { span: 0.25, offsets: [0], bg: "..." },
      NOTE_4: { span: 1, offsets: [0], bg: "..." },
      // ... 선택 위치부터 이어지는 연속 빈 공간에 따라 선택 가능 여부 결정
    };

    결과

    한 마디의 길이를 초과하는 입력을 편집 단계에서 차단했습니다.

    동일한 span을 입력 제약과 화면 배치에 사용해 박자 길이와 표시 너비의 불일치를 방지했습니다.

Gallery

  1. 144BPM 프로젝트 화면 1
  2. 144BPM 프로젝트 화면 2
  3. 144BPM 프로젝트 화면 3