✅ 구현됨 10🟡 부분 12❌ 미구현 5⚪ 미측정 1기능SFR기능 · 구현됨 2개 — SFR-001, SFR-0102기능 · 부분 5개 — SFR-002, SFR-003, SFR-006, SFR-008, SFR-0095기능 · 미구현 3개 — SFR-004, SFR-005, SFR-007310개보안SEC보안 · 구현됨 5개 — SEC-002, SEC-003, SEC-004, SEC-010, SEC-0115보안 · 부분 5개 — SEC-005, SEC-006, SEC-008, SEC-009, SEC-0125보안 · 미구현 2개 — SEC-001, SEC-007212개성능PER성능 · 부분 2개 — PER-001, PER-0022성능 · 미측정 1개 — PER-00313개품질QUA품질 · 구현됨 3개 — QUA-001, QUA-002, QUA-00333개
그림 5-1. 이 장의 요구사항 28개(기능 10 · 보안 12 · 성능 3 · 품질 3)를 분류마다 상태별로 쌓았다 — 아래 각 절 요약표의 상태 기호를 센 것이라, 표를 고치면 그림도 따라온다. 칸에 마우스를 올리면 요구사항 번호가 보인다.

1) 기능 요구사항

서비스가 무엇을 하는가를 적는다. 어떤 조건에서 동작해야 하는가는 아래 2)절이다.

번호는 새로 매기지 않는다. 부록 D가 SFR-001~010을 이미 근거로 인용하고 있어 (각 도메인 테이블 설명), 여기서 번호를 바꾸면 그 인용이 통째로 끊긴다. 아래 항목은 새로 정의한 것이 아니라 3장·부록 D에 흩어져 있던 정의를 한자리에 모은 것이다.

2)절과 같은 형식으로 확인 방법을 함께 적는다. 상태 열은 2026-09-04 기준이며 반드시 낡으므로, 믿을 것은 상태가 아니라 확인 방법이다.

아래는 요약이다. 전문·확인 방법·근거는 표 바로 아래 「상세」를 펼쳐서 본다. 상태 아이콘(✅ 구현됨 · 🟡 부분 · ❌ 미구현)도 요약일 뿐이라, 실제로 무엇이 됐고 안 됐는지는 상세의 괄호 안 서술이 정본이다.

ID 요구사항 (요약) 상태
SFR-001 경기·훈련 클립 업로드 — 규격 검사·반려 사유 기록 ✅
SFR-002 결정론적 코드로 지표 측정·적재 (언어 모델은 수치를 생성하지 않는다) 🟡
SFR-003 측정값 근거의 판정 코멘트 (점수 숫자 없이) 🟡
SFR-004 지표 기반 호칭 부여 (절대 기준, 상대 비교 아님) ❌
SFR-005 성향 벡터화·유사도 비교 (점수화하지 않는다) ❌
SFR-006 지원 건별 적합도 3축(수준·역할·성향) 산출 🟡
SFR-007 모집 팀에 후보 추천 + 사유 기록 ❌
SFR-008 경기 후 상호 평가 (선택형, 제재는 별도 기록) 🟡
SFR-009 카드 공개 공유 (인증 없이, 수치 비노출) 🟡
SFR-010 경기 등록 + 필요 포지션·인원 ✅
상세 — 요구사항 전문 · 확인 방법 · 근거
ID 요구사항 확인 방법 상태
SFR-001 사용자는 자신의 경기·훈련 클립을 업로드한다. 업로드는 저장 위치와 메타를 video에 남기고, 규격 검사를 거쳐 반려 사유를 값으로 기록한다(video_validation) — 사유가 남지 않으면 왜 반려됐는지 사후에 확인할 수 없다. 촬영 가이드(측면 촬영·전신 포함·최소 해상도)는 업로드 화면에서 제시한다 업로드 1건에 video 1행과 video_validation 1행이 생기는지. 규격 미달 클립의 반려 사유가 비어 있지 않은지 구현됨 (업로드 3단계 — POST /videos/upload-url(사전 서명) · POST /videos(등록) · GET /videos, 2026.09.03. 등록 1건에 video 와 video_validation 이 함께 생기고, 규격 미달은 사유 문장으로 남는다(용량 200MB · 길이 60초 · 1920x1080). 🔴 촬영 가이드 문구는 업로드 화면에 아직 없다)
SFR-002 업로드된 클립에서 결정론적 코드가 관절 각도·각속도·무게중심 궤적을 측정해 지표 항목별로 적재한다(analysis_metric_value). 지표 항목은 종목·동작마다 다르므로 컬럼으로 고정하지 않고 metric_definition에 정의한다. 언어 모델은 수치를 생성하지 않는다(3장 3) 같은 클립을 두 번 분석해 지표 값이 일치하는지(QUA-001). 지표 항목이 코드가 아니라 metric_definition에 정의되어 있는지 부분 (agent/에 측정·등급 판정이 있고 활성 루브릭은 축구 인스텝 슈팅·야구 투구·농구 점프슛 3종. DB 적재 경로는 없다)
SFR-003 측정값과 채점 기준을 대조한 판정 결과를 선수가 읽을 문장으로 남긴다(analysis_report). 근거가 된 측정값과 프레임 번호를 함께 기록한다 — 근거 없는 문장은 실력 검증의 산출물이 될 수 없다. 코멘트는 두 문장 이내이며 총점·등급 숫자를 넣지 않는다(3장 4) 리포트 1건에 근거 측정값과 프레임 번호가 함께 남는지. 코멘트에 점수 숫자가 들어가지 않는지 부분 (agent/judge.py가 근거 문장을 만든다. 적재 경로 없음 · 모델 라이선스는 미결 1번)
SFR-004 지표를 근거로 호칭을 부여한다. 호칭 기준은 절대 기준이며 항목·비교연산자·임계값을 행으로 나누어 정의한다(title_definition · title_criteria). 부여 이력은 user_title에 남긴다. 사용자 간 상대 비교로 부여하지 않는다 같은 지표에 같은 호칭이 부여되는지. 호칭 조건이 코드가 아니라 title_criteria 행으로 표현되어 있는지 미구현
SFR-005 플레이 성향을 특징 벡터로 만들어 유사도 비교에 쓴다(player_vector, pgvector 색인). 성향은 우열이 아니라 유형이므로 점수로 환산하지 않는다 벡터 색인이 걸려 있는지. 유사도 조회가 P95 500ms 안에 드는지(PER-003, 부록 D.4가 4단 조인을 위험 지점으로 지목한다) 미구현
SFR-006 경기 지원 건마다 적합도를 수준·역할·성향 세 축으로 각각 산출한다(fitness_score). 실력 점수와 적합도는 다른 값이다 — 점수는 클립 1건의 절대 평가, 적합도는 지원 1건의 상대 평가다. 축을 하나로 합친 단일 점수를 내지 않는다 축별로 개별 반환되는지(부록 D.4의 검수 기준). 적합도가 지원 건과 무관하게 단독 조회되지 않는지 부분 (지원·제안 경로 구현 — match_application, 2026.09.02. 적합도 산출(fitness_score) 자체는 미구현이고 분석 지표 적재에 걸려 있다)
SFR-007 모집 팀에 후보를 추천하고 추천 사유를 함께 남긴다(recommendation). 사유가 없으면 팀이 왜 이 사람인지 판단할 수 없고, 추천 품질을 사후에 검증할 수도 없다 추천 1건에 사유가 비어 있지 않은지 미구현 (선행인 지원 경로는 2026.09.02에 생겼다)
SFR-008 경기 후 상호 평가를 받는다. 평가는 선택형이며 선택지 정의(review_option)와 선택 결과(review_selection)를 나누어 담는다. 불참·신고 등 제재 기록은 평가 점수로 환산하지 않고 별도로 둔다(no_show · report) 평가 결과가 단일 점수로 합산되지 않는지. 제재 기록이 review와 직접 이어지지 않는지 부분 (테이블 5종 — review_option · review · review_selection · report · no_show — 과 review_option 초기 목록이 2026.09.03 마이그레이션으로 들어왔다. 적재·조회 API 는 아직 없다)
SFR-009 사용자는 자신의 카드를 공개 링크로 공유한다(player_card). 공개 조회는 인증 없이 되고 경로에는 내부 식별자 대신 추측 불가능한 슬러그를 쓴다(SEC-005). 카드에 수치 능력치를 노출하지 않는다 — 수치는 리포트 경로로만 조회된다 토큰 없이 GET /cards/{slug} → 200. 응답에 점수·등급 수치가 없는지. 슬러그가 이름에서 유도되지 않는지 부분 (조회·생성 구현 — /me/card GET·POST · /cards/{slug}. 생성 시점은 2026.09.02에 「사용자가 요청할 때」로 정했다. 카드에 붙는 호칭은 SFR-004에 걸려 있다)
SFR-010 팀은 경기를 등록하고 필요한 포지션과 인원을 함께 적는다(match · match_position_need). 포지션은 둘 이상일 수 있으므로 행으로 나눈다. 종목은 team이 결정하므로 경기에 종목 컬럼을 두지 않는다 경기 1건에 포지션 요구가 여러 행으로 들어가는지. match에 종목 컬럼이 없는지 구현됨 (팀 생성·가입·탈퇴 + 경기 등록·조회·지원, 2026.09.02. position 은 종목별 기본 포지션으로 채웠다. 경기 탐색(GET /matches)과 수정·취소(PATCH·DELETE /matches/{id})를 2026.09.03 에 더했다. 지원이 붙은 경기도 취소할 수 있다 — 지원을 무르고 거절하는 경로(DELETE /matches/{id}/applications/{application_id})가 2026.09.04 에 생기며 409 가 풀렸다(미결 jin 16번 해소). 적합도·추천(SFR-006·007)은 다음 단계)

순위표를 만들지 않는다. SFR-004·005·006·008은 모두 “다른 사람보다 낫다”가 아니라 “이 사람이 이 경기에 맞는다”를 답한다. 사용자 간 비교 점수를 저장하는 테이블을 두지 않는다는 부록 D의 설계 원칙과 같은 이야기이며, 이는 판단이지 누락이 아니다.

SFR-002·003은 미결 항목에 걸려 있다. 채점 품질을 측정할 골든셋(미결 2번)이 없으면 개선 여부를 판별할 수 없고, 판정 모델의 상업 이용 가능 여부(미결 1번)가 정해지지 않았다. 두 항목의 “구현됨”은 그 둘이 풀린 뒤에야 판정할 수 있다.

이 절에 넣지 않은 것

  • 가입·로그인·프로필 — 서비스 기능이 아니라 모든 기능의 전제다. 요구사항으로는 SEC-003·004·011에서 다루고, 스키마는 부록 D 사용자·팀 도메인에 있다.
  • 결제·구독 — 부록 D에 과금 도메인이 있으나 10주 범위 밖이다. 4장 수익 모델이 확정된 뒤에 적는다.
  • 팀 스쿼드 편성(squad) — 카드 묶음이라 SFR-009의 연장이지만, 화면 설계가 정해지지 않아 별도 항목으로 세우지 않는다.

2) 비기능 요구사항

기능 요구사항(SFR)이 “무엇을 하는가”라면 이 절은 “어떤 조건에서 동작해야 하는가”다.

부록 D와 3장·6장이 이미 이 절의 항목을 근거로 인용하고 있다(SEC-003 · SEC-006 · PER-001 · PER-003 · QUA-002). 따라서 번호는 기존 참조에 맞추어 고정한다 — 여기서 번호를 바꾸면 다른 문서의 근거가 통째로 끊긴다.

각 항목에는 확인 방법을 같이 적는다. 확인할 수 없는 요구사항은 지켜졌는지 판별할 방법이 없어 문서에만 남기 때문이다. 상태 열은 2026-08-28 저녁 기준이며(QUA-001·002 는 2026-09-23 에 실물과 대조해 고쳤다) 반드시 낡으므로, 믿을 것은 상태가 아니라 확인 방법이다.

아래 세 절도 요약 → 상세(펼치기) 구조다. 아이콘은 ✅ 구현됨 · 🟡 부분 · ❌ 미구현 · ⚪ 미측정이며, 실제로 무엇이 됐고 안 됐는지는 상세의 괄호 안 서술이 정본이다.

보안 (SEC)

ID 요구사항 (요약) 상태
SEC-001 통신 구간 암호화 (TLS + DB 인증서 검증까지) ❌
SEC-002 비밀번호 해시 저장, 알고리즘 한계 초과 입력 거부 ✅
SEC-003 계정·신원 분리 식별 (이메일로 사람 식별 안 함) ✅
SEC-004 만료형 토큰, 변경·탈퇴 시 즉시 무효화 ✅
SEC-005 자기 자원만 접근, 추측 불가능한 슬러그 🟡
SEC-006 삭제 시 DB 행 + 객체 저장소 원본까지 함께 삭제 🟡
SEC-007 영상 속 제3자 동의 절차·삭제 요청 경로 ❌
SEC-008 업로드 파일을 실제 컨테이너 형식으로 검증 🟡
SEC-009 인증 엔드포인트 남용 방지 제한 (계정 잠금 방식은 안 씀) 🟡
SEC-010 인증 이벤트 로깅 (비밀번호·토큰은 기록 안 함) ✅
SEC-011 시크릿은 배포 환경 주입, 기본값 없이 실패 ✅
SEC-012 계정 존재 여부 비노출 (가입 중복 안내는 예외) 🟡
상세 — 요구사항 전문 · 확인 방법 · 근거
ID 요구사항 확인 방법 상태
SEC-001 모든 통신 구간을 암호화한다. 클라이언트–서버는 TLS, 애플리케이션–DB는 인증서 검증까지 수행한다. 검증 없는 암호화(sslmode=require)는 중간자 공격을 막지 못한다 접속 문자열에 sslmode=verify-full과 CA 번들 경로가 있는지 미구현
SEC-002 비밀번호는 평문으로 저장·기록·전송하지 않는다. 해시(bcrypt)만 보관하며, 알고리즘 한계(72바이트)를 넘는 입력은 잘라내지 않고 거부한다 — 자동으로 잘리면 앞부분만 같아도 통과한다 user_credential.password_hash가 $2b$로 시작. app/core/password.py 구현됨
SEC-003 계정과 신원을 분리해 식별한다. 계정은 user.email 유일 제약으로, 외부 로그인은 제공자가 준 subject로 식별한다 — 이메일로 사람을 식별하지 않는다. 자격증명은 user와 분리된 테이블에 둔다 부록 D.7의 유일 제약 3건(user.email, user_identity(provider, subject), user_identity(user_id, provider)) 구현됨
SEC-004 인증은 만료가 있는 Bearer 토큰으로 한다. 비밀번호 변경·탈퇴 시 기존 토큰이 즉시 무효가 되어야 한다 비밀번호 변경 후 옛 토큰으로 GET /me → 401 구현됨
SEC-005 자기 자원에만 접근할 수 있다. 공개 링크는 추측 불가능한 슬러그로만 열고, 내부 식별자(uuid)를 공개 경로에 노출하지 않는다 남의 식별자로 요청 → 404. 슬러그가 이름에서 유도되지 않고 무작위인지 부분 (본인 조회는 토큰 기준. 슬러그 생성 규칙은 2026.09.02에 정했다 — 96비트 무작위, 닉네임에서 유도하지 않는다)
SEC-006 삭제 요청 시 원본과 모든 파생물을 함께 삭제한다. DB 행뿐 아니라 객체 저장소의 원본·썸네일·추출 프레임·임베딩을 포함한다 — 외래키 연쇄만으로는 저장소에 원본이 남는다 부록 D.6의 연쇄 경로. 삭제 후 해당 객체 키 조회 → 404 부분 (DB 연쇄는 외래키로 걸었다 — DELETE /me. 저장소는 S3 로 정했지만(2026.09.03) 탈퇴가 객체까지 지우지는 않아 원본이 남는다)
SEC-007 영상에는 업로더 외의 인물(상대 팀·관중)이 함께 촬영된다. 업로드 시 동의 절차를 두고, 촬영된 제3자의 삭제 요청 경로를 제공한다 업로드 화면의 동의 항목, 제3자 삭제 요청 접수 경로의 존재 미구현
SEC-008 업로드 파일은 확장자가 아니라 실제 컨테이너 형식으로 검증한다. 용량·길이·해상도 상한을 두고, 디코딩·메타 추출은 애플리케이션 프로세스 밖에서 수행한다 video_validation의 반려 사유. 확장자만 바꾼 파일이 반려되는지 부분 (Content-Type 화이트리스트(mp4 · mov)와 용량·길이·해상도 상한이 있고 반려 사유가 video_validation 에 남는다. 실제 컨테이너 형식은 검사하지 않는다 — 길이·해상도는 클라이언트가 잰 값이고, 서버가 다시 재려면 원본을 내려받아야 해 PER-002 와 부딪힌다)
SEC-009 인증 엔드포인트에 남용 방지 제한을 둔다. 해싱은 의도적으로 느리므로 인증 요청 자체가 자원 소모 수단이 된다. 계정 잠금 방식은 쓰지 않는다 — 남의 이메일을 아는 것만으로 그 계정을 잠글 수 있어 그 자체가 서비스 거부 수단이 된다 동일 출처에서 임계값 초과 요청 → 429 부분 (프로세스 안에서만 센다 — 서버를 여러 대로 늘리면 공유 저장소가 필요하다)
SEC-010 인증 관련 사건(로그인 성공·실패, 토큰 거부)을 사후에 추적 가능한 형태로 기록한다. 비밀번호·토큰·Authorization 헤더는 기록하지 않는다 로그에 password/Bearer 문자열이 남지 않는지 검사 구현됨
SEC-011 시크릿은 저장소에 두지 않고 배포 환경에서 주입한다. 값이 없으면 조용한 기본값 대신 실패한다 — 기본값이 있으면 그 값으로 서명한 토큰을 누구나 만들 수 있다 JWT_SECRET 없이 로그인 → 503(AUTH_NOT_CONFIGURED) 구현됨
SEC-012 실패 응답과 공개 인터페이스가 계정 존재 여부를 드러내지 않는다. 로그인은 “없는 이메일”과 “틀린 비밀번호”를 구분하지 않는다. API 문서와 데모 자격증명은 개발 환경에서만 노출한다 미가입 이메일과 가입된 이메일의 로그인 실패 응답이 동일한지. 운영 환경에서 /docs 접근 → 404 부분 (/docs는 닫았고 로그인은 구분하지 않으나, 가입은 중복을 알려준다 — 아래 예외)

SEC-012의 예외를 명시해 둔다. 가입은 “이미 가입된 이메일입니다”를 알려주어야 사용자가 다음 행동을 정할 수 있으므로, 계정 열거를 감수하고 안내하는 쪽을 택한다. 대신 SEC-009의 요청 제한으로 대량 열거의 비용을 올린다. 이는 판단이지 누락이 아니다.

성능 (PER)

ID 요구사항 (요약) 상태
PER-001 영상 분석 비동기 처리, 작업 상태·소요시간 기록 🟡
PER-002 업로드·재생이 앱 서버를 경유하지 않음 (사전 서명 URL) 🟡
PER-003 조회 API 응답 P95 500ms 이내 ⚪
상세 — 요구사항 전문 · 확인 방법 · 근거
ID 요구사항 확인 방법 상태
PER-001 영상 분석은 비동기로 처리한다. 업로드 응답이 분석 완료를 기다리지 않으며, 작업의 상태와 소요 시간을 analysis_job에 기록한다. 목표 소요 시간은 6장 4)의 실측으로 확정한다 업로드 응답 시각과 분석 완료 시각이 분리되어 기록되는지 부분 (analysis_job 에 status 와 created_at·started_at·finished_at 세 시각이 따로 있고, 등록 응답은 분석을 기다리지 않는다. 워커가 집고 끝내는 경로도 열렸다 — POST /internal/analysis-jobs/claim · PATCH /internal/analysis-jobs/{job_id}, 2026.09.04. 실제 폴링 워커는 아직 안 붙었다(미결 jin 18번))
PER-002 영상 업로드·재생은 애플리케이션 서버를 경유하지 않는다(객체 저장소 사전 서명 URL). 앱 서버가 대용량 전송을 떠안으면 무관한 API 응답까지 함께 느려진다 업로드 트래픽이 API 서버를 통과하지 않는지 부분 (업로드는 사전 서명 URL 로 S3 에 직접 올라가 앱 서버를 지나지 않는다(2026.09.03). 재생 경로는 아직 없다 — 내려받을 URL 을 내주는 자리가 없다)
PER-003 조회 API 응답은 P95 500ms 이내 부하 시험. 부록 D.4가 벡터 검색의 4단 조인을 가장 위험한 지점으로 지목한다 미측정

품질 (QUA)

ID 요구사항 (요약) 상태
QUA-001 측정 결정론적 재현성 (같은 영상 → 같은 수치) ✅
QUA-002 지표 산출 버전 기록 ✅
QUA-003 자동 검증 통과한 변경만 병합 (skip을 통과로 안 봄) ✅
상세 — 요구사항 전문 · 확인 방법 · 근거
ID 요구사항 확인 방법 상태
QUA-001 측정은 결정론적이다. 같은 영상은 언제나 같은 수치를 낸다. 판단(언어 모델)만 비결정적이며, 그 결과에도 근거가 된 측정값과 프레임 번호를 함께 남긴다 같은 영상을 두 번 분석해 analysis_metric_value가 일치하는지 구현됨 (2026-09-09 실측 — 같은 영상을 5번 분석해 4편 모두 지표값이 소수 끝자리까지 같고 총점 표준편차 0.00. 분석 결과로 쟀고, 백엔드는 그 지표값을 그대로 적재한다. 같은 실행 환경에서 잰 값이다)
QUA-002 지표 산출에는 산출 버전을 기록한다. 채점 기준이 바뀌어도 과거 결과가 어느 버전으로 산출된 것인지 판별할 수 있어야 한다 analysis_metric의 버전 값이 비어 있지 않은지 구현됨 (분석 결과마다 채점 기준 버전과 파이프라인 버전을 함께 저장한다. 보고서에 버전이 빠지면 「unknown」으로 남는다)
QUA-003 자동 검증을 통과한 변경만 병합한다. 특히 DB 통합 테스트가 건너뛴 채 초록으로 끝나지 않아야 한다 — 통과와 “한 줄도 실행하지 않음”이 구별되지 않으면 검증이 아니다 .github/workflows/backend-tests.yml의 마지막 단계가 skipped를 exit 1로 잡는다 구현됨

이 절에 넣지 않은 것

  • 백업·재해복구(RPO·RTO) — 운영 인프라가 확정된 뒤에 적는다. 지금 숫자를 적으면 근거 없는 값이 된다.
  • 다중 인증(MFA)·단말 관리 — 10주 개발 범위 밖이다.
  • 수치 능력치·순위표 미노출(3.5) — 성능이나 보안이 아니라 서비스 설계 원칙이므로 아래 3) 제약사항에서 다룬다.

3) 제약사항 및 전제조건

1)절이 “무엇을 하는가”, 2)절이 “어떤 조건에서 동작해야 하는가”라면 이 절은 “무엇을 할 수 없는가”와 “무엇을 참으로 놓고 설계했는가”다.

둘을 나누어 적는다. 제약(CON)은 우리가 바꿀 수 없는 조건이고, 전제(ASM)는 참이라고 가정한 것이다. 전제는 깨질 수 있으므로 깨지면 무엇이 무너지는지를 함께 적는다. 적어 두지 않으면 전제가 사실로 굳어, 틀렸을 때 어디부터 다시 봐야 하는지 알 수 없다.

번호는 이 절에서 처음 매긴다 — 다른 문서가 아직 인용하지 않는다.

제약사항 (CON)

ID 제약 영향 대응
CON-001 개발 기간 10주(2026.08.20~10.27), 인원 4명 서비스 전 범위를 만들 수 없다 과금 도메인·MFA·백업(RPO·RTO)을 범위 밖으로 두고, 2)절에 “넣지 않은 것”으로 명시한다
CON-002 필수 투입자원 목록에 MediaPipe·Ollama·llama.cpp가 없다 포즈 추정과 모델 서빙을 통상적인 조합으로 짤 수 없다 OpenCV + Transformers로 구성한다(6장 2)·4)). ViTPose로 COCO-17 키포인트를 뽑는다
CON-003 개발 GPU가 RTX 3050 8GB(상시 점유분 제외 약 7.4GB) 포즈 추정기와 판정 모델을 동시에 올릴 수 없다 추출과 판정을 순차로 적재한다. 32B급은 24GB 이상이 필요하므로 조달 여부는 미결 4번
CON-004 판정 모델(EXAONE)의 라이선스가 NC(비상업) 수익 모델을 전제한 서비스와 충돌한다 상업 라이선스 확인, 불가 시 Apache-2.0/MIT 계열로 교체. 교체 범위는 판정 백엔드 한 곳이라 루브릭·스키마·파이프라인은 재사용된다(미결 1번)
CON-005 지도자가 라벨링한 골든셋이 아직 없다 — 섭외 여건이 안 됨을 확인(2026.09.09) QWK·MAE는 정의 자체가 안 됨(사람 라벨과 비교하는 지표라 대체 불가) 골든셋 없이 잴 수 있는 재현성·fps 불변성·지표 타당성을 1차 검증 지표로 쓴다(3장 「검증 기준」, 미결 2·34번). 등급 경계 근거는 지도자 검수 대신 문헌 인용으로 낮춘다. 골든셋 확보는 여건이 되는 대로 진행하는 별도 트랙
CON-006 루브릭은 (종목, 동작) 단위로만 성립한다 — 같은 지표가 동작에 따라 반대로 채점된다 종목 단위로 열 수 없다 축구·야구·농구 종목당 1동작만 연다. 나머지는 검수 대기(미결 3번, 08.26 해소)
CON-007 던지는 팔·차는 발의 자동 판별이 팔 종목에서 신뢰할 수 없다 잘못 고른 쪽으로 채점하면 지표 전체가 무의미해진다 업로드 시 사람이 지정할 수 있게 열고, 지정이 없을 때만 자동 판별을 쓴다(미결 6번)
CON-008 임팩트 탐색 범위가 클립 전체다 — 신전 각속도의 전역 최댓값을 쓰므로 동작과 무관한 구간(와인드업·드리블 주행)이 실제 임팩트를 이긴다 야구·농구뿐 아니라 축구도 채점 기준이 확정되지 않았다. 접촉 지점의 신호는 언제나 상위권인데 근소한 차이로 진다 탐색 범위를 좁히는 것이 선행이다. 검증에 팔 종목 릴리스 정답 25~60클립이 필요해 확보 전까지 보류(미결 5번, 2026.08.31 재정의)
CON-009 영상은 사용자가 직접 촬영해 올린다 — 촬영 환경을 통제할 수 없다 카메라 거리·각도가 다르면 같은 자세도 다른 수치가 된다 어깨 너비 기준 스케일 정규화와 골반 중심 이동, 그리고 촬영 가이드 + video_validation 규격 검사(3장 3))

전제조건 (ASM)

ID 전제 깨지면 확인 시점
ASM-001 사용자가 촬영 가이드(측면·전신·최소 해상도)를 따른다 키포인트 품질이 낮아 신뢰도 “낮음” 표기가 대량 발생한다. 정규화로 흡수되지 않는 편차다 실클립 검증(스프린트 2)
ASM-002 저장소는 PostgreSQL + pgvector다 SFR-005의 성향 벡터 검색을 다시 설계해야 한다 인프라 확정 시
ASM-003 영상 원본은 객체 저장소에 두고 업로드·재생이 앱 서버를 경유하지 않는다(PER-002) 앱 서버가 대용량 전송을 떠안아 무관한 API까지 느려진다. SEC-006의 삭제 연쇄도 저장소 객체까지 넓혀야 한다 확정 (2026.09.03) — 버킷 supersub-ai. 업로드는 앱 서버를 안 지난다. 재생과 SEC-006의 객체 삭제는 남았다
ASM-004 라벨링·검수를 맡을 지도자를 섭외할 수 있다 CON-005와 물려 채점 품질을 아예 검증할 수 없다. 루브릭 임계값도 임시값으로 남는다 깨짐 — 섭외 불가로 확인 (2026.09.09). 대응은 CON-005 갱신 내용 참고(미결 34번)
ASM-005 외부 로그인은 구글 하나만 지원하며, 배포 전에는 등록된 테스트 계정으로만 검증된다 일반 사용자가 구글 로그인을 쓸 수 없다 — 동의 화면 게시가 배포의 선행 조건이 된다 앱 배포 전
ASM-006 판정 모델을 자체 호스팅한다 — 분석 1회당 외부 API 비용이 없다 호출량에 비례하는 비용이 생긴다. 4장은 아직 원가를 다루지 않으므로(수익 항목만 있다) 그쪽을 채울 때 이 전제가 출발점이 된다 모델 교체 검토 시 — CON-004(EXAONE NC 라이선스)가 외부 API 로 가는 순간 깨진다(미결 1번)
ASM-007 운영 배포 환경은 아직 없다 지금은 확정할 수 없는 항목이 있다는 뜻이다 — SEC-001(sslmode=verify-full), PER-003 실측, SEC-009 요청 제한의 공유 저장소가 여기에 걸려 있다 EC2 에 올랐다 (2026.09.03, 미결 jin 8번) — SEC-001의 verify-full 은 배포 문서가 지시하지만 코드 기본값은 아직 require 다

서비스 설계 원칙으로 두는 제약

성능이나 보안이 아니라 무엇을 일부러 만들지 않는가에 대한 결정이라 이 절에 둔다. 2)절에서 넘겨받은 항목이다. 전부 부록 D의 D.5에서 스키마 구조로 강제되어 있다 — 코드에만 두면 지켜지지 않기 때문이다.

원칙 스키마로 어떻게 막는가
카드에 수치 능력치를 노출하지 않는다 player_card에 능력치 컬럼을 두지 않는다. 수치는 리포트 경로로만 조회된다
전체 순위표를 두지 않는다 사용자 간 비교 점수를 저장하는 테이블이 없다. fitness_score는 지원 건에 종속된다
호칭은 미부여 방식으로만 작동한다 user_title에는 부여된 행만 있다. 미달을 false로 저장하면 그 자체가 부정 표식이 된다
제재는 평가가 아니라 기록으로 처리한다 report·no_show를 review와 분리한다
매칭 확정은 사람이 한다 match_application이 팀·본인의 수락 시각을 각각 갖는다

이 절에 넣지 않은 것

  • 팀 구성과 일정 — 7장 개발 구현 계획에서 다룬다.
  • 수익 모델의 전제(가격·전환율) — 4장의 몫이다. 여기서는 원가에 영향을 주는 ASM-006만 적는다.
  • 미결 항목의 진행 상황 — 미결 항목 페이지가 담당자·기한과 함께 관리한다. 이 절은 그것이 요구사항에 어떤 제약으로 걸리는지만 적는다.

← 목차로