Blueprints

우리 서비스에서 실제로 구현한 것을 추상화한 재사용 청사진. 골라서 특정 도메인에 적용한다 — 인터페이스 계약·핵심코드 발췌·트레이드오프 위주(reference-guided).

featurearchitecture
scalerspearvcraftzappzerocloud29 / 29

IAM — 인증·인가 (권한 판정 엔진)

"이 **주체(subject)** 가 이 **리소스(resource)** 에 이 **액션(action)** 을 (이 **테넌트 스코프**에서) 해도 되는가?" 를 한 지점에서 예/아니오로 답하는 것. 인증(누구인가, JWT 검증)과 인가(무엇을 해도 되는가, 권한 판정)를 분리하되 하나의 파이프라인으로 엮는다. 서비스 성숙도에 따라 필요 복잡도가 크게 갈린다 — 부트스트랩기엔 "로그인 됐나"만, SaaS 로 크면 "요금제가 이

architecture⊕ 4 serviceszappzerocloudspearvcraft3 variants

API 토큰 (PAT — 개인 액세스 토큰)

외부 AI 도구(Claude 등)·CI·스크립트가 사람 없이 API/MCP 에 인증하도록 장수명 토큰을 발급한다. JWT(단수명, 갱신 필요)와 달리 PAT 는 장수명·개별 폐기 가능해야 한다. 핵심 긴장은 **보안(유출 시 피해 최소화)** 과 **UX(사용자가 발급한 토큰을 나중에 다시 볼 수 있나)** 사이의 저장 전략 선택.

feature⊕ 2 serviceszappzerocloud

Frontend Auth Session — 토큰 세션·부트스트랩 복원·전송 주입

SPA/Next 프론트가 "로그인 상태"를 신뢰성 있게 들고 다니는 것. 4개의 관심사가 얽힌다 — (1) 토큰을 **어디에 저장**하나, (2) 새로고침 후 세션을 **어떻게 복원**하나, (3) 매 요청에 토큰을 **어떻게 주입**하나, (4) 컴포넌트가 인증 상태를 **어떻게 소비**하나. 저장소·언랩 깊이가 앱의 보안 모델·백엔드 응답 규약에 종속되므로, 같은 조직 안에서도 앱마다 다르게 구현된다.

feature⊕ 2 servicesspearvcraft3 variants

MCP Server — 자사 도메인 서비스를 외부 AI 도구에 노출

이미 NestJS(또는 임의 백엔드)로 도메인 서비스를 갖춘 제품이 있다. 외부 AI 도구 (Claude Desktop / Cursor / ChatGPT)가 이 제품의 데이터를 읽고 쓰게 하려면, HTTP REST API 를 그대로 노출하는 대신 **MCP(Model Context Protocol) 서버**로 감싸 "tool" 목록을 제공해야 한다. 핵심 긴장은 세 가지다:

architecture⊕ 2 serviceszappzerocloud

소셜 로그인 (OAuth2 code flow)

외부 신원제공자(구글·카카오·네이버)로 로그인해 우리 세션/JWT 를 발급받기. 핵심 난점은 세 가지: ①`client_secret` 을 브라우저에 노출하지 않기(서버 격리) ②프로바이더 콜백을 SPA 오리진으로 안전하게 넘기기 ③여러 프로바이더와 어드민/일반 유저 분기를 하나의 흐름으로 다형화하기.

feature⊕ 2 servicesspearvcraft2 variants

Aggregate + Reverse Reference — 매니페스트 members + 읽기시점 역참조

여러 하위 문서(계약서·영수증·보고서)를 하나의 상위 개념(거래=Deal)으로 묶되, 하위 문서는 **제자리에 그대로 두고** 자유롭게 재배치·다중소속 가능하게 한다. 해법: 상위(Aggregate)가 `members: ChildId[]` 매니페스트로 하위를 가리키고(링크 방향 = 상위→하위), UI 는 읽는 시점에 `child→parent` **역참조 인덱스**를 만들어 "이 문서는 어느 거래 소속?"과 "미분류" 뷰를 구성

architecturescaler

AI Agent Harness — 레포에서 코딩 에이전트를 운용하는 규약 골격

AI 코딩 에이전트(Claude Code · Codex 등)가 한 레포에서 일관되게 일하려면, "이 레포의 규약· 디자인·워크플로우"를 매 세션 재발명하지 않게 하는 **하네스**가 필요하다. 순진한 접근의 실패:

architecturezapp

Artifact Pre-generation — 무거운 렌더를 빌드타임 산출·serve-with-fallback

PDF·썸네일·번들처럼 **무거운 렌더 의존성(headless Chrome, 네이티브 라이브러리)** 이 필요한 산출물을, 그 의존성이 없는 경량 런타임 컨테이너에서도 서빙해야 한다. 해법: expensive artifact 를 **build-time(=발행 시점, 개발자 host)에 미리 산출**하고, 소스 옆에 content-addressed 로 저장한 뒤, 런타임은 **serve-with-fallback** — 미리 구운

architecturescaler

Design System Tokens — semantic 토큰·티어드 컴포넌트·Storybook 배포

여러 앱(콘솔·랜딩·백오피스)이 하나의 디자인 언어를 공유하되, 라이트/다크·브랜드 교체를 런타임에 한 지점에서 갈아끼우게 하는 것. 그리고 컴포넌트를 재사용 단위로 티어링해 스토리와 함께 배포·검수하는 것. 핵심은 **앱이 값을 몰라야 한다** — 토큰 클래스(`bg-primary`)만 소비.

architecturespear2 variants

Dual-Audience Admin Prefix — 청중별 엔드포인트 경계 + 게이팅 주입점

"소셜 로그인"·"목록 조회" 같은 **같은 유스케이스**를 사용자(consumer)와 운영자(admin)가 각각 쓰는데, 둘의 권한·감사·진입점이 다르다. 코어 로직은 공유하되 청중 경계를 명확히 그어, 나중에 게이팅(운영자 권한 검증)을 **한 주입점**에서 켤 수 있게 하는 것.

architecturespear

Dual-representation Artifact — 편집가능 데이터 + 불변 렌더 버전들

계약서 같은 아티팩트는 **편집 가능한 구조화 데이터**(당사자·품목·금액…)와, 거기서 특정 시점에 그려낸 **불변 렌더물**(HTML/PDF)이라는 두 얼굴을 갖는다. 렌더물에 데이터를 동봉하는 평면 방식(template-roundtrip)은 중첩·배열엔 부족하다. 해법: `Artifact = { data(editable), documents[](immutable renders) }` 로 명시 분리. data 를 고치고 `

architecturescaler

Git-tracked FS as SSOT — 문서 도메인의 DB-less 저장소

계약서·거래처·프로젝트처럼 **문서 성격이 강하고, 사람이 diff 로 검토하고 싶고, 동시 쓰기가 거의 없는** 도메인을 DB 없이 부팅한다. "디렉토리 구조 = 스키마", "frontmatter = 메타데이터, 본문 = 마크다운"을 규약으로 못박고, 앱은 그 위에 얹는 **무상태 read-mostly 어댑터**로만 존재한다. 핵심 목표: 제로인프라로 시작하되, 상위 타입(`Repository<Entity>`)을 불변으로 유

architecturescaler

Human-readable Composite ID — prefix 세그먼트 + zero-pad 시퀀스

계약서 번호처럼 **사람이 읽고 분류·대조할 수 있는 ID**(예 `CONT-JPU-2026-001`)가 필요하다. UUID 는 불투명하고, DB auto-increment 는 DB 를 전제한다. 해법: `prefix 세그먼트들 + zero-padded 시퀀스` 조합 ID 를, **기존 목록을 스캔해 최대 순번+1** 로 채번한다. 생성과 파싱은 **하나의 정규식**으로 정의해 drift 를 막는다.

featurescaler

Lifecycle Status Sidecar — 불변 원본 옆 append-only 상태·서명 이력

계약서·영수증처럼 **원본(HTML/PDF)이 법적으로 불변**이어야 하는 문서의 진행 상태(작성중→발송→ 서명완료…)와 변경 이력·전자서명 정보를 관리한다. 원본에 상태 필드를 박으면 원본이 바뀐다. 해법: 원본 옆 **사이드카 파일**(`<doc_id>.status.json`)에 현재 상태 + append-only 이력 + 서명 메타를 둔다. 전이는 kind별 화이트리스트 FSM 으로 강제하고, `--force` 로만 우회

featurescaler

Monorepo Docker Dev — 핫리로드·의존성 격리·URL 이원화

Turborepo/Yarn 모노레포(백엔드 + 여러 프론트 + DB)를 `docker compose up` 한 방으로 띄우면서, 소스 저장 즉시 반영(핫리로드)되고, mac 호스트에서 설치한 네이티브 모듈이 리눅스 컨테이너로 새지 않게 하는 것. 브라우저용 URL 과 컨테이너-간 URL 을 혼동하면 런타임에 조용히 깨진다.

architecturespear

OpenAPI 다국어 SDK 코드젠 — 스펙이 SoT

API 를 타 언어/타 팀이 호출할 때 DTO·경로를 손으로 복붙하면 서버와 어긋난다(drift). 필드 하나 바꾸면 클라이언트마다 수동 반영 → 런타임 타입 구멍. 여러 언어를 지원하면 이 고통이 배가된다.

architecturezerocloud

PRD 점진적 공개 — 경량 초안에서 정식 문서로 승격

기획 문서(PRD)를 처음부터 완결된 정식 구조로 강요하면 착수 저항이 크고, 반대로 끝까지 자유 서술로 두면 검증·추적이 안 된다. 이 둘을 시간축으로 분리한다 — **경량 초안 모드로 가볍게 시작 → 필수 조건 게이트 통과 → 정식 모드로 승격**(초안 필드가 정식 구조로 변환). 정식 문서는 구조화 체크리스트(수용기준)로 진행률을 추적하고, 페르소나·페인·지표 같은 타 자산은 복제하지 않고 참조한다.

featurezapp

Template Round-trip — 렌더물에 소스 변수를 sidecar-free 동봉

템플릿 + 변수로 렌더한 산출물(HTML 등)을 나중에 **다시 편집·재생성**하려면 원래 변수값이 필요하다. 별도 사이드카 파일(`.vars.json`)로 두면 렌더물과 어긋나거나 유실된다. 해법: 렌더 변수를 **렌더물 안에 보이지 않게 동봉**(주석 블록)해 파일 1개를 self-contained round-trip 가능하게 만든다. 문서가 "나를 다시 만드는 입력"을 스스로 들고 다닌다.

featurescaler

감사 로그 — 누락 없는 단일 테이블

"누가 무엇을 언제 바꿨나"를 하나의 조회 가능한 로그로 남기고 싶다. 순진하게 컨트롤러마다 `auditService.log(...)` 를 손으로 박으면 반드시 빠뜨린다 — 새 컨트롤러, 실패/거부 경로, 프레임워크 훅 밖의 raw 경로(MCP/웹소켓)에서. 또 요청 본문을 그대로 남기면 password·token 이 로그에 유출된다.

architecturezerocloud

대사 + AI 소견 루프 — 기계 집계·인간/AI 판단·지식 축적

감사·이상탐지(세무 검수·재무 마감 등)를 "일회성 스크립트"가 아니라 **매 실행마다 똑똑해지는 루프**로 만드는 것. 여러 출처를 조인해 불일치를 뽑는 건 기계가 잘하지만(멱등·재현), 그 불일치가 문제인지 정상인지의 **판단은 기계가 못 한다**. 그렇다고 판단을 매번 사람이 처음부터 하면 지식이 축적되지 않는다. 세 단계를 명확히 분리한다 — **기계 집계 → 인간/AI 판단 강제 → 새 사실을 지식 저장소에 역반영(다

featurescaler

도메인 모델링 분류학 — 자산형·이벤트형·단위형 + shape 접기

새 도메인 개념(페르소나·결정·PRD·측정값·프레임워크…)을 모델링할 때, **엔티티부터 그리기 전에** "이 개념은 어떤 종류의 것인가"를 먼저 판정하면 API 동사·수정 정책·저장 구조가 거의 자동으로 결정된다. zapp core-api 는 이 판정을 **3분류(자산형/이벤트형/단위형)** 로 명문화하고, 여기에 더해 **변형이 많은 축은 개별 엔티티로 늘리지 않고 shape 카탈로그 + payload JSON 으로 접는다

architecturezapp

문서 리뷰 워크플로 — 문서에 PR/브랜치 얹기

편집 가능한 문서(위키·PRD·개요 등)에 대해 "누가 바로 고쳐도 되는 변경"과 "리뷰를 거쳐야 하는 제안"을 **같은 문서 데이터 위에 병존**시키는 것. 코드의 git 워크플로를 문서에 이식한다 — 직접 커밋(`update`)과 PR(`draft → review → merge`)이 한 저장소에 공존. 로컬 AI/데스크톱 에이전트가 "브랜치처럼" 문서를 작업해 제안을 올리고, 사람이 diff 를 보고 승인·머지·반려하는 흐

featurezapp

신뢰성 있는 비동기 부수효과 — 커밋과 외부작용 연결

DB 트랜잭션이 커밋된 뒤 외부 부수효과(메일 발송, 정산 트리거, 썸네일 재생성, 웹훅)를 실행하고 싶다. 순진한 방법들은 각각 구멍이 있다:

architecturevcraft2 variants

알림 파이프라인 — 템플릿·동의·벤더 어댑터

앱 곳곳에서 "이 유저에게 알림톡/SMS/메일을 보내라"를 호출한다. 순진하게 짜면 매 호출부에 (1) 전화번호 유무, (2) 스테이지 환경 오발송 방지, (3) 수신동의 확인, (4) 파라미터 검증, (5) 벤더 SDK 호출 + 실패 처리가 흩어진다. 규제(마케팅 수신동의)와 벤더 종속이 코드 전역에 새어나가고, 발송 실패가 결제/주문 트랜잭션을 rollback 시킨다.

featurevcraft

오브젝트 스토리지 — 스코프 토큰 + 프로바이더 어댑터

자사 서비스가 오브젝트 스토리지(S3 등)를 **재판매/중개**할 때, 두 가지를 풀어야 한다. (1) 백엔드 프로바이더 크리덴셜(AWS 액세스키)을 고객에게 절대 노출하지 않으면서 고객이 특정 버킷에만 접근하게 하는 것 — **스코프 토큰**. (2) 프로바이더가 강제하는 페이지네이션(S3 는 커서 기반만 제공)을 앱이 원하는 형태(오프셋/페이지 번호)로 바꾸는 것 — **어댑터**.

featurezerocloud

인터뷰 스터디 파이프라인 — 목적 게이트 + 세션 누적 + 자산 환류

정성 리서치(사용자 인터뷰)를 "메모 뭉치"가 아니라 **검증 가능한 파이프라인**으로 만드는 것. 목적이 흐린 채 인터뷰를 시작하는 오류, 원문을 건너뛰고 요약부터 쓰는 오류, 결과가 아무 자산도 개정하지 못하고 증발하는 오류 — 셋을 구조로 차단한다. 상위(스터디)는 목적 공식이 게이트가 되고, 하위(세션)는 이벤트로 누적되며 정형 단계를 컬럼으로 강제하고, 취합 산출물이 상위 자산(페르소나·페인)을 개정하는 **되먹임 루

featurezapp

잔액-원장 — 캐시 잔액 + append-only 원장

포인트·적립금·크레딧·정산잔액처럼 "현재 얼마"와 "왜 그렇게 됐나"를 **둘 다** 정확히 답해야 하는 값. 잔액만 컬럼으로 들고 있으면 빠르지만 이력·감사가 없고, 매 거래를 로그로만 쌓으면 감사는 되지만 조회가 매번 집계다. 해법은 **원장(ledger)을 SoT 로, 잔액(balance)을 캐시로** 두고 둘을 한 트랜잭션에서 원자적으로 갱신하며, 불변식 `balance == Σ ledger.delta` 를 유지하는 것

architecturevcraft

팀 멀티테넌시 — 멤버십 라이프사이클(초대·권한변경·추방) + IAM 그랜트 + 읽기 격리

SaaS 에서 "팀에 사람을 초대하고, 수락하면 멤버가 되며 그 팀 안에서 권한을 갖는다"를 구현하는 것. 그게 전부가 아니다 — **멤버의 역할을 바꾸고(권한 변경), 내보내고(추방), 스스로 나가는(탈퇴)** 전체 라이프사이클이 있어야 하며, 각 전이가 **IAM 그랜트와 원자적으로 동기화**돼야 한다. 동시에, **비멤버는 그 팀의 리소스를 쓰기는커녕 조회조차 못 해야 한다**(테넌트 읽기 격리).

featurezerocloud

환경별 허용 정책 — 이메일·도메인 화이트리스트

"이 이메일(또는 식별자)이 이 동작을 해도 되나?"를 여러 곳에서 판정한다 — 어드민 로그인 허용, 유저 로그인 링크 발급, 스테이지 알림 발송 대상 등. 순진하게 각 지점에 `if (email.endsWith(...))` 를 흩뿌리면 (1) prod/stage 환경별 차이가 코드에 하드코딩되고, (2) 목적별로 명단이 갈릴 때 서로 오염되며, (3) 대소문자·공백 정규화를 매번 빠뜨린다.

architecturevcraft