“자료를 저장하고 정리하는 앱”은 화면을 만들기에는 충분한 설명이지만, 저장 결과가 맞는지 판정하기에는 결정이 많이 남아 있습니다. 같은 링크를 다시 넣어도 되는지, 다른 계정에서도 보여야 하는지, 새로고침 뒤에도 남아야 하는지에 따라 구현이 달라집니다. 영국 정부의 사용자 이야기 작성 지침은 사용자, 하려는 일, 목적을 적고 사용자 필요가 충족됐는지 확인할 결과를 수용 조건으로 남깁니다.
앱의 첫 요구사항은 이 결정을 짧은 흐름과 데이터 규칙으로 바꾸는 작업입니다. 화면 모양을 고르기 전에 저장과 변경의 의미가 정해져 있으면, 생성된 코드가 임의로 채운 가정도 찾아낼 수 있습니다.
사용자 한 명이 끝낼 작은 흐름부터 정하기
가상의 ‘개인 자료함’은 로그인한 사용자가 나중에 읽을 링크를 보관하는 웹앱입니다. 첫 범위는 링크 추가, 자신의 자료 목록 보기, 읽음 상태 변경, 자료 삭제까지입니다. 공개 공유, 공동 편집, 링크 내용 자동 수집, AI 요약은 첫 범위에서 제외합니다. 다음 표는 이 앱의 설계 예시이며 실제로 구현한 앱의 명세가 아닙니다.
| 기능 | 시작 상태와 사용자 행동 | 끝났을 때 보이는 결과 | 첫 범위에서 제외한 일 |
|---|---|---|---|
| 링크 추가 | 로그인한 사용자가 HTTPS URL과 선택 제목을 입력한다 | 자신의 목록에 새 자료가 나타나고 새로고침 뒤에도 남는다 | 링크 원문 수집과 제목 자동 추출 |
| 자료 목록 보기 | 로그인한 사용자가 자료함을 연다 | 자신의 자료만 생성 시각의 내림차순으로 보인다 | 다른 사람 자료 검색과 공동 자료함 |
| 읽음 상태 변경 | 자신의 자료에서 읽음 또는 안 읽음을 선택한다 | 선택한 상태가 목록과 상세에서 같고 재접속 뒤에도 유지된다 | 읽은 시간 측정과 자동 판정 |
| 자료 삭제 | 자신의 자료에서 삭제를 확인한다 | 목록과 상세에서 사라지고 다시 접속해도 돌아오지 않는다 | 휴지통과 삭제 복구 |
“링크 추가”의 끝을 성공 알림으로만 정하면 서버에 저장하지 않고도 화면은 통과할 수 있습니다. 위 예시는 새로고침 뒤의 목록까지 완료 범위에 넣습니다. 반대로 원문 수집까지 요구하면 네트워크 접근과 추출 실패라는 새 흐름이 생깁니다. 첫 기능에 필요한 결과와 다음 기능의 결과를 나누면 각 기능에서 검증할 범위가 드러납니다.
표에 없는 기능 요청이 생기면 기존 흐름에 들어가는지 먼저 봅니다. ‘나중에 읽기’에 ‘팀 공유’가 추가되면 단순히 공유 버튼 하나를 붙이는 작업으로 끝나지 않습니다. 누가 자료를 소유하는지, 팀을 나갔을 때 접근이 유지되는지, 누가 삭제할 수 있는지까지 새로운 결정이 생깁니다.
데이터에는 이름과 변경 규칙을 함께 적습니다
화면에 필요한 값과 보존할 원본 데이터는 구분합니다. 목록의 ‘자료 수’는 저장한 자료에서 계산할 수 있지만 자료의 소유자와 URL은 각 항목의 원본입니다. 원본과 계산값을 함께 저장한다면 언제 같은 상태로 맞출지도 구현 범위가 됩니다.
개인 자료함의 자료 한 건은 다음처럼 정의할 수 있습니다. 필드 이름은 설명용 설계이며 특정 프레임워크나 데이터베이스에 맞춘 실행 스키마가 아닙니다.
| 필드 | 의미와 값 | 생성·변경 규칙 | 누락·충돌 처리 |
|---|---|---|---|
| id | 자료 한 건의 고유 식별자 | 서버가 만들고 이후 변경하지 않는다 | 식별자가 없거나 중복된 자료는 만들지 않는다 |
| owner_id | 자료를 소유한 사용자 식별자 | 서버가 확인한 로그인 사용자로 정하고 일반 수정에서 바꾸지 않는다 | 로그인 사용자가 확인되지 않으면 생성을 거부한다 |
| url | 사용자가 보관할 절대 HTTPS URL | 앞뒤 공백만 제거해 저장하며 이 버전에서는 수정하지 않는다 | 형식이 맞지 않으면 저장하지 않고 입력 오류를 표시한다 |
| title | 사용자가 붙인 선택 제목 | 생성 시 앞뒤 공백을 제거하고 비어 있으면 값 없음으로 저장한다; 생성 뒤에는 유지한다 | 값이 없으면 화면에 저장한 URL을 대신 표시한다 |
| status | unread 또는 read | 생성 시 unread, 소유자만 두 값 사이에서 변경한다 | 다른 값은 저장하지 않는다 |
| created_at | 자료를 처음 만든 시각 | 서버가 정하고 이후 유지한다 | 목록의 생성 시각 정렬에 쓴다 |
| updated_at | 마지막으로 내용을 바꾼 시각 | 상태가 실제로 바뀔 때 서버가 갱신한다 | 바뀐 내용이 없으면 기존 값을 유지한다 |
‘중복 자료 금지’도 범위가 필요합니다. 예시에서는 같은 사용자의 저장된 URL 문자열이 같을 때 중복으로 처리합니다. 서로 다른 사용자는 같은 URL을 각각 저장할 수 있습니다. URL의 쿼리나 끝 슬래시를 합치는 정규화는 하지 않으며, 서로 다른 문자열이 같은 웹페이지를 가리키는 경우도 허용합니다. 이 규칙을 바꾸려면 기존 자료의 충돌 처리도 새로 정합니다.
PostgreSQL 18의 제약 문서는 필수값, 행의 조건, 중복, 다른 테이블과의 관계를 서로 다른 제약으로 표현합니다. 기본키는 행을 식별하며 고유성과 값이 비어 있지 않음을 요구하고, 외래키는 참조한 행의 존재를 다룹니다. 데이터 규칙을 정해 두면 이런 저장 계층의 제약과 앱의 오류 처리를 어디에 둘지 판단할 수 있습니다.
사용자마다 같은 URL을 한 번만 저장하도록 구현한다면 소유자와 URL을 함께 비교하는 규칙이 필요합니다. URL 하나만 고유값으로 정하면 다른 사용자의 저장까지 막습니다. 화면에서 중복 안내를 보이는 일과 동시 저장 요청이 와도 실제 중복 행을 만들지 않는 일도 각각의 검증 대상입니다.
삭제의 의미도 명시합니다. 이 예시는 삭제를 확인한 자료를 영구 삭제하고 복구 기능을 제공하지 않는 범위입니다. 휴지통이 필요해지면 삭제 상태, 보관 기간, 목록 제외, 복구 시 중복 처리까지 요구사항이 늘어납니다. 삭제라고만 적어 두면 생성된 코드가 이 결정을 대신하게 됩니다.
수용 조건은 준비 상태·행동·관측 결과로 씁니다
Cucumber의 Gherkin 문법에서 Given은 초기 조건, When은 사건이나 행동, Then은 기대 결과를 표현합니다. 기대 결과는 사용자나 외부 시스템이 관측할 수 있는 출력에 둡니다. 이 구조는 특정 시험 도구를 도입하지 않아도 요구사항을 모호하지 않게 적는 데 쓸 수 있습니다.
“저장이 잘 됩니다”를 “빈 자료함을 가진 로그인 사용자 A가 유효한 URL을 저장하면, A의 목록에 한 건이 생기고 새로고침 뒤에도 남습니다”로 바꿉니다. 시작 데이터, 실행한 행동, 확인할 결과가 같은 문장에 들어갑니다. 아래 표는 개인 자료함의 수용 조건 예시이며 실행 결과 칸을 채운 시험 보고서가 아닙니다.
| 확인할 조건 | 준비 상태 | 행동 | 기대하는 관측 결과 |
|---|---|---|---|
| 첫 자료 저장 | A가 로그인했고 자료가 없다 | 유효한 새 HTTPS URL을 저장한다 | A의 목록에 unread 자료 한 건이 생기고 새로고침 뒤에도 남는다 |
| 선택 제목 누락 | A가 로그인했다 | 제목을 공백만 입력하고 새 URL을 저장한다 | 저장은 성공하고 목록에는 URL이 제목 대신 보인다 |
| URL 형식 오류 | A가 로그인했다 | URL 형식이 아닌 문자열을 저장한다 | 필드 오류가 보이고 자료 수가 늘지 않는다 |
| 같은 사용자 중복 | A가 같은 URL을 이미 저장했다 | 앞뒤 공백만 다른 같은 URL을 다시 저장한다 | 중복 안내가 보이고 A의 자료는 한 건으로 유지된다 |
| 다른 사용자 같은 URL | A가 URL을 저장했고 B는 저장하지 않았다 | B가 자신의 세션에서 같은 URL을 저장한다 | B의 목록에도 자신의 자료 한 건이 생기고 A의 자료는 유지된다 |
| 읽음 상태 저장 | A의 자료가 unread다 | A가 read로 바꾼 뒤 새로고침한다 | 목록과 상세가 모두 read로 보인다 |
| 저장 응답 실패 | 저장 결과를 확정하지 못한 상태다 | 네트워크 실패를 시험한다 | 완료로 표시하지 않고 입력을 보존하며 확인하지 못한 상태를 보여 준다 |
| 삭제 완료 | A의 자료가 존재한다 | A가 삭제를 확인하고 다시 접속한다 | 목록에서 사라지고 이전 상세 주소에서도 자료가 보이지 않는다 |
성공 화면만 확인하면 입력 오류에서 저장이 발생했는지 놓치기 쉽습니다. 실패 조건에는 보이는 안내와 바뀌지 않아야 할 결과를 함께 적습니다. 다만 저장 응답을 받지 못한 경우에는 서버 저장도 실패했다고 단정할 수 없어, 확인 불가 상태와 후속 확인 절차를 따로 설계합니다.
이 표를 자동 시험으로 바꾸려면 입력 자료, 실행 코드, 결과를 비교하는 검사가 연결되어야 합니다. Gherkin 문장도 실행할 단계 정의가 연결돼야 시험이 됩니다. 명세 파일을 썼다는 사실과 실제 요청으로 동작을 확인했다는 사실을 구분합니다.
권한 경계와 미결정 항목을 구현 전에 표시하기
자료를 볼 수 있는 사용자도 데이터 명세에 포함합니다. 예시의 owner_id는 서버가 확인한 로그인 사용자에서 정하며, 클라이언트가 보낸 소유자 값을 그대로 신뢰하지 않습니다. B가 A의 자료 식별자를 보냈을 때 목록·상세·수정·삭제가 어떻게 동작할지 수용 조건에도 남깁니다.
OWASP의 인가 지침은 기본 거부와 모든 요청의 권한 검사를 권고합니다. 개인 자료함에서는 “목록에서 A의 자료가 숨겨진다”에 더해 “B의 직접 상세 요청에 A의 내용이 반환되지 않고, B의 수정·삭제 요청으로 A의 원본이 바뀌지 않는다”를 적습니다. 버튼 표시와 실제 데이터 접근은 서로 다른 확인 대상입니다.
이 단계에서는 허용할 관계와 관측할 결과를 정합니다. 실제 서버·데이터베이스 정책과 배포 전 검사 절차는 바이브 코딩 앱의 보안 점검으로 연결할 수 있습니다. 요구사항에 권한 문장을 넣은 것만으로 그 앱의 보안 검사를 끝냈다고 판단하지 않습니다.
기획 중 답을 정하지 못한 항목은 따로 표시합니다. 제목 길이 제한, 목록의 같은 시각 정렬 순서, 계정 탈퇴 때 자료 처리, 동시 수정 충돌처럼 아직 정하지 않은 것은 ‘AI가 적당히 처리’할 범위로 숨기지 않습니다. 첫 구현에서 해당 경로를 제외할지, 결정을 내린 뒤 넣을지 구분합니다.
코드를 생성할 때는 선택한 기능 한 개와 그 기능에 필요한 데이터 규칙, 성공·실패 수용 조건을 함께 전달하는 편이 좋습니다. 결과를 확인한 뒤 다음 흐름을 추가하면, 화면과 저장 상태가 어디서 요구사항과 갈라졌는지 좁혀 볼 수 있습니다.
자료 확인 기준: 2026년 10월 28일. 개인 자료함은 기능·데이터·수용 조건을 설명하기 위한 설계 예시이며 구현과 시험은 수행하지 않았습니다.
기능은 되는데 수정할수록 고장나는 AI 코드: 구조·중복·결합도
규칙 하나를 바꾸는데 여러 화면과 저장 경로를 동시에 고친다면 변경의 책임이 흩어져 있을 수 있습니다. 배송비 계산 예시로 규칙·상태·의존 관계를 점검하고 작게 고치는 기준을 설명합니다.
AI가 같은 오류를 계속 고칠 때: 재현·로그·원인을 나누는 법
오류 화면만 보여 주며 수정을 반복하면 코드와 가설이 함께 바뀌어 원인을 놓치기 쉽습니다. 실패 입력과 관측 사실을 고정하고, 원인이 갈라지는 지점에서 시험하는 과정을 설명합니다.
AI가 작성한 테스트는 무엇을 검증하고 있을까
테스트가 모두 통과해도 요구사항의 경계에서 오류가 남을 수 있습니다. 기대값의 출처와 실패할 조건을 보면 AI가 만든 테스트를 평가할 수 있습니다.
