이 페이지에서 다루는 것
AI 권한 경계 테스트
한 번에 끝까지 읽으며 맥락을 쌓을 수 있도록 구성했습니다.
AI가 만든 로그인·팀·관리자 기능에서 IDOR, cross-tenant 접근, privilege escalation을 막는 permission boundary 테스트 루프
학습 유형
주제 심층 학습
핵심 주제
AI 권한 경계 테스트
키워드
VIBE 코딩 · 권한 테스트 · 보안 가드레일 · 멀티테넌트 · AI 코드 품질 · 회귀 테스트
이 페이지에서 다루는 것
AI 권한 경계 테스트
한 번에 끝까지 읽으며 맥락을 쌓을 수 있도록 구성했습니다.
예상 학습 시간
15분
본문과 보조 자료(이미지·영상)를 포함한 대략적인 소요입니다.
학습 팁
섹션 순서대로 읽고, 필요한 부분만 다시 찾아보기
표·이미지·영상은 본문 흐름을 돕는 보조 설명입니다.
AI가 만든 기능은 화면이 예쁘고 테스트 데이터로 동작해도, 권한 경계가 한 번 새면 바로 신뢰 사고가 됩니다. 사용자는 자기 글만 봐야 하는데 다른 팀의 문서를 열 수 있고, 일반 멤버가 관리자 버튼을 호출할 수 있으며, URL의 숫자 하나를 바꿨더니 남의 결제 내역이 보일 수 있습니다. 이런 문제는 authentication, 즉 “누구인지 확인했는가”만으로 막히지 않습니다. 로그인 이후에도 authorization, 즉 “이 사람이 이 객체에 이 행동을 해도 되는가”를 매 요청마다 검증해야 합니다.
초보자는 permission boundary를 “여기부터는 이 사람에게 허용되지 않는 선”으로 이해하면 됩니다. 실무자는 여기에 RBAC, role matrix, tenant isolation, object ownership, least privilege, deny by default, server-side guard, policy test, negative test, audit log, rollback criteria를 붙여야 합니다. VIBE 코딩에서는 AI에게 “로그인 붙여 줘”라고만 시키면 부족합니다. AI는 종종 화면 버튼을 숨기는 것과 서버 권한 검사를 혼동하고, 정상 사용자 happy path는 잘 만들지만 cross-tenant, IDOR, privilege escalation 같은 공격적 상황을 테스트하지 않습니다.
이 글은 AI로 빠르게 만든 제품에 권한 경계 테스트 루프를 붙이는 방법입니다. 핵심은 권한 정책을 문장으로만 남기지 않고, 역할과 객체 소유권을 표로 고정한 뒤, 허용 테스트보다 거부 테스트를 먼저 많이 만들고, 서버 경계에서 실패하게 만드는 것입니다. 목적은 보안 전문가만 이해하는 이론이 아니라, 작은 SaaS, Q&A, 관리자 화면, 팀 협업 앱, 결제 대시보드에서 바로 쓸 수 있는 작업 순서입니다.
AI 권한 경계 테스트 루프의 결론은 명확합니다. “사용자가 로그인했는지 확인한다”에서 멈추지 말고, “로그인한 사용자가 이 tenant, 이 object, 이 action에 접근할 수 있는지 서버에서 매번 검증한다”를 테스트로 고정해야 합니다. authentication은 출입증 확인이고, authorization은 방마다 다른 열쇠 확인입니다. 출입증이 있다고 모든 방에 들어갈 수는 없습니다.
좋은 permission boundary는 세 겹으로 만듭니다. 첫째, 정책을 role matrix로 명시합니다. owner, admin, editor, viewer, guest가 어떤 action을 할 수 있는지 표로 적습니다. 둘째, 데이터 경계를 tenant isolation과 object ownership으로 고정합니다. 같은 역할이어도 다른 조직, 다른 프로젝트, 다른 문서에는 접근할 수 없어야 합니다. 셋째, 그 정책을 policy test와 negative test로 실행합니다. 허용되는 요청만 테스트하면 실제 사고를 못 잡습니다. 거부되어야 하는 요청이 반드시 403이나 404로 실패하는지 봐야 합니다.
AI에게 구현을 맡길 때도 순서가 중요합니다. 먼저 정책 표와 테스트를 만들고, 그 다음 guard 함수를 구현하게 해야 합니다. 반대로 구현부터 맡기면 AI는 화면에 버튼을 숨기는 방식, 클라이언트 라우팅 제한, 사용자 입력을 신뢰하는 방식으로 빠르게 끝내려 할 수 있습니다. VIBE 코딩의 사람 역할은 경계 조건을 정하고, AI가 놓친 부정 경로를 테스트로 계속 밀어 넣는 것입니다.
권한 버그는 기능 버그보다 복구가 어렵습니다. 잘못 보낸 이메일은 사과할 수 있지만, 다른 고객 데이터가 노출되면 신뢰와 계약 문제가 됩니다. 그래서 rollback criteria도 숫자로 정해야 합니다. 배포 후 cross-tenant 403 실패율, 비정상 audit log 증가, 관리자 action 실패/성공 패턴, 민감 페이지의 404/403 비율이 기준을 넘으면 기능 플래그를 끄거나 이전 버전으로 되돌려야 합니다.
많은 AI 생성 코드가 session을 확인하면 충분하다고 가정합니다. 예를 들어 route handler 초반에 “session이 없으면 로그인 페이지로 보내기”만 넣고, 이후에는 요청된 projectId나 invoiceId를 그대로 조회합니다. 이 경우 사용자가 로그인되어 있다면 URL을 바꿔 다른 사람의 객체를 요청할 수 있습니다. 이것이 IDOR, 즉 Insecure Direct Object Reference의 전형적인 모습입니다.
실무에서는 session 사용자와 대상 객체 사이의 관계를 다시 확인해야 합니다. 문서라면 document.ownerId가 session.user.id와 맞는지, 팀 문서라면 document.tenantId가 사용자의 tenant membership 안에 있는지, 관리자 action이라면 membership.role이 admin 이상인지 확인해야 합니다. 이 검사는 클라이언트가 보내는 role 값이 아니라 서버가 신뢰하는 데이터에서 계산되어야 합니다.
AI에게 “권한 체크 추가”라고만 말하면 세부가 비어 있습니다. 어떤 action인지, 어떤 객체인지, 객체 소유권 기준이 무엇인지, tenant isolation이 필요한지, 실패 시 403을 줄지 404로 숨길지, audit log를 남길지까지 알려줘야 합니다. 그래서 permission boundary는 코드가 아니라 계약으로 시작해야 합니다.
개인 앱에서는 권한 버그가 한 계정 안에서 끝날 수 있습니다. 하지만 팀, 회사, 학교, 고객사 단위로 데이터를 나누는 서비스는 cross-tenant 실수가 곧 데이터 노출입니다. 같은 “viewer”라도 자기 tenant의 문서는 볼 수 있지만 다른 tenant의 문서는 볼 수 없습니다. role만 보면 부족하고 tenant isolation을 함께 봐야 하는 이유입니다.
AI는 종종 role matrix를 전역으로 단순화합니다. “admin이면 모든 것을 할 수 있다”는 식입니다. 내부 운영자라면 일부 전체 권한이 필요할 수 있지만, 고객 tenant의 admin은 자기 tenant 안에서만 admin이어야 합니다. 이 차이를 테스트하지 않으면 개발 환경에서는 모두 잘 보이다가, 실제 고객 데이터가 쌓인 뒤에야 문제가 터집니다.
멀티테넌트 권한 테스트는 정상 접근보다 금지 접근이 더 중요합니다. tenant A의 admin이 tenant B의 문서를 읽지 못하는지, tenant B의 projectId를 tenant A session으로 수정하지 못하는지, 삭제 action이 다른 tenant row에 닿지 않는지 확인해야 합니다. 이 negative test가 없으면 AI가 만든 쿼리 하나가 where tenantId 조건을 빠뜨려도 CI가 조용히 지나갑니다.
프런트엔드에서 관리자 버튼을 숨기는 것은 UX일 뿐 보안이 아닙니다. 사용자는 브라우저 개발자 도구, 직접 fetch 요청, 저장된 링크, 모바일 클라이언트, 오래된 화면을 통해 서버 endpoint를 호출할 수 있습니다. 따라서 중요한 permission boundary는 server-side guard에 있어야 합니다. 클라이언트는 안내를 돕고, 서버가 최종 판단을 해야 합니다.
AI는 UI를 함께 만들 때 버튼 조건부 렌더링을 권한 구현으로 오해하기 쉽습니다. “admin에게만 버튼 보여 줘”는 필요하지만 “admin이 아니면 서버 action이 실패하게 해 줘”가 더 중요합니다. 이 둘을 분리해서 테스트해야 합니다. UI test는 버튼 노출을 확인하고, policy test는 서버 요청이 거부되는지 확인합니다.
이 원칙은 API, 서버 액션, 배치 작업, webhook 처리에도 적용됩니다. 사용자 화면에서 접근할 수 없더라도 서버 endpoint가 열려 있으면 권한 경계가 필요합니다. 특히 AI가 만든 내부 도구나 자동화 endpoint는 “우리만 쓸 것”이라는 이유로 guard가 약해지기 쉽습니다.
코드를 보기 전에 보호 대상 목록을 만듭니다. 예를 들어 project, document, comment, billing profile, invite, export file, admin note처럼 사용자가 보거나 바꿀 수 있는 객체를 적습니다. 그 다음 action을 read, create, update, delete, invite, approve, export, retry처럼 동사로 나눕니다. 이 목록이 없으면 AI는 눈에 보이는 화면만 기준으로 권한을 붙이고, 숨은 action을 놓칩니다.
작은 서비스라면 표 하나면 충분합니다. 행은 role, 열은 action입니다. owner는 billing update 가능, admin은 member invite 가능, editor는 document update 가능, viewer는 read만 가능, guest는 public read만 가능처럼 적습니다. 중요한 것은 “누가 무엇을 못 하는가”도 표에 넣는 것입니다. 허용만 적으면 deny by default를 테스트하기 어렵습니다.
AI 작업 지시서에는 “이 표에 없는 action은 모두 deny by default로 처리한다”를 반드시 넣습니다. 새로운 endpoint가 추가될 때도 기본 허용이 아니라 기본 거부가 되어야 합니다. 이 문장은 단순해 보이지만 AI가 임의로 편의를 위해 열어 두는 행동을 막는 강한 제약입니다.
권한 경계는 role만으로 끝나지 않습니다. 객체가 누구의 것인지, 어떤 tenant에 속하는지 확인해야 합니다. object ownership은 “이 문서의 owner가 누구인가”이고, tenant isolation은 “이 문서가 어느 조직의 경계 안에 있는가”입니다. 개인 프로젝트는 ownership이 중심이고, 팀 서비스는 tenant가 중심입니다.
테스트 데이터도 이 구분을 반영해야 합니다. userA와 userB, tenantA와 tenantB, projectA와 projectB를 만들고 서로 엇갈린 요청을 보냅니다. 같은 role이지만 다른 tenant인 경우, 같은 tenant이지만 낮은 role인 경우, 객체 owner이지만 tenant membership이 끊긴 경우처럼 조합을 만들어야 합니다. AI가 만든 테스트가 한 사용자 한 객체만 쓰면 권한 버그를 거의 못 잡습니다.
실무적으로는 권한 검사를 한 곳에 모읍니다. canReadProject(user, project), canUpdateDocument(user, document), requireTenantRole(user, tenantId, role) 같은 server-side guard나 policy function을 만들고 route handler는 이를 호출하게 합니다. 이름은 프로젝트 스타일에 맞추되, 중요한 것은 모든 민감 action이 이 경로를 통과하는 것입니다.
TDD에서는 허용 테스트보다 거부 테스트를 먼저 쓰는 것이 좋습니다. 예를 들어 “viewer가 billing profile을 수정하면 실패한다”, “tenant A 사용자가 tenant B 문서를 읽으면 실패한다”, “로그인했지만 owner가 아닌 사용자가 export file을 내려받으면 실패한다” 같은 테스트입니다. 이 테스트는 구현 전에는 실패해야 합니다. 실패하지 않으면 이미 권한이 뚫려 있거나 테스트가 잘못된 것입니다.
negative test는 세 가지 층에서 둡니다. 첫째, policy test는 guard 함수가 false나 deny를 반환하는지 확인합니다. 둘째, route test는 실제 요청이 403 또는 의도된 404로 끝나는지 확인합니다. 셋째, UI smoke는 금지된 action이 화면에서 보이지 않는지 확인합니다. 세 층 중 하나만 있어도 도움이 되지만, 제품 권한은 서버 route test가 핵심입니다.
AI에게는 “먼저 실패하는 negative test를 작성하고, 그 다음 최소 구현으로 통과시켜라”라고 지시합니다. 그리고 테스트 이름에 역할, 객체, action, 기대 결과가 드러나게 합니다. 예를 들어 “tenant A editor cannot update tenant B document”처럼 이름만 읽어도 정책이 보이게 합니다.
테스트가 실패한 뒤에 구현합니다. guard는 session에서 userId를 가져오고, 서버 데이터에서 membership과 object를 조회하고, role matrix와 ownership 조건을 계산합니다. 클라이언트가 보낸 role, tenantName, isAdmin 같은 값은 믿지 않습니다. 필요한 것은 서버가 알고 있는 사용자, membership, object, action입니다.
실패 응답도 정책입니다. 존재 자체를 숨겨야 하는 cross-tenant read는 404가 더 안전할 수 있고, 같은 tenant 안에서 권한이 부족한 action은 403이 사용자에게 더 설명적일 수 있습니다. 무엇을 선택하든 테스트에 고정합니다. AI가 route마다 다른 응답을 만들면 디버깅과 감사가 어려워집니다.
중요 action에는 audit log를 남깁니다. 성공한 관리자 action, 거부된 privilege escalation 시도, 반복되는 cross-tenant 요청, export file 접근은 나중에 사고 분석에 필요합니다. audit log는 민감 값을 그대로 저장하기보다 user id, tenant id, action, object type, result, reason, timestamp처럼 필요한 필드만 남기는 것이 좋습니다.
권한 버그는 리팩터링 때 되살아납니다. 쿼리 helper를 바꾸거나, 새로운 list endpoint를 추가하거나, 페이지네이션을 붙이다가 tenantId 조건이 빠질 수 있습니다. 그래서 권한 테스트는 단발성이 아니라 regression suite에 들어가야 합니다. 특히 list, detail, update, delete, export endpoint는 각각 cross-tenant negative test를 둡니다.
배포 후에는 라이브 데이터로 위험한 요청을 직접 만들 필요는 없습니다. 대신 안전한 샘플 계정이나 테스트 fixture가 있다면 금지 action이 403/404로 끝나는지 smoke합니다. 공개 페이지에서는 관리자 전용 버튼, 내부 상태, 권한 디버그 문구가 보이지 않는지도 확인합니다. 권한은 서버 문제이면서 동시에 공개 UI 신뢰 문제입니다.
rollback criteria는 미리 정합니다. 예를 들어 배포 후 30분 안에 403이 평소보다 5배 증가하면서 정상 사용자 문의가 늘면 기능 플래그를 끕니다. cross-tenant guard 실패 로그가 하나라도 성공으로 찍히면 즉시 rollback합니다. 관리자 action audit log가 비정상적으로 비거나 폭증하면 배포를 멈춥니다. 숫자로 정해야 AI와 사람이 같은 기준으로 움직입니다.
팀 문서 앱에서는 editor role이 있어도 모든 문서를 수정할 수 없습니다. tenant A의 editor는 tenant A 문서만 수정해야 하고, tenant B 문서는 읽기도 거부되어야 합니다. 테스트 데이터는 tenantAEditor, tenantBProject, tenantBDocument를 만들고 update 요청이 실패하는지 봅니다. 이때 실패가 “로그인 안 됨”이 아니라 “권한 없음” 또는 “존재 숨김”인지도 확인합니다.
AI에게는 이렇게 지시할 수 있습니다. “document update route에 server-side guard를 추가하라. session user의 tenant membership을 서버에서 조회하고, document.tenantId와 일치하지 않으면 404를 반환하라. 같은 tenant지만 role이 viewer이면 403을 반환하라. tenant mismatch와 viewer update에 대한 negative test를 먼저 작성하라.” 이 정도로 구체적이어야 AI가 버튼 숨김으로 끝내지 않습니다.
실무 팁은 list endpoint도 함께 보는 것입니다. detail/update는 막았는데 list에서 다른 tenant 문서 제목이 섞여 나오면 이미 정보 노출입니다. list query에는 tenantId 조건이 들어가야 하고, 테스트는 결과 배열에 다른 tenant object가 없는지 확인해야 합니다.
billing profile, 구독 플랜, 결제 수단, 환불 action은 일반 CRUD보다 민감합니다. tenant admin이라도 session이 오래되었거나, 2단계 확인이 필요한 정책이라면 바로 실행하면 안 됩니다. 여기서 permission boundary는 role뿐 아니라 action sensitivity와 session freshness를 포함합니다.
테스트는 member가 billing update를 못 하는지, viewer가 결제 페이지를 열 수 없는지, admin이라도 stale session이면 재확인을 요구하는지, 성공/실패가 audit log에 남는지 확인합니다. AI는 결제 연동 코드를 빠르게 만들 수 있지만, 권한과 감사 로그를 누락하기 쉽습니다. 특히 “관리자 화면에서만 버튼이 보이니 괜찮다”는 설명은 받아들이면 안 됩니다.
운영에서는 rollback criteria를 더 보수적으로 둡니다. 권한 거부가 과도하게 발생해 정상 admin이 결제를 못 바꾸는 것도 장애이고, 반대로 member의 결제 변경이 성공하는 것은 보안 사고입니다. 배포 후 billing 관련 403/200 패턴과 audit log를 짧은 주기로 확인해야 합니다.
초대 링크는 권한 경계를 우회하기 쉬운 영역입니다. 링크를 가진 사람이 tenant에 들어올 수는 있지만, 어떤 role로 들어오는지, 누가 초대했는지, 링크가 만료되었는지, 이미 사용되었는지 확인해야 합니다. invitation token 자체가 모든 권한을 뜻하지 않습니다.
테스트는 만료된 초대, 이미 사용된 초대, tenant가 다른 초대, viewer가 admin 초대를 만드는 시도, 초대 수락 후 role이 정책보다 높아지는 privilege escalation을 다룹니다. AI에게는 invitation accept route와 invitation create route를 나눠서 policy test를 만들게 합니다. create는 초대하는 사람의 role을 보고, accept는 token 상태와 target tenant를 봅니다.
실무에서는 초대와 멤버십 변경을 audit log로 남겨야 합니다. 누가 누구를 어떤 role로 초대했는지, 언제 수락했는지, 실패 이유가 무엇인지 추적할 수 있어야 합니다. 나중에 계정 탈취나 내부 실수 조사가 필요할 때 이 로그가 없으면 원인을 찾기 어렵습니다.
사용자가 버튼을 눌러 시작한 AI 요약, export, 메일 발송 같은 background job은 worker에서 실행됩니다. 이때 worker가 “서버 내부니까 권한 검사 생략”으로 동작하면 위험합니다. job payload에 userId와 tenantId가 들어가더라도, 실행 시점에 membership이 아직 유효한지, object ownership이 유지되는지 확인해야 합니다.
예를 들어 사용자가 문서 export를 요청한 뒤 바로 팀에서 제거되었을 수 있습니다. worker가 몇 분 뒤 실행될 때는 더 이상 권한이 없습니다. 따라서 job 실행 시점에도 authorization을 재검증해야 합니다. 이 검사는 background job guard나 service layer policy로 공통화하는 것이 좋습니다.
테스트는 job 생성 시점과 실행 시점의 권한 변화를 다룹니다. “요청 당시 editor였지만 실행 전 viewer로 강등된 사용자의 export job은 실패한다” 같은 사례입니다. 이것이 실무자가 놓치기 쉬운 permission boundary입니다.
가장 흔한 실수는 role 이름만 보면 충분하다고 생각하는 것입니다. admin, editor, viewer 같은 role은 tenant나 object와 함께 해석되어야 합니다. tenant A admin이 tenant B admin은 아닙니다. 문서 owner가 프로젝트 billing owner도 아닐 수 있습니다. role matrix는 항상 scope와 action을 같이 가져야 합니다.
AI가 만든 코드에서 if user.role === "admin" 같은 전역 조건이 보이면 멈춰야 합니다. 이 조건이 정말 전역 운영자만 의미하는지, 고객 tenant admin을 의미하는지 분리해야 합니다. 이름이 같아도 scope가 다르면 다른 권한입니다. 가능하면 globalAdmin, tenantAdmin처럼 용어를 명확히 나눕니다.
요청 body에 role, tenantId, ownerId가 들어온다고 해서 그대로 믿으면 안 됩니다. tenantId는 URL이나 body에 있을 수 있지만, 사용자가 그 tenant에 속하는지는 서버가 확인해야 합니다. ownerId도 클라이언트가 보내는 값이 아니라 객체 조회 결과에서 읽어야 합니다.
AI는 빠른 구현을 위해 form hidden field나 local state의 role 값을 사용할 수 있습니다. 이것은 UI 표시에는 괜찮을 수 있지만 server-side guard에는 부적절합니다. 테스트는 악의적 body를 만들어 role을 admin으로 바꿔 보내도 실패하는지 확인해야 합니다.
새 action이 추가될 때 기본 허용이면 시간이 지날수록 구멍이 늘어납니다. 권한 시스템은 모르는 action을 거부해야 합니다. role matrix에 없는 조합, tenant membership을 찾을 수 없는 사용자, object가 없는 요청, session이 애매한 요청은 안전하게 실패해야 합니다.
테스트도 unknown action을 포함하면 좋습니다. 예를 들어 policy function에 정의되지 않은 action이 들어오면 false를 반환하는지 확인합니다. 이런 작은 테스트가 AI가 새 action을 추가할 때 기본 허용으로 흘러가는 것을 막습니다.
권한 실패 메시지도 정보 노출이 될 수 있습니다. cross-tenant 문서에 대해 “문서는 존재하지만 권한이 없습니다”라고 알려주면 공격자는 문서 존재를 알 수 있습니다. 어떤 경우에는 404로 숨기는 편이 낫습니다. 반면 같은 tenant 안에서 role이 낮아 실패한 경우에는 403과 설명이 사용자 지원에 도움이 됩니다.
정답은 서비스 정책에 따라 다르지만, 일관성이 중요합니다. 테스트는 상태 코드뿐 아니라 공개 메시지도 확인해야 합니다. 내부 디버그 문구, 객체 id, policy reason을 사용자에게 그대로 보여주면 안 됩니다. audit log에는 필요한 reason을 남기되, 공개 응답은 절제합니다.
테스트 데이터가 user 하나, project 하나, role 하나면 권한 경계를 검증하지 못합니다. 최소한 서로 다른 두 사용자, 두 tenant, 두 role, 두 object가 필요합니다. 그래야 cross-tenant, 낮은 role, 소유권 불일치, session 없음 같은 조합을 만들 수 있습니다.
AI에게 테스트 생성을 맡길 때도 “happy path 하나와 negative test 여러 개”를 요구해야 합니다. 특히 list endpoint, detail endpoint, mutation endpoint가 같은 guard를 공유하는지 확인합니다. 하나만 막고 나머지가 열려 있는 경우가 많습니다.
처음부터 모든 권한 시스템을 갈아엎으려고 하지 마세요. 가장 위험한 기능 하나를 고릅니다. 추천 순서는 결제 설정, 초대/멤버 관리, export, 관리자 action, 팀 문서 수정입니다. 그 기능에 대해 object, action, role matrix, tenant isolation, negative test를 먼저 붙입니다. 하나가 안정되면 같은 패턴을 다른 기능으로 복제합니다.
AI에게 줄 첫 작업 단위는 작을수록 좋습니다. “권한 시스템 개선”이 아니라 “document update route에서 tenant mismatch와 viewer update negative test를 먼저 추가하고 server-side guard로 통과시켜라”가 좋습니다. 범위가 작으면 테스트 실패 이유도 분명하고, 리뷰도 쉬워집니다.
팀에서 권한 리뷰를 할 때는 “이거 안전해 보이나요?”보다 구체적인 질문을 씁니다. 이 action의 object ownership은 무엇인가, tenant isolation은 어디서 확인하는가, role matrix에 없는 조합은 어떻게 실패하는가, UI 숨김 말고 server-side guard가 있는가, negative test가 있는가. 이 질문이 반복되면 AI가 만든 코드도 같은 기준으로 평가할 수 있습니다.
코드 리뷰 코멘트도 테스트로 끝나야 합니다. “viewer는 billing update를 못 해야 함”이라는 코멘트가 나오면, 그 자리에서 negative test를 추가합니다. 말로 합의한 권한은 시간이 지나면 사라지지만, 테스트는 계속 남습니다.
권한 사고나 near miss가 있었다면 바로 구현을 고치기보다, 재현 테스트를 먼저 만듭니다. 어떤 session, 어떤 tenant, 어떤 object, 어떤 action에서 뚫렸는지 최소 케이스로 고정합니다. 그 테스트가 실패하는 것을 확인한 뒤 guard를 수정합니다. 이것이 VIBE 코딩에서 AI를 안전하게 쓰는 핵심 루프입니다.
마지막으로 권한 경계는 “한 번 만들고 끝”이 아닙니다. 새 role, 새 endpoint, 새 background job, 새 외부 연동이 생길 때마다 permission boundary가 바뀝니다. 새로운 기능의 완료 조건에 “role matrix 업데이트, negative test 추가, server-side guard 확인, audit log 확인, rollback criteria 확인”을 넣으세요. 그러면 AI가 빠르게 만든 기능도 제품 운영의 신뢰선을 넘지 않습니다.
다음 학습
AI에게 화면과 서버 API를 동시에 맡기면 가장 자주 생기는 실패는 “둘 다 그럴듯하지만 서로 맞지 않는 상태”입니다. 프론트엔드는 name 필드를 기대하는데 서버는 displayName을 돌려주고, 서버는 201을 반환하는데 화면 테스트는 200만 기다리고, 오류 응답은 어떤 곳에서는 message이고 어떤 곳에서는 error.detail입니다. 작은 불일치는 로컬 데모에서는 지나가지만 배포 후에는 빈 화면, 재시도 루프, 잘못된 캐시, 깨진 알림으로 나타납니다.
초보자는 API 계약을 “서로 약속한 요청과 응답의 모양”으로 이해하면 됩니다. 실무자에게는 더 엄격합니다. 요청 스키마, 응답 스키마, status code, error envelope, pagination, idempotency key, versioning, 인증 실패 형태,…
AI가 만든 기능은 버튼을 눌렀을 때 바로 끝나는 화면보다, 뒤에서 오래 도는 background job에서 더 자주 무너집니다. 메일 발송, 이미지 변환, 결제 후 정산, 크롤링, AI 요약, 데이터 마이그레이션, 알림 팬아웃처럼 시간이 걸리는 작업은 queue와 worker로 분리하는 순간 실패 모드가 늘어납니다. 같은 작업이 두 번 실행될 수 있고, 일부만 성공한 뒤 worker가 죽을 수 있으며, 외부 서비스의 rate limit 때문에 retry가 폭주할 수 있습니다.
초보자는 백그라운드 작업 큐를 “나중에 처리할 일을 줄 세워 두는 시스템”으로 이해하면 됩니다. 실무자는 여기서 한 걸음 더 나아가야 합니다. queue에 넣는 job payload, idempotency key, retry policy, exponential back…