Tickmark 요구사항 명세서
1. 목적과 범위
Tickmark는 감사인과 AI가 협업하는 감사 Work OS의 축소판이다. 첫 업무인 분개 테스트에서 의심 전표를 선별하고, AI 제안과 사람의 결론 및 검토를 연결해 판단 근거를 추적하는 것이 목적이다. 이 문서는 무엇을 제공해야 하는지와 기준 커밋에서 어디까지 구현했는지를 구분한다. 사용자 동작과 처리 순서는 기능 정의서에 둔다.
MVP는 감사 대상 생성, 멤버 추가, 합성 GL 적재, 룰 8종 실행, AI 트리아지 요청, 작성자 결론, 검토자 승인 또는 반려, 감사 로그 조회까지다. AI는 제안만 하고 판단과 서명은 사람이 한다. 제품 전체 성공 조건은 3분 시연, mix precommit 통과, 외부 데모 URL 및 README 제공이다. 구현 코드가 있다는 사실과 시연 및 배포 완료는 별개다. 근거: MVP 1-3, 7장, WBS M0-M6.
제외 범위
| 범위 |
처리 |
근거 |
| 실제 고객 데이터, 외부 ERP 연동 |
MVP 제외. 저장소와 데모에는 합성 데이터만 사용 |
MVP 4장, AGENTS.md 1, 8장 |
| 다중 통화 |
MVP는 KRW만 지원 |
MVP 4-5장 |
| 외부 이메일 전달 인프라 |
로컬 메일박스로 대체. 배포용 메일 및 데모 계정은 확인 필요 |
MVP 4장, 계약 12.4 |
| 세분된 조직 권한, 멤버 역할 변경 및 삭제 UI |
preparer, reviewer와 생성자 예외만 제공; 변경/삭제 공개 함수 없음 |
MVP 4장, Tickmark.Engagements.Policy.allowed?/2, lib/tickmark/engagements.ex |
| OpenTelemetry, Terraform + Azure, ClickHouse + Benford, Ash 실험, 두 번째 감사 절차 |
2단계 |
MVP 3장, WBS M7 |
| 생성기 목표 행 수 조절, 감사 대상별 룰 파라미터 편집 |
MVP 미지원. 생성기는 seed만, 룰은 기본 파라미터 스냅샷 |
도메인 7.1, 8장, 계약 2.1, Tickmark.Ledger.Generator.generate/1 |
| 감사 로그의 단순 조회 이력 |
현재 조회 자체는 기록하지 않음. 2단계 검토 |
화면 S6.2, Tickmark.AuditTrail.list_events/3 |
2. 용어와 ID 체계
| 용어 |
뜻과 코드 대응 |
| 감사 대상 |
회사와 회계연도로 구분하는 engagement; 권한과 데이터 경계 |
| GL / 전표 / 행 |
총계정원장 파일 / journal_entries / journal_lines; 같은 전표번호의 행들을 묶음 |
| 적재 |
ledger_imports: pending, processing, succeeded, failed |
| 테스트 실행 |
test_runs: running, completed, completed_with_errors; 룰별 상태는 queued, running, succeeded, skipped, failed |
| 검토 항목 |
finding: 한 실행에서 적중한 전표 1건; 전표의 부정 확정을 뜻하지 않음 |
| 룰 점수 / 검토 큐 |
적중 가중치 합의 상한 100 / 실행에 저장한 triage_threshold 이상인 항목; 기본 25 |
| AI 제안 |
ai_triages; triage_status는 none, queued, succeeded, failed; 사람 상태와 독립 |
| 사람 결론 |
conclusions.outcome: no_exception(이상 없음), needs_follow_up(추가 확인 필요), exception(예외) |
| 검토 상태 |
findings.status: open, concluded, approved, rejected; review_decisions.decision은 approved, rejected |
| 직무 분리 |
결론 작성자와 검토자가 달라야 함; 역할 변경 이력이 있어도 자기 결론 검토 금지 |
| 감사 이벤트 |
audit_events; 실제 action과 행위자 유형 user, agent, system을 저장; seq는 정렬용 DB 부여 값이며 결번 없음은 보장하지 않음 |
근거: 계약 3-5, 8장; lib/tickmark/testing/{test_run,finding}.ex, lib/tickmark/review/{conclusion,review_decision}.ex, lib/tickmark/audit_trail/audit_event.ex. 함수 표기의 Engagements, Ledger, Testing, Triage, Review, AuditTrail, AI, Accounts는 모두 Tickmark 아래 모듈이다.
| ID |
의미 |
규칙 |
REQ-{영역}-{nn} |
기능 요구사항 |
ACC, ENG, GL, RUN, AI, REV, AUD, UI; 영역 안에서 순번 |
NFR-{nn} |
비기능 요구사항 |
문서 전체 순번 |
FN-{영역}-{nn} |
기능 정의 |
S1-S6, AUTH, SYS; 기능 정의서 참조 |
| S1-S6 |
화면 |
목록, 감사 대상 상세, GL 불러오기, 테스트 실행, 전표 검토, 감사 로그 |
WBS n.n |
작업 분해 항목 |
WBS 문서의 기존 번호를 그대로 사용 |
ID 근거는 계약 12.4다. 표의 문서 약칭은 머리의 관련 문서 링크를 가리킨다. 코드 경로와 테스트 경로는 저장소 상대 경로다.
| 상태 |
이 문서에서의 의미 |
| 구현 |
기준 커밋에 코드와 관련 테스트가 있음. 이번 문서 작업에서 테스트를 재실행했다는 뜻은 아님 |
| 부분 |
백엔드 또는 일부 화면만 있음 |
| 미구현 |
계획만 있고 해당 동작을 제공하지 않음 |
| 진행 중 |
기준 커밋에서는 미완료이고 W6, F1, F2에 배정됨. 향후 브랜치 결과를 현재 사실로 포함하지 않음 |
| 확인 필요 |
소스만으로 결과를 확정할 수 없거나 통합·운영 검증이 남음 |
우선순위는 MVP 필수, MVP 선택, 2단계로 구분한다. 별도 성능 SLA나 보안 인증 기준은 합의되지 않았으므로 임의의 목표치를 만들지 않는다.
3. 이해관계자와 역할
| 이해관계자 |
책임과 기대 |
작성자 (preparer) |
GL과 룰 결과, AI 제안을 검토하고 자기 결론 및 코멘트를 제출 |
검토자 (reviewer) |
최신 결론과 증거를 읽고 승인하거나 사유를 붙여 반려 |
| 감사 대상 생성자 |
생성 시 작성자 멤버가 되며 이미 가입한 사용자를 멤버로 추가 |
AI (agent) |
위험도와 추가 절차만 제안. 사용자 멤버 역할이 아님 |
시스템 (system) |
적재, 룰, 트리아지 잡 수행 및 감사 기록. 사용자 역할이 아님 |
| 개발자 / 포트폴리오 평가자 |
요구사항, 구현 근거, 테스트, 미완료 범위를 추적 |
실제 권한표
| 권한 / 행동 |
preparer |
reviewer |
비멤버 |
검사 위치 |
| S1 목록 및 신규 생성 |
로그인하면 가능 |
로그인하면 가능 |
로그인하면 가능 |
UserAuth, Engagements.list_engagements/1, create_engagement/2 |
:view |
허용 |
허용 |
거부 |
Engagements.authorize/3 |
:import_ledger |
허용 |
거부 |
거부 |
Policy.allowed?/2, Ledger |
:start_test_run |
허용 |
거부 |
거부 |
Policy.allowed?/2, Testing.Runner |
:request_triage |
허용 |
거부 |
거부 |
Policy.allowed?/2, Triage |
:submit_conclusion |
허용 |
거부 |
거부 |
Policy.allowed?/2, Review |
:review_conclusion |
거부 |
허용, 자기 결론 제외 |
거부 |
Review.decide/4, DB CHECK 및 복합 FK |
:manage_members |
생성자인 멤버만 |
생성자인 멤버만 |
거부 |
Policy는 모두 false; Engagements.authorize/3의 별도 생성자 검사 |
| 정의하지 않은 권한 |
거부 |
거부 |
거부 |
Policy.allowed?/2의 기본 false |
근거: lib/tickmark/engagements/policy.ex:10, Engagements.authorize/3; test/tickmark/engagements/policy_test.exs, authorization_test.exs. 생성자는 별도 역할명이 아니며 기본 생성 흐름에서는 preparer다. 한 감사 대상에서 한 사용자는 하나의 역할만 가지며 (engagement_id, user_id) unique 제약이 중복을 막는다.
직무 분리는 화면 버튼, context, DB에서 나누어 보장한다. 승인·반려는 concluded에만 가능하고 화면에서 본 conclusion_id가 최신이어야 한다. Review.decide/4는 권한, finding 잠금 및 상태, 최신 결론, 자기 검토 순으로 검사한다. 작성자 역할의 검토 시도는 review.denied의 reason=role, 과거 자기 결론을 가진 검토자의 시도는 reason=self_review다. 비멤버의 시도는 감사 대상을 오염시키지 않도록 기록하지 않는다. DB의 reviewer_not_preparer CHECK와 (conclusion_id, preparer_id) 복합 FK가 우회를 막는다. 근거: 계약 8장, lib/tickmark/review.ex, priv/repo/migrations/20261017110531_create_review.exs, test/tickmark/review_test.exs.
4. 기능 요구사항
수락 기준은 향후 확인할 조건이며, 괄호의 테스트는 현재 존재하는 근거다. 미구현 화면의 테스트가 있다고 오인하지 않도록 백엔드 테스트와 화면 검증 대기를 구분했다.
4.1. 계정과 인증
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-ACC-01 |
이메일로 계정을 만들고 확인용 로그인 링크를 제공해야 한다. |
MVP 3장; 계약 12.4; Accounts.register_user/1 |
MVP 필수 |
이메일 필수·최대 160자·중복 거부; 성공 시 로그인 화면 이동 (test/tickmark_web/live/user_live/registration_test.exs) |
AUTH, S1 |
구현 (한글화는 진행 중 F2) |
| REQ-ACC-02 |
유효한 매직 링크로 계정 확인과 로그인을 처리해야 한다. |
MVP 3장; Accounts.login_user_by_magic_link/1 |
MVP 필수 |
미등록 이메일에도 같은 요청 안내; 만료·재사용 링크 거부 (test/tickmark/accounts_test.exs, test/tickmark_web/live/user_live/confirmation_test.exs) |
AUTH, S1 |
구현 |
| REQ-ACC-03 |
설정한 비밀번호로 로그인할 수 있어야 한다. |
MVP 3장; Accounts.get_user_by_email_and_password/2 |
MVP 필수 |
정상 자격으로 세션 생성; 실패는 이메일 존재 여부를 구분하지 않는 문구 (test/tickmark_web/controllers/user_session_controller_test.exs) |
AUTH, S1 |
구현 |
| REQ-ACC-04 |
로그아웃 시 세션과 로그인 유지 쿠키를 해제해야 한다. |
MVP 3장; TickmarkWeb.UserAuth.log_out_user/1 |
MVP 필수 |
저장 세션 토큰 삭제; 연결된 세션에 disconnect (test/tickmark_web/user_auth_test.exs) |
AUTH, S1-S6 |
구현 |
| REQ-ACC-05 |
최근 인증을 확인한 뒤 이메일과 비밀번호를 변경할 수 있어야 한다. |
계약 12.4; Accounts.sudo_mode?/1, update_user_email/2, update_user_password/2 |
MVP 필수 |
재인증 필요 시 로그인 이동; 이메일 확인 링크와 비밀번호 12-72자·최대 72바이트 검증 (test/tickmark_web/live/user_live/settings_test.exs, test/tickmark/accounts_test.exs) |
AUTH |
구현 (한글화는 진행 중 F2) |
| REQ-ACC-06 |
S1-S6에 접근하기 전에 로그인 여부를 검사해야 한다. |
MVP 3장; 계약 2장; lib/tickmark_web/router.ex |
MVP 필수 |
미인증 HTTP와 LiveView 연결 모두 로그인으로 이동 (test/tickmark_web/engagement_routes_test.exs, test/tickmark_web/user_auth_test.exs) |
S1-S6 |
구현 |
4.2. 감사 대상과 멤버
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-ENG-01 |
사용자가 멤버인 감사 대상만 최신 생성순으로 보여야 한다. |
화면 S1.1; Engagements.list_engagements/1 |
MVP 필수 |
다른 대상 제외; 최근 실행 상태·검토 큐와 내 역할 표시 (test/tickmark/engagements_test.exs, test/tickmark_web/live/engagement_live_test.exs) |
S1 |
구현 |
| REQ-ENG-02 |
회사명·회계연도·결산일·수행중요성으로 감사 대상을 생성해야 한다. |
MVP 2장; 화면 S1.2; Engagements.create_engagement/2 |
MVP 필수 |
회사명 1-200자, 연도 2000-2100, 결산일 필수, 금액 0 초과; 실패 시 생성 없음 (test/tickmark/engagements_test.exs) |
S1 |
구현 |
| REQ-ENG-03 |
감사 대상 생성자와 작성자 멤버 및 생성 이벤트를 함께 저장해야 한다. |
계약 2.1, 4장; Engagements.create_engagement/2 |
MVP 필수 |
생성자 ID는 scope에서 취함; 대상·멤버·이벤트 원자적 저장 (test/tickmark/engagements_test.exs: creates the engagement, the preparer membership and the audit event) |
S1 |
구현 |
| REQ-ENG-04 |
감사 대상 생성자만 가입된 사용자를 역할과 함께 추가할 수 있어야 한다. |
MVP 3장; 화면 S2.3; Engagements.add_member/4 |
MVP 필수 |
없는 이메일·권한 없음·기존 멤버를 구분; 성공 시 engagement.member_added (test/tickmark/engagements_test.exs, test/tickmark_web/live/engagement_live_test.exs) |
S2 |
구현 |
| REQ-ENG-05 |
한 감사 대상의 멤버는 작성자 또는 검토자 한 역할만 가져야 한다. |
MVP 4장; 계약 3.2; Tickmark.Engagements.Member.changeset/2 |
MVP 필수 |
허용 역할은 preparer, reviewer뿐; 멤버 중복 unique 거부 (test/tickmark/schemas_test.exs, test/tickmark/engagements/policy_test.exs) |
S2 |
구현 |
| REQ-ENG-06 |
감사 대상 상세에 멤버·적재·실행 이력과 최신 기준의 통계를 표시해야 한다. |
화면 S2.1; Ledger.list_imports/2, Testing.list_test_runs/2, count_findings/2 |
MVP 필수 |
전표·행은 최신 성공 적재 기준; 검토 큐·경미·승인은 최신 종료 실행 기준 (test/tickmark_web/live/engagement_live_test.exs) |
S2 |
구현 (검토 후 통계 갱신 제한은 8장) |
4.3. GL 적재와 합성 생성
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-GL-01 |
작성자가 CSV 파일을 선택하거나 끌어 놓아 적재를 요청할 수 있어야 한다. |
MVP 3장; 화면 S3.1, S3.6; Ledger.create_import/3 |
MVP 필수 |
.csv 1개·20,000,000바이트 제한; 검토자의 조작 이벤트 거부 (test/tickmark_web/live/import_live_test.exs) |
S3 |
구현 |
| REQ-GL-02 |
GL 계약의 16개 컬럼을 이름으로 찾고 타입과 필수값을 검증해야 한다. |
MVP 5장; 계약 9.2; Tickmark.Ledger.CsvParser.parse/3 |
MVP 필수 |
순서 변경·UTF-8 BOM·CRLF 허용; 누락·중복·알 수 없는 컬럼과 잘못된 값 거부 (test/tickmark/ledger/csv_parser_test.exs) |
S3 |
구현 |
| REQ-GL-03 |
전표의 차대 균형·헤더 일관성·행 번호 유일성과 연속 배치를 검증해야 한다. |
MVP 5장; Tickmark.Ledger.CsvParser.parse/3 |
MVP 필수 |
원 단위 금액·한쪽만 양수; 후반 오류도 전체 적재 롤백 (test/tickmark/ledger/csv_parser_test.exs, test/tickmark/ledger_test.exs) |
S3 |
구현 |
| REQ-GL-04 |
적재 오류와 경고를 안전한 고정 문구 및 발생 위치로 안내해야 한다. |
화면 S3.2, S3.5; lib/tickmark_web/live/import_live/components.ex |
MVP 필수 |
오류·경고 각 최대 100건과 전체 수; 기간 불일치는 경고만, 13기는 예외 (test/tickmark_web/live/import_live_test.exs, test/tickmark/ledger/csv_parser_test.exs) |
S3 |
구현 |
| REQ-GL-05 |
정수 시드로 동일한 합성 GL과 이상 전표를 재현할 수 있어야 한다. |
MVP 3장; 도메인 7.1-7.5; Tickmark.Ledger.Generator.generate/1 |
MVP 필수 |
기본 seed 20251231; 같은 seed는 동일 바이트, 미지원 옵션 거부 (test/tickmark/ledger/generator_test.exs) |
S3 |
구현 |
| REQ-GL-06 |
정답 라벨은 별도 파일로 만들고 룰·AI 입력과 분리해야 한다. |
도메인 7.6; 계약 2.1; Ledger.generate_sample_import/3 |
MVP 필수 |
GL과 라벨 전표 1:1; 라벨은 DB에 적재하지 않으며 Runner 결과와 대조 (test/tickmark/testing/runner_label_test.exs, test/tickmark/ledger/generator_test.exs) |
S3, S4 |
구현 |
| REQ-GL-07 |
적재 요청 뒤 화면을 떠나도 처리하고 결과를 조회할 수 있어야 한다. |
계약 5.1; 화면 S3.3; Ledger.process_import/1 |
MVP 필수 |
pending·processing·succeeded·failed 표시; 선택한 적재의 메시지만 반영 (test/tickmark_web/live/import_live_test.exs, test/tickmark/ledger/import_worker_test.exs) |
S2, S3 |
구현 |
| REQ-GL-08 |
각 적재의 원본 파일명·출처·크기·해시와 집계 결과를 보존해야 한다. |
계약 3.3, 4.2; Ledger.create_import/3 |
MVP 필수 |
파일명은 basename, 저장명은 UUID; SHA-256과 성공 시 전표·행·차대 합계 기록 (test/tickmark/ledger_test.exs) |
S2, S3 |
구현 |
4.4. 테스트 실행과 룰
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-RUN-01 |
성공한 GL에 대해 작성자가 룰 테스트를 시작하거나 종료 후 재실행할 수 있어야 한다. |
MVP 2장; 화면 S2.3; Testing.start_test_run/3 |
MVP 필수 |
실패·미완료 적재 거부; 현재 감사 대상과 다른 적재 ID 거부 (test/tickmark/testing/runner_test.exs, test/tickmark_web/live/engagement_live_test.exs) |
S2, S4 |
구현 |
| REQ-RUN-02 |
같은 GL의 동시 실행을 제한하고 실행 조건과 룰별 잡을 함께 저장해야 한다. |
계약 5.3; Tickmark.Testing.Runner.start_test_run/3 |
MVP 필수 |
실행 중 하나만 허용; 기본 파라미터·기준점수 스냅샷과 룰당 잡 하나 (test/tickmark/testing/runner_test.exs) |
S2, S4 |
구현 |
| REQ-RUN-03 |
룰별 진행률과 실패·미실행을 구분하여 종료 결과를 표시해야 한다. |
화면 S4.1-S4.3; 계약 5.4; Testing.run_rule/2, fail_rule/3 |
MVP 필수 |
모든 룰 종료 뒤 finding 생성; 실패 포함 시 completed_with_errors, skipped는 실패 아님 (test/tickmark/testing/runner_test.exs, test/tickmark_web/live/test_run_live_test.exs) |
S4 |
구현 |
| REQ-RUN-04 |
주말 또는 등록된 공휴일의 수기 전표를 탐지해야 한다. |
도메인 2.2, 2.10; Tickmark.Testing.Rules.WeekendHolidayPosting.run/1 |
MVP 필수 |
토·일과 holiday_table 적중, system 제외; 가중치 15 (test/tickmark/testing/rules/weekend_holiday_posting_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-05 |
KST 업무시간 밖에 입력된 수기 전표를 탐지해야 한다. |
도메인 2.3; Tickmark.Testing.Rules.OffHoursEntry.run/1 |
MVP 필수 |
08:00 미만 또는 20:00 이상 적중; 가중치 10 (test/tickmark/testing/rules/off_hours_entry_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-06 |
기준 금액 이상의 라운드 금액 수기 전표를 탐지해야 한다. |
도메인 2.4; Tickmark.Testing.Rules.RoundAmount.run/1 |
MVP 필수 |
차변 합계 10,000,000원 이상이며 1,000,000원 배수; 가중치 10 (test/tickmark/testing/rules/round_amount_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-07 |
결산일 직전 구간과 결산조정 기간의 수기 전표를 탐지해야 한다. |
도메인 2.5; Tickmark.Testing.Rules.PeriodEndManual.run/1 |
MVP 필수 |
결산일 포함 3일 또는 fiscal_period=13 적중; 가중치 20 (test/tickmark/testing/rules/period_end_manual_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-08 |
무승인 또는 자기승인인 일정 금액 이상 수기 전표를 탐지해야 한다. |
도메인 2.6; Tickmark.Testing.Rules.ApprovalControlGap.run/1 |
MVP 필수 |
1,000,000원 이상이며 승인자 없음 또는 입력자 동일; 가중치 25 (test/tickmark/testing/rules/approval_control_gap_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-09 |
증빙일과 전기일 사이의 비정상 괴리를 탐지해야 한다. |
도메인 2.7; Tickmark.Testing.Rules.BackdatedPosting.run/1 |
MVP 필수 |
전기일-증빙일 30일 이상 또는 0일 미만, source 무관; 가중치 15 (test/tickmark/testing/rules/backdated_posting_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-10 |
모집단에서 드문 차변·대변 계정 조합을 탐지해야 한다. |
도메인 2.8; Tickmark.Testing.Rules.RareAccountPair.run/1 |
MVP 필수 |
모집단 500건 미만은 skipped; 쌍 포함 전표 수 2건 이하 적중, 가중치 20 (test/tickmark/testing/rules/rare_account_pair_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-11 |
거래처·금액·계정 구성이 같은 근접 전표의 후속 건을 탐지해야 한다. |
도메인 2.9; Tickmark.Testing.Rules.DuplicateEntry.run/1 |
MVP 필수 |
거래처 있음, 1,000,000원 이상, 7일 이내; 후속 건만 가중치 15와 duplicate_of (test/tickmark/testing/rules/duplicate_entry_test.exs) |
S4, S5 |
구현 |
| REQ-RUN-12 |
적중 전표별 가중치 합을 100점으로 제한하고 기준점수로 큐를 나눠야 한다. |
도메인 3장; Tickmark.Testing.Runner, Tickmark.Testing.TestRun |
MVP 필수 |
실행·전표당 finding 하나; 기본 25 이상 검토 큐, 미만 경미 적중 (test/tickmark/testing/runner_test.exs, test/tickmark/testing/runner_label_test.exs) |
S1, S2, S4, S5 |
구현 |
| REQ-RUN-13 |
큐·검토 상태·적중 룰로 발견 목록을 조회해야 한다. |
계약 2.1; 화면 S4.1, S4.3; Testing.list_findings/3 |
MVP 필수 |
검토 큐·경미·전체 탭; 점수 내림차순 후 전표번호 오름차순, 잘못된 URL 필터 무시 (test/tickmark_web/live/test_run_live_test.exs) |
S4 |
구현 (페이지 나누기 미구현) |
| REQ-RUN-14 |
전표 상세에서 원본 행과 룰별 근거 및 점수 산식을 확인할 수 있어야 한다. |
화면 S5.1; Testing.get_finding!/2, list_rule_results/2 |
MVP 필수 |
행 번호순 원본과 차대 합계 표시; 100점 초과 합산은 min 식으로 표시 (test/tickmark_web/live/finding_live_test.exs) |
S5 |
구현 |
4.5. AI 트리아지 제안
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-AI-01 |
작성자가 기준 이상 미요청 항목을 한 번에 제한된 수만큼 요청할 수 있어야 한다. |
계약 5.5.1; 화면 S4.3; Triage.request_triage/2 |
MVP 필수 |
none만 점수·금액 내림차순으로 최대 100건; 0건이면 이벤트 없음 (test/tickmark/triage_test.exs) |
S4 |
부분 (context 구현, 화면 연결 미구현) |
| REQ-AI-02 |
작성자가 기준 이상 전표를 건별 요청하거나 완료·실패 뒤 재요청할 수 있어야 한다. |
계약 2.1, 5.5.1; Triage.request_finding_triage/2 |
MVP 필수 |
queued는 already_queued, 기준 미만은 below_threshold, 검토자는 forbidden (test/tickmark/triage_test.exs) |
S5 |
부분 (context 구현, 화면 연결 미구현) |
| REQ-AI-03 |
동일한 전표·모델·프롬프트·입력의 저장 제안은 재사용해야 한다. |
계약 5.5.1; Triage.triage_finding/1 |
MVP 필수 |
동일 입력에 API 재호출 없음; 달라진 입력은 새 불변 행 (test/tickmark/triage_test.exs) |
S4, S5 |
구현 |
| REQ-AI-04 |
AI는 위험도·근거·추가 절차·부족한 정보만 제안하고 사람의 검토 상태를 바꾸지 않아야 한다. |
MVP 2장; 도메인 4장; Tickmark.AI.Anthropic.triage/2, Triage.triage_finding/1 |
MVP 필수 |
low/medium/high, 절차 1-4개, 부족 정보 0-5개 검증; 승인·반려·결론 단정 출력 거부 (test/tickmark/ai/anthropic_test.exs, test/tickmark/triage_test.exs) |
S5 |
구현 |
| REQ-AI-05 |
AI 제안과 사람 판단을 분리하여 최신 성공 제안의 생성 근거를 표시해야 한다. |
화면 S5.1-S5.2; lib/tickmark_web/live/finding_live/components.ex |
MVP 필수 |
AI 위험도와 결론 배지 분리; 모델·응답 모델·프롬프트·해시 표시 (test/tickmark_web/live/finding_live_test.exs) |
S4, S5 |
부분 (S5 구현, S4 열 미구현) |
| REQ-AI-06 |
AI 실패나 미요청 상태에서도 사람이 결론을 작성할 수 있어야 한다. |
도메인 4장; 화면 S5.2; Review.submit_conclusion/3 |
MVP 필수 |
AI 연결 없는 결론 허용; 실패 원문은 화면에 노출하지 않음 (test/tickmark/review_test.exs, test/tickmark_web/live/finding_live_test.exs) |
S5 |
부분 (백엔드 구현, 제출 UI 진행 중 W6) |
4.6. 결론과 검토
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-REV-01 |
작성자는 판단 세 가지 중 하나와 필수 코멘트로 결론을 제출해야 한다. |
MVP 2장; 계약 8장; Review.submit_conclusion/3 |
MVP 필수 |
outcome 필수, 코멘트 1-2000자; 제출 시 concluded 및 이벤트 원자적 기록 (test/tickmark/review_test.exs) |
S5 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-02 |
재제출은 기존 결론을 고치지 않고 새 결론으로 남겨야 한다. |
계약 3.11, 8장; Review.submit_conclusion/3 |
MVP 필수 |
open·concluded·rejected에서 제출; approved에서는 거부 (test/tickmark/review_test.exs) |
S5 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-03 |
결론은 작성자가 본 같은 finding의 AI 제안에만 연결해야 한다. |
계약 12.3 C-11; Review.submit_conclusion/3 |
MVP 필수 |
다른 finding의 제안 ID는 changeset 오류; 표시된 ID를 제출할 화면 검증 필요 (test/tickmark/review_test.exs; UI는 W6) |
S5 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-04 |
검토자는 화면에서 확인한 최신 결론만 승인하거나 반려해야 한다. |
계약 8장, 12.3; Review.decide/4 |
MVP 필수 |
concluded만 허용; 낡거나 조작된 conclusion_id는 stale, 중복 결정 거부 (test/tickmark/review_test.exs) |
S5 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-05 |
반려에는 사유를 요구하고 승인·반려 전에 확인 단계를 제공해야 한다. |
화면 S5.2, S5.4; 계약 12.3; Tickmark.Review.ReviewDecision.changeset/2 |
MVP 필수 |
반려 공백 사유 거부·최대 2000자; 확인/취소로 결정, finding_updated 시 확인 해제 (test/tickmark/review_test.exs; 확인 UI 검증 대기) |
S5 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-06 |
자기 결론의 승인·반려를 context와 DB에서 차단해야 한다. |
MVP 2장; 계약 8장; Review.decide/4 |
MVP 필수 |
역할 변경 후에도 self_review; CHECK와 복합 FK 우회 거부; 멤버의 거부 시도 기록 (test/tickmark/review_test.exs) |
S5, S6 |
구현 (화면 결정 연결은 진행 중 W6) |
| REQ-REV-07 |
판단 초안을 보존하며 결론·결정 이력과 최신 상태를 보여야 한다. |
화면 3.4, S5.2; lib/tickmark_web/live/finding_live/show.ex |
MVP 필수 |
다른 작성자 제출 시 초안 유지·안내; 승인 수신 시 잠금; 결론과 결정 시간순 표시 (test/tickmark_web/live/finding_live_test.exs) |
S5 |
구현 (서명 확인 단계 초기화는 W6) |
4.7. 감사 로그
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-AUD-01 |
업무 상태 변경과 감사 이벤트를 같은 트랜잭션에 남겨야 한다. |
MVP 2장; 계약 4장; AuditTrail.append/3, record/1 |
MVP 필수 |
업무 롤백 시 이벤트도 없음; review.denied만 별도 기록 (test/tickmark/audit_trail_test.exs, test/tickmark/review_test.exs) |
S1-S6 |
구현 (실제 기록 범위는 8장) |
| REQ-AUD-02 |
멤버에게 사람·AI·시스템 이벤트를 최신순 읽기 전용으로 제공해야 한다. |
화면 S6.1; AuditTrail.list_events/3 |
MVP 필수 |
seq 내림차순·한글 동작명·원본 action·payload; 수정·삭제 UI 없음 (test/tickmark_web/live/audit_live_test.exs) |
S6 |
구현 |
| REQ-AUD-03 |
감사 이벤트를 행위자·전표번호·실행으로 필터링하고 이전 기록을 더 읽을 수 있어야 한다. |
계약 2.1; 화면 S6.3; AuditTrail.list_events/3 |
MVP 필수 |
필터 AND, before_seq 미만으로 50건씩; context limit 1-200 (test/tickmark/audit_trail_test.exs, test/tickmark_web/live/audit_live_test.exs) |
S6 |
구현 |
| REQ-AUD-04 |
새 감사 이벤트는 읽던 목록을 밀지 않고 수동 갱신 안내로 제공해야 한다. |
화면 3.4, S6.2; lib/tickmark_web/live/audit_live/index.ex |
MVP 필수 |
필터에 맞는 새 seq만 중복 없이 집계; 갱신 클릭 시 첫 행 포커스 (test/tickmark_web/live/audit_live_test.exs) |
S6 |
구현 |
4.8. 공통 사용자 경험
| ID |
요구사항 |
근거 |
우선순위 |
수락 기준 |
관련 화면 |
구현 상태 |
| REQ-UI-01 |
공통 셸에서 감사 대상·로그·계정으로 이동하고 로그인 상태에 맞는 홈을 제공해야 한다. |
화면 3.1; 계약 12.4; lib/tickmark_web/components/layouts.ex, controllers/page_controller.ex |
MVP 필수 |
로그인 홈은 S1 이동, 비로그인 홈은 소개·로그인·가입; 대상 안에서는 이름과 로그 링크 (F1 검증 대기) |
S1-S6, AUTH |
진행 중 (F1) |
| REQ-UI-02 |
시스템·라이트·다크 테마를 선택하고 가능한 환경에서 선택을 보존해야 한다. |
화면 3.1; 디자인 시스템 2.3; lib/tickmark_web/components/layouts/root.html.heex |
MVP 필수 |
세 모드 전환; 계약의 tk:theme 저장 및 저장 실패 시 현재 화면 유지 (현 저장키 차이는 8장) |
S1-S6, AUTH |
진행 중 (F1, 기존 테마 구현 일부) |
| REQ-UI-03 |
현재 감사 대상과 같은 전표를 보는 사람을 실시간으로 표시해야 한다. |
MVP 3장; 화면 3.1, S5.1; TickmarkWeb.Presence.topic/1 |
MVP 필수 |
여러 탭의 같은 사람 중복 제거; S5는 finding view만 표시 (화면 track 및 검증 대기) |
S2-S6 |
부분 (프로세스·토픽 구현, UI 미구현) |
| REQ-UI-04 |
한국어 상태·오류·빈 화면과 권한별 행동 안내를 제공해야 한다. |
화면 3.2-3.3, 부록 A; 계약 12.4 |
MVP 필수 |
비멤버는 동일 404; 연결 끊김·인증·검증 문구 한국어; disabled 행동의 이유 표시 (F1/F2 검증 대기) |
S1-S6, AUTH |
진행 중 (기존 업무 문구 구현, F1/F2) |
| REQ-UI-05 |
키보드·보조기술과 좁은 화면에서 핵심 업무를 사용할 수 있어야 한다. |
화면 3.5, S5.3; 디자인 시스템 7장; lib/tickmark_web/live/* |
MVP 필수 |
표 caption·scope와 폼 label, 상태 aria-live 확인; 색 외 문구·아이콘, 키보드 및 좁은 화면 수동 검증 필요 |
S1-S6, AUTH |
부분 (마크업 있음, 전체 접근성 확인 필요) |
| REQ-UI-06 |
전표 검토 큐와 다음 미판단 이동에서 S4의 선택 맥락을 유지해야 한다. |
화면 S4.3, S5.1; 계약 12.3; lib/tickmark_web/live/finding_live/show.ex |
MVP 필수 |
tab·status를 이어받음; 현재 뒤 첫 open 이동, 없으면 비활성 (대응 코드·테스트 없음) |
S4, S5 |
미구현 (라운드 4b 메인 예정) |
5. 비기능 요구사항
다음 수치는 기준 커밋의 코드·설정에서 읽은 값이다. 처리량 보장이나 외부 서비스의 실제 응답 속도를 뜻하지 않는다.
| ID |
범주 / 요구사항 |
수락 기준과 실제 제한 |
근거 |
우선순위 |
구현 상태 |
| NFR-01 |
감사 추적성 / 증거 행을 수정·삭제할 수 없어야 한다. |
audit_events UPDATE·DELETE·TRUNCATE 거부; ai_triages·conclusions·review_decisions UPDATE·DELETE 거부 |
계약 4장; priv/repo/migrations/20261017110533_add_append_only_triggers.exs; test/tickmark/audit_trail_test.exs, audit_trail_truncate_test.exs, schemas_test.exs |
MVP 필수 |
구현 |
| NFR-02 |
감사 추적성 / AI 결과의 생성 조건을 재구성할 수 있어야 한다. |
model·response_model·prompt_version·input_hash·input·토큰 수·지연 저장; 같은 입력 해시 재현 |
계약 3.10, 7장; Triage.triage_finding/1, AI.input_hash/1; test/tickmark/triage_test.exs, ai_test.exs |
MVP 필수 |
구현 |
| NFR-03 |
보안 / 웹 요청과 context에서 권한 및 데이터 소속을 재검사해야 한다. |
미로그인은 로그인으로 이동; 비멤버·없는 ID·잘못된 UUID는 상세에서 같은 404; 목록 API는 빈 목록 |
계약 2.1, 8장; Engagements.authorize/3, 각 get 함수; test/tickmark/engagements/authorization_test.exs, test/tickmark_web/engagement_routes_test.exs |
MVP 필수 |
구현 |
| NFR-04 |
보안 / 운영 시크릿을 환경 변수로 읽고 응답·기록에 노출하지 않아야 한다. |
ANTHROPIC_API_KEY·DATABASE_URL·SECRET_KEY_BASE 환경 참조; AI 오류에 키와 응답 원문 미반환 |
AGENTS.md 6, 8장; config/runtime.exs; test/tickmark/ai/anthropic_test.exs |
MVP 필수 |
부분 (코드 확인, 배포 환경 확인 필요) |
| NFR-05 |
보안 / CSV 입력의 자원 사용과 형식을 제한해야 한다. |
파일 20,000,000바이트·비어 있지 않은 데이터 최대 100,000행; 물리 줄 65,536바이트; 적요 500자·기타 셀 200자 |
lib/tickmark/ledger.ex:32, ledger/csv_parser.ex:42, ledger/csv_parser/row.ex:14; test/tickmark/ledger/csv_parser_test.exs, ledger_test.exs |
MVP 필수 |
구현 |
| NFR-06 |
데이터 / 저장소·데모·검증은 합성 데이터만 사용해야 한다. |
생성 GL과 fixture 사용; 공개 전 실제 고객·회사 데이터 포함 여부 점검; 업로드 파일의 합성 여부 자동 판별 기능은 없음 |
MVP 4장; AGENTS.md 1, 8장; Ledger.Generator.generate/1; WBS 6.3 |
MVP 필수 |
부분 (생성기 구현, 운영 규칙 준수 확인 필요) |
| NFR-07 |
성능 / 큰 GL은 스트리밍 및 묶음 적재로 처리해야 한다. |
해시 65,536바이트 블록; 전표 1,000건과 행 1,000건씩 insert_all; 기본 생성 GL 19,804행 적재 테스트 존재, 운영 SLA 미정 |
lib/tickmark/ledger.ex, ledger/importer.ex:14; test/tickmark/ledger_test.exs: loads the default synthetic GL, one entry per label row |
MVP 필수 |
구현 (운영 성능 확인 필요) |
| NFR-08 |
신뢰성 / 장시간 작업을 제한된 Oban 큐와 재시도로 처리해야 한다. |
Basic engine, ingest 1·rules 4·llm 2; 적재 최대 3회·10분, 룰 최대 3회·5분, 트리아지 최대 5회·3분 |
config/config.exs; Ledger.ImportWorker, Testing.RuleWorker, Triage.TriageWorker; 각 worker_test.exs와 test/tickmark/jobs/failure_handler_test.exs |
MVP 필수 |
구현 |
| NFR-09 |
신뢰성 / AI 오류 유형에 맞춰 재시도와 최종 실패를 구분해야 한다. |
429는 최대 10회 snooze, 기본 30초; 일시 오류 backoff 20·40·80·160초; fatal은 즉시 취소; Req receive_timeout 120,000ms·자체 retry false |
lib/tickmark/triage/triage_worker.ex, ai/anthropic.ex; test/tickmark/triage/triage_worker_test.exs, test/tickmark/ai/anthropic_test.exs |
MVP 필수 |
구현 |
| NFR-10 |
신뢰성 / 중복 실행과 동시 수정에도 업무와 증거의 일관성을 지켜야 한다. |
부모 행 FOR UPDATE 후 자식 저장; 마지막 룰 완료 1회; 트리아지 조건부 claim; 결론 최신 ID와 unique 결정 |
계약 5.4-5.5, 8장; Ledger.process_import/1, Testing.run_rule/2, Triage.request_triage/3, Review.decide/4; runner·triage·review 테스트 |
MVP 필수 |
부분 (코드·테스트 있음, Review 실제 두 연결 경합 확인 필요) |
| NFR-11 |
외부 의존성 / API 키 없이 Fake로 핵심 흐름을 실행할 수 있어야 한다. |
기본 AI.Fake, model fake-triage-v1; 테스트는 실키가 있어도 Anthropic으로 전환하지 않음; UI 전체 시연은 별도 확인 |
AGENTS.md 6장; config/config.exs, config/runtime.exs, config/test.exs; test/tickmark/ai/fake_test.exs, triage_test.exs |
MVP 필수 |
부분 (백엔드 구현, 전체 UI 흐름 확인 필요) |
| NFR-12 |
사용성 / 한국어 UI와 검증 문구를 일관되게 제공해야 한다. |
기본 locale ko; 번역 없는 인증·changeset 영어 제거 여부는 F2 병합 뒤 확인 |
화면 부록 A, C-06; 계약 12.4; config/config.exs, lib/tickmark_web/live/user_live/* |
MVP 필수 |
진행 중 (F2, 공통 오류 F1) |
| NFR-13 |
접근성 / 상태와 조작 의미를 보조기술에 전달해야 한다. |
label·caption·scope, 상태 aria-live, disabled 이유, 갱신 후 focus; 라이트/다크 AA 대비·키보드·스크린리더 확인은 필요 |
디자인 시스템 7장; 화면 3장; lib/tickmark_web/live/audit_live/index.ex; test/tickmark_web/live/audit_live_test.exs |
MVP 필수 |
부분 (마크업·일부 테스트, 수동 확인 필요) |
| NFR-14 |
사용성 / GL 입력 시각과 시스템 시각의 시간대 의미를 구별해야 한다. |
CSV entered_at은 오프셋 없는 KST; 시스템 DateTime은 UTC 저장·KST 표시·datetime UTC ISO; title 정합 대기 |
MVP 5장; 화면 3.6; TickmarkWeb.Format.format_kst/1, utc_title/1; test/tickmark_web/format_test.exs, test/tickmark/ledger/csv_parser_test.exs |
MVP 필수 |
부분 (S1/S2 helper title F1 정합 중) |
| NFR-15 |
유지보수 / 변경을 테스트·포맷·경고 없는 컴파일로 검증해야 한다. |
mix precommit의 compile --warnings-as-errors, deps.unlock --unused, format, test; 기능에는 ExUnit·LiveView 테스트 |
AGENTS.md 4, 6, 9장; mix.exs의 aliases; test/ |
MVP 필수 |
확인 필요 (테스트 존재 확인, 이번 문서 작업에서는 mix 미실행) |
| NFR-16 |
운영 / 외부에서 접속 가능한 합성 데이터 데모와 끊김 없는 시연을 제공해야 한다. |
데모 URL 접속, 두 역할로 핵심 시나리오 3분 시연; 배포 상태·실제 동작 별도 확인 |
MVP 1, 7장; WBS 5.1-5.4, 6.2 |
MVP 필수 |
미구현 (배포 대상 결정과 시연 검증 대기) |
| NFR-17 |
보안 / CSV 자유문과 AI 출력을 명령 또는 확정 판단으로 취급하지 않아야 한다. |
description·counterparty는 untrusted_text로 전달; HEEx 이스케이프 표시; AI 출력 스키마·금지 단정 검증 및 오류 원문 차단 |
도메인 4.3; Triage.build_input/2, Tickmark.AI.Anthropic.triage/2; test/tickmark/ai/anthropic_test.exs, test/tickmark_web/live/finding_live_test.exs |
MVP 필수 |
구현 (실제 Claude 안전성 수동 검증은 확인 필요) |
6. 추적표
WBS 항목의 완료 표기가 화면까지 완료했다는 뜻은 아니다. 아래 구현 상태는 4-5장의 기준 커밋 판정을 그대로 사용한다. 기능 정의서의 ID로 사용자 동작과 시스템 처리를 찾을 수 있다.
| REQ / NFR |
WBS 항목 |
화면 |
관련 기능 |
구현 상태 |
| REQ-ACC-01 |
0.3, 5.2 |
AUTH, S1 |
FN-AUTH-01 |
구현 (한글화는 진행 중 F2) |
| REQ-ACC-02 |
0.3 |
AUTH, S1 |
FN-AUTH-02, FN-AUTH-03 |
구현 |
| REQ-ACC-03 |
0.3 |
AUTH, S1 |
FN-AUTH-04 |
구현 |
| REQ-ACC-04 |
0.3 |
AUTH, S1-S6 |
FN-AUTH-05 |
구현 |
| REQ-ACC-05 |
0.3, 5.2 |
AUTH |
FN-AUTH-06, FN-AUTH-07 |
구현 (한글화는 진행 중 F2) |
| REQ-ACC-06 |
0.3, 1.7, 1.9 |
S1-S6 |
FN-S1-01, FN-SYS-05 |
구현 |
| REQ-ENG-01 |
1.11, 2.5 |
S1 |
FN-S1-01 |
구현 |
| REQ-ENG-02 |
1.11 |
S1 |
FN-S1-02 |
구현 |
| REQ-ENG-03 |
1.11 |
S1 |
FN-S1-02 |
구현 |
| REQ-ENG-04 |
1.6, 1.11 |
S2 |
FN-S2-02 |
구현 |
| REQ-ENG-05 |
1.3, 1.4, 1.6 |
S2 |
FN-S2-02 |
구현 |
| REQ-ENG-06 |
1.16, 2.6 |
S2 |
FN-S2-01 |
구현 (검토 후 통계 갱신 제한은 8장) |
| REQ-GL-01 |
1.12, 2.3 |
S3 |
FN-S3-01, FN-S3-02, FN-S3-04 |
구현 |
| REQ-GL-02 |
1.12 |
S3 |
FN-S3-01, FN-SYS-01 |
구현 |
| REQ-GL-03 |
1.12, 1.17 |
S3 |
FN-SYS-01 |
구현 |
| REQ-GL-04 |
1.12, 2.3 |
S3 |
FN-S3-05 |
구현 |
| REQ-GL-05 |
1.13, 1.15 |
S3 |
FN-S3-03 |
구현 |
| REQ-GL-06 |
1.13, 1.17, 2.4 |
S3, S4 |
FN-S3-03, FN-SYS-02 |
구현 |
| REQ-GL-07 |
1.12, 1.16, 2.3 |
S2, S3 |
FN-S3-05, FN-SYS-01 |
구현 |
| REQ-GL-08 |
1.12, 1.16 |
S2, S3 |
FN-S2-01, FN-S3-05 |
구현 |
| REQ-RUN-01 |
2.1, 2.6 |
S2, S4 |
FN-S2-03 |
구현 |
| REQ-RUN-02 |
2.1 |
S2, S4 |
FN-S2-03, FN-SYS-02 |
구현 |
| REQ-RUN-03 |
2.1, 2.3 |
S4 |
FN-S4-01, FN-SYS-02 |
구현 |
| REQ-RUN-04 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-05 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-06 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-07 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-08 |
2.0, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-09 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-10 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-11 |
2.2, 2.4 |
S4, S5 |
FN-SYS-02, FN-S5-01 |
구현 |
| REQ-RUN-12 |
2.1, 2.4, 2.5, 2.6 |
S1, S2, S4, S5 |
FN-S4-01, FN-SYS-02 |
구현 |
| REQ-RUN-13 |
2.3 |
S4 |
FN-S4-02, FN-S4-04 |
구현 (페이지 나누기 미구현) |
| REQ-RUN-14 |
3.3 |
S5 |
FN-S5-01 |
구현 |
| REQ-AI-01 |
3.2, 3.4 |
S4 |
FN-S4-03 |
부분 (context 구현, 화면 연결 미구현) |
| REQ-AI-02 |
3.2, 4.3 |
S5 |
FN-S5-05 |
부분 (context 구현, 화면 연결 미구현) |
| REQ-AI-03 |
3.2 |
S4, S5 |
FN-SYS-03 |
구현 |
| REQ-AI-04 |
3.1, 3.2 |
S5 |
FN-SYS-03, FN-S5-06 |
구현 |
| REQ-AI-05 |
3.3, 3.4 |
S4, S5 |
FN-S5-06, FN-S4-01 |
부분 (S5 구현, S4 열 미구현) |
| REQ-AI-06 |
3.3, 4.1, 4.3 |
S5 |
FN-S5-02, FN-S5-06 |
부분 (백엔드 구현, 제출 UI 진행 중 W6) |
| REQ-REV-01 |
4.1, 4.3 |
S5 |
FN-S5-02 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-02 |
4.1, 4.3 |
S5 |
FN-S5-02 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-03 |
4.1, 4.3 |
S5 |
FN-S5-02 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-04 |
4.1, 4.3 |
S5 |
FN-S5-03, FN-S5-04 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-05 |
4.1, 4.3 |
S5 |
FN-S5-03, FN-S5-04 |
진행 중 (백엔드 구현, W6 UI) |
| REQ-REV-06 |
4.1 |
S5, S6 |
FN-S5-03, FN-S5-04, FN-SYS-04 |
구현 (화면 결정 연결은 진행 중 W6) |
| REQ-REV-07 |
3.3, 4.3 |
S5 |
FN-S5-02, FN-S5-07 |
구현 (서명 확인 단계 초기화는 W6) |
| REQ-AUD-01 |
1.5, 2.1, 3.2, 4.1 |
S1-S6 |
FN-SYS-04 |
구현 (실제 기록 범위는 8장) |
| REQ-AUD-02 |
4.2 |
S6 |
FN-S6-01, FN-S6-05 |
구현 |
| REQ-AUD-03 |
4.2 |
S6 |
FN-S6-02, FN-S6-03 |
구현 |
| REQ-AUD-04 |
4.2 |
S6 |
FN-S6-04, FN-SYS-05 |
구현 |
| REQ-UI-01 |
5.2 |
S1-S6, AUTH |
FN-S1-03 |
진행 중 (F1) |
| REQ-UI-02 |
5.2 |
S1-S6, AUTH |
FN-S1-04 |
진행 중 (F1, 기존 테마 구현 일부) |
| REQ-UI-03 |
1.2, 4.3, 4.4 |
S2-S6 |
FN-SYS-06 |
부분 (프로세스·토픽 구현, UI 미구현) |
| REQ-UI-04 |
5.2 |
S1-S6, AUTH |
FN-S1-03, FN-AUTH-01 |
진행 중 (기존 업무 문구 구현, F1/F2) |
| REQ-UI-05 |
2.3, 3.3, 4.2, 5.2 |
S1-S6, AUTH |
FN-S4-01, FN-S5-02, FN-S6-04 |
부분 (마크업 있음, 전체 접근성 확인 필요) |
| REQ-UI-06 |
4.3, 4.4 |
S4, S5 |
FN-S4-04, FN-S5-08 |
미구현 (라운드 4b 메인 예정) |
| NFR-01 |
1.3, 1.4, 1.5 |
S5, S6 |
FN-SYS-04 |
구현 |
| NFR-02 |
3.1, 3.2 |
S5, S6 |
FN-SYS-03, FN-S5-06 |
구현 |
| NFR-03 |
0.3, 1.6, 1.9, 4.1 |
S1-S6 |
FN-SYS-05 |
구현 |
| NFR-04 |
3.1, 5.4, 6.3 |
AUTH, S3-S6 |
FN-SYS-03 |
부분 (코드 확인, 배포 환경 확인 필요) |
| NFR-05 |
1.12, 2.3 |
S3 |
FN-S3-01, FN-SYS-01 |
구현 |
| NFR-06 |
1.13, 5.3, 6.3 |
S1-S6 |
FN-S3-03 |
부분 (생성기 구현, 운영 규칙 준수 확인 필요) |
| NFR-07 |
1.12, 1.17 |
S3 |
FN-SYS-01 |
구현 (운영 성능 확인 필요) |
| NFR-08 |
1.1, 1.12, 2.1, 3.2 |
S3-S5 |
FN-SYS-01, FN-SYS-02, FN-SYS-03 |
구현 |
| NFR-09 |
3.1, 3.2 |
S4, S5 |
FN-SYS-03 |
구현 |
| NFR-10 |
1.12, 2.1, 3.2, 4.1, 4.4 |
S3-S6 |
FN-SYS-01, FN-SYS-02, FN-SYS-03, FN-S5-03 |
부분 (코드·테스트 있음, Review 실제 두 연결 경합 확인 필요) |
| NFR-11 |
3.1, 3.2, 3.4 |
S3-S6 |
FN-SYS-03 |
부분 (백엔드 구현, 전체 UI 흐름 확인 필요) |
| NFR-12 |
5.2 |
S1-S6, AUTH |
FN-AUTH-01, FN-S1-03 |
진행 중 (F2, 공통 오류 F1) |
| NFR-13 |
2.3, 3.3, 4.2, 5.2 |
S1-S6, AUTH |
FN-S6-04 |
부분 (마크업·일부 테스트, 수동 확인 필요) |
| NFR-14 |
1.12, 2.3, 5.2 |
S1-S6 |
FN-S3-01, FN-S5-01, FN-S6-01 |
부분 (S1/S2 helper title F1 정합 중) |
| NFR-15 |
0.1, 1.14, 4.4 |
S1-S6 |
FN-SYS-01, FN-SYS-02, FN-SYS-03 |
확인 필요 (테스트 존재 확인, 이번 문서 작업에서는 mix 미실행) |
| NFR-16 |
5.1, 5.3, 5.4, 6.2 |
S1-S6 |
FN-S1-03 |
미구현 (배포 대상 결정과 시연 검증 대기) |
| NFR-17 |
3.1, 3.2, 3.3 |
S3-S6 |
FN-SYS-03, FN-S5-01 |
구현 (실제 Claude 안전성 수동 검증은 확인 필요) |
7. 미결 사항과 가정
| 항목 |
판정 / 가정 |
확인 주체와 근거 |
| 기준선 |
후속 브랜치와 배포는 이 문서에 포함하지 않음. W6/F1/F2 결과는 통합 뒤 재판정 |
메인; 계약 12.3-12.4, TASKS.md |
| S5 제출·확인 UI |
진행 중. 실제 성공 flash, 표시 ID 전달, 승인/반려 2단계, 갱신 충돌 테스트 확인 필요 |
W6 및 메인; 계약 12.3 |
| S4/S5 AI 요청과 S4 AI·판단 열 |
context는 구현. 버튼과 집계, Fake로 전체 흐름 확인 필요 |
메인; WBS 3.4, 4.3 |
| Presence·큐·다음 미판단 |
Presence 프로세스만 있음. 화면 추적과 필터 전달, 다음 항목 규칙의 통합 확인 필요 |
메인; WBS 4.3-4.4 |
| S4 페이지 나누기 |
현재 전량 조회. 화면의 50건 더 보기는 제안이며 MVP 선택 여부 확인 필요 |
메인; 화면 C-08, Testing.list_findings/3 |
| 사용자 표시명 |
MVP는 이메일로 확정. display_name을 새 요구사항으로 만들지 않음 |
계약 12.4 C-05 |
| 공휴일 범위 |
기본 공휴일표는 2025년. 다른 연도에는 주말 검사는 가능하나 공휴일 누락 경고만 서버에 남음 |
Tickmark.Testing.Holidays.all/0, WeekendHolidayPosting.run/1; 대상 연도 확대 전 확인 필요 |
| 합성 GL과 감사 대상 연도 |
기본 생성기는 2025 데이터. 감사 대상 연도와 파일 연도 일치를 강제하는 검증은 확인되지 않음 |
도메인 7.1; Ledger.generate_sample_import/3, CsvParser.parse/3; 메인 확인 필요 |
| 실제 Claude 호출 |
Req.Test와 Fake 근거만 사용. 실키 호출, 비용, 실제 응답 품질 검증은 이 문서에서 수행하지 않음 |
WBS 리스크 표, 3.4; 확인 필요 |
| Review 동시성 |
lock-first 및 stale·DB 제약 테스트 있음. 서로 다른 실제 DB 연결의 경쟁 검증은 별도 |
WBS 4.1, 4.4; 확인 필요 |
| 배포와 메일 |
배포 대상, 영속 import 저장소, 메일 전달 방식, 데모 계정 및 외부 URL 동작 확인 필요 |
WBS 5.1-5.4, 계약 12.4 |
| 사용성 최종 판정 |
한국어·접근성·반응형·시연은 소스만으로 완료 판정하지 않음 |
F1/F2 통합 및 S1-S6 브라우저 확인 필요 |
8. 불일치
기존 문서와 코드는 고치지 않았다. 아래 표의 기준 코드 사실을 본문에 사용하고, 요구 변경 여부는 메인 세션이 판단한다.
| 항목 |
문서 근거 |
코드 근거 |
영향 |
| 모든 행위의 감사 기록 |
MVP 2장, AGENTS.md 1장 |
Accounts·조회 함수에는 AuditTrail 호출 없음; 룰 running/succeeded/skipped별 이벤트도 없음 |
실제 감사 action 목록만 보장. 인증·조회·모든 중간 상태 기록을 완료로 주장할 수 없음 |
| S5/S6 상태 표기 |
화면 1장, S5/S6의 스텁 표기 |
FindingLive.Show 읽기·검증·갱신, AuditLive.Index 구현과 테스트 있음 |
설계서 상태가 기준 커밋보다 오래됨 |
| S3 검토자 진입 |
화면 3.2, S3.3의 S2 리다이렉트 제안 |
lib/tickmark_web/live/import_live/new.ex:19 권한 없음 패널을 현재 화면에 표시 |
기능 정의는 실제 거부 화면 기준 |
| S3 테스트 실행 |
화면 S3.4-S3.6의 직접 start_test_run |
lib/tickmark_web/live/import_live/components.ex:113의 S2 이동 링크 |
직접 실행 이벤트는 S2에만 있음 |
| S4 조회 계약 |
화면 S4.3은 min_score와 행별 갱신, S4.1은 더 보기 제안 |
Testing.list_findings/3은 queue·status·rule_id, TestRunLive.Show는 stream reset, 페이지 옵션 없음 |
화면 설계와 context 호출·갱신 단위가 다름 |
| S4 AI·판단 표시 |
화면 S4.1-S4.3의 실제 배지와 요청 버튼 |
lib/tickmark_web/live/test_run_live/show.ex, components.ex의 비활성 버튼과 자리표시 |
백엔드 Triage 완성과 화면 완성을 분리해야 함 |
| C-09, C-10, C-11 |
화면 부록 C의 기준 미만 허용, role 거부 미기록, conclusion_id 미수신 설명 |
Triage.request_finding_triage/2 below_threshold; Review.decide/4 role 이벤트·stale 검사 |
최신 계약 5.5.1, 8, 12.3과 코드에서 해결됨. UI 연결은 별도 |
| C-12, C-13 및 AI 실패 행위자 |
화면 부록 B의 빈 payload, S6 필터 미해결 및 실패 agent 예시 |
AuditTrail.broadcast_appended/1, list_events/3, Triage.mark_failed/2는 system triage.triage_worker |
필터별 정확한 새 이벤트 수 가능. 실패를 AI 행위로 잘못 분류하지 않아야 함 |
| 결론 재작성 |
화면 S5.2는 concluded에서 읽기 전용 후 다시 쓰기 제안 |
FindingLive.Show는 approved 외 preparer를 edit로 설정 |
진행 중 UI와 재작성 UX를 통합 때 확정 |
| CSV 13기 경고 |
화면 S3.5는 13기가 12월이면 경고 없음 |
lib/tickmark/ledger/csv_parser.ex:323은 13기 전체에서 경고 생략; MVP 5장과 일치 |
화면 설명 수정 필요 |
| CSV 정수 오류 문구 |
화면 S3.5의 fiscal_period 오류 확인 필요 |
CsvParser.Row.parse/2는 행 번호·연도·기간에도 invalid_number; 화면 문구는 "금액은 원 단위 정수여야 합니다" |
코드 분류는 확인됨. 금액 이외 필드 설명이 부정확함 |
| S2 승인 통계 실시간 갱신 |
화면 3.4 및 S2 요약 흐름 |
lib/tickmark_web/live/engagement_live/show.ex:127는 finding_updated 무시 |
승인 후 S2 통계는 재진입 등 새 조회 전까지 오래된 값일 수 있음 |
| 공통 셸·테마·시각 title |
화면 3.1, 3.6; 계약 12.4의 tk:theme와 UTC title |
기본 셸과 기존 phx:theme 저장키, S1/S2 kst_time title은 ISO |
F1 진행 중이며 현재 전체 정합 완료 아님 |
| 명칭과 일정 상태 |
화면 C-05 표시명 미결; WBS 1장 M4 대기 및 오래된 M1 통합 상태 |
계약 12.4는 이메일 확정; f5f7f78에 Review·AuditTrail·Triage와 테스트 존재 |
요약 상태를 그대로 구현 근거로 사용하지 않음 |
Changelog
- 2026-10-20: 초안 작성 (D1)
- 2026-10-20: 메인 병합 (60781a3). 병렬 작성 문서 (API 연동 규격서) 도 병합됨 (164788e). 기준 커밋 이후 코드 변경 (홈 리다이렉트, 한글 문구, S5 결론과 결정, AI 제안 요청, 문서 위키) 은 API 연동 규격서 14장 을 본다. FN 과 IF 교차 링크는 아직 없다