AI슈트 Console
관리자 · 직원 콘솔 — 설명 & 구조
Console은 이미 증명된 신뢰 코어(권한·승인·감사·Fernet 비밀 금고·MCP 4단 게이트) 위에 올라가는 사람용 제어판입니다. 처음의 11화면에서 20화면으로 자라, 거버넌스(권한·승인·시크릿·토큰·세션)에 더해 조직 지식 레이어 · 평가·측정 루프 · 사용·ROI까지 아우릅니다. 관리자는 통치하고, 직원은 일하고, 지식·평가가 그 사이를 잇습니다. 정적 React SPA로 만들어 API와 동일 출처에서 서빙되며, 제품 전체가 개발 완료로 app.aisuit.dev에 라이브 배포됐습니다.
AISUIT_DATABASE_URL env로 선택, 미설정 시 SQLite 기본) · 스택: Vite+React 정적 SPA + FastAPI, 동일 출처 · prod Node 런타임 없음. 남은 것은 멀티조직 XL(계정 ⟂ 멤버십) 하나뿐 — 현 비전엔 불필요로 보류. 전체 구조·결정은 console-system-implementation-plan-v0.1.md, 신뢰 코어 자체는 코어 설계 페이지 →콘솔이 무엇이고, 어떤 원칙으로 만들었나
콘솔은 신뢰 코어를 사람이 다루는 면입니다. 코어는 "무엇을 강제하나"이고, 디자인은 "어떻게 보일까"입니다. 콘솔은 둘 사이의 갭을 메우되, 코어가 이미 보장하는 것을 다시 만들지 않습니다. 세 가지 설계 원칙이 이 페이지 전체를 끌고 갑니다.
새 통제 WRITE는 발급뿐
콘솔이 새로 추가하는 통제용 쓰기는 토큰·시크릿 발급뿐입니다. 승인/반려/실행 같은 나머지 관리자 액션은 신뢰 코어가 이미 강제하는 4-eyes 승인·감사를 그대로 재사용합니다. 콘솔의 대부분은 read-projection + 얇은 aggregator입니다.
없는 데이터는 지어내지 않는다
디자인이 발명한 필드(평탄화한 risk·evidence·대기시간·SLA·sparkline·호출수·QA 점수)는 실제 모델에서 파생하거나(대기/SLA는 생성·만료 시각에서) 정직하게 드롭/stub합니다. 백킹 없는 텔레메트리는 만들지 않습니다.
제어판이지 챗봇이 아니다
직원은 자신의 BYO 클라이언트를 쓰고, 콘솔은 통제·열람 면입니다. "Agent 협업채팅"의 대화 기록은 시각화(mock)이며, 사이드 패널만 실제 read(권한 핸들·참조 지식·학습·다음 액션)에 바인딩합니다.
정적 React SPA · 동일 출처
콘솔을 무엇으로 그리고 어디서 서빙하는가는 ADR-0009로 확정됐습니다 — JSON API + Vite+React 정적 SPA, 동일 출처. 서버렌더 HTML 티어는 없습니다.
nginx 정적 + FastAPI /api/*
Vite가 정적 dist/를 방출하고 nginx가 그것을 서빙합니다. FastAPI는 /api/*를 같은 출처에서 서빙합니다. prod에 Node 런타임 없음.
동일 출처 → 쿠키 인증 유지
같은 출처에서 서빙하므로 httponly 쿠키 세션이 CORS 없이 동작하고, 세션 값이 JS에 노출되지 않습니다. write-once 토큰/시크릿 흐름에 가장 작은 XSS 표면입니다.
디자인 CSS는 verbatim 이식
디자인 핸드오프의 CSS를 그대로(verbatim) SPA로 옮깁니다. CSS는 렌더 호스트와 독립이라 이후 어떤 이동에도 살아남습니다.
근거왜 정적 SPA인가
client-only → SSR 불필요
디자인 프로토타입이 SSR/Next 전용 기능을 쓰지 않는 client-only React라 서버 렌더링이 필요 없습니다 → 정적 번들로 충분하고, Vite가 더 가볍고 적합합니다.
build-once — 이중개발 회피
React가 확정 목적지인데 서버렌더 티어를 지었다 다시 SPA로 재작성하면 HTML 템플릿/핸들러를 버리고 JSON 엔드포인트를 두 번 짓게 됩니다. 한 번만 짓습니다.
사람 신원과 agent 신원의 분리
콘솔이 푼 가장 큰 단일 문제입니다. 이전에는 인증이 MCP actor 토큰 하나뿐이라, 대시보드 로그인이 그 토큰을 비밀번호 칸에 붙여넣는 것이었습니다 → agent 자격증명과 사람 세션이 한 비밀로 결합(폭발 반경·폐기·수명을 공유). 지금은 사람 신원과 세션이 agent 토큰과 완전히 분리됩니다.
비밀번호 + SSO
사람 비밀번호(argon2 해시)와 SSO(Google Workspace · OIDC)로 사람을 인증합니다. agent는 그대로 MCP 토큰을 씁니다.
서버 발급 DB 세션
로그인하면 서버가 DB에 세션 행을 만들고 httponly 불투명 쿠키(role/org claim 미포함)를 내려줍니다. 매 요청 서버가 권한을 재조회하므로 비활성화·강등이 즉시 반영됩니다.
agent 토큰과 수명 분리
사람 세션과 agent MCP 토큰의 수명이 완전히 분리됩니다. 한쪽을 폐기해도 다른 쪽은 영향이 없고, 사람 세션 id로 토큰 테이블을 조회하는 경로가 아예 없습니다.
idle + absolute
유휴(약 30분) + 절대(약 12시간) TTL을 모두 강제하고, org별 세션 정책으로 조정합니다.
모든 state-changing POST
세션에 바인딩된 double-submit CSRF 토큰을 모든 상태 변경 POST에 강제합니다.
fixation·열거 차단
로그인마다 fresh 세션 id(권한 변경 시 회전)로 세션 fixation을 막고, 계정 잠금 + IP throttle, 미존재 사용자에도 균일 타이밍으로 계정 열거를 차단합니다.
두 워크스페이스 + 기반 시스템
콘솔은 처음의 11화면에서 20화면으로 자랐습니다 — 관리자 16 · 직원 3 · 공용 1(WorkLog) = 20. 절반 이상이 거버넌스이고, 새로 자란 층이 지식·평가·측정·사용ROI입니다. 핵심 — 워크스페이스 분리는 서버에서 강제합니다. 사이드바를 숨기는 것은 인가가 아니며, 관리자 라우트는 엔드포인트에서 비-admin을 403으로 막습니다.
| 워크스페이스 | 화면 | 핵심 |
|---|---|---|
| 직원 | 업무 브리핑 | 어제 완료 · 승인 대기 · 오늘 예정 카운트 + 우선순위 |
| 직원 | 이슈 | 내 이슈 list/detail · "내 도구로 시작" 프롬프트 복붙 |
| 직원 | Agent 협업 | 대화는 시각화(mock) · 사이드 패널만 실제 read |
| 관리자 | 운영 대시보드 | 메트릭 타일 · 리스크 피드 · 어댑터 상태 · 최근 WorkLog · 인라인 승인 |
| 관리자 | 승인 큐 | 리스크 탭 · per-row 승인/반려 |
| 관리자 | 사용·ROI | 볼륨 + 품질 + 거버넌스 + 커버리지 + 정직한 시간절감 추정 |
| 관리자 | 구성원·Agent | MCP 토큰 발급/회전/폐기 |
| 관리자 | 권한·정책 | role-pack × action 매트릭스. '미구성'을 '거부'와 절대 등치하지 않음 |
| 관리자 | 연동·API키 | 시크릿 · 연결 테스트 · 변경 로그(값 제외) |
| 관리자 | 알림 | Slack 채널 연결/테스트/해제 |
| 관리자 | 조직·보안 | SSO · 세션 정책 · 세션 일괄 폐기 |
| 관리자 | 업무·스킬 | task 카탈로그 + 스킬 런북/지식 저작 · draft → active |
| 관리자 | 스킬 신호 | task별 암묵 신호(수정률·거부률) + 스킬 유무 · 자문 |
| 관리자 | 평가·측정 | task별 평가 루브릭 저작 + 신호 ⟂ 루브릭 루프 + AI 초안 |
| 관리자 | 지식·신선도 | 스킬 런북 신선도 롤업(stale · 미사용 · 미검토 · drift) |
| 관리자 | 조직 지식 | 지식 Playbook 저작 + 엔티티 그래프 + 질의응답 |
| 관리자 | 지연 실행 | 좌초된 'executing' 복구 — 리퍼의 사람 창구 |
| 관리자 | 조직 연결 | 동의 기반 cross-org 거버넌스 롤업 |
| 관리자 | 온보딩·인수인계 | Agent 재배정/인수인계(전용 테이블 없이 기존 배정 모델 재사용) |
| 공용 | WorkLog·지식 | 완료 업무 일지 · 4축 playbook(학습한 규칙) · 직원·관리자 공용 |
정직성 원칙을 구체화하다
각 화면이 얼마나 실제 백엔드로 뒷받침되는지를 솔직하게 분류했습니다. 이것이 "없는 데이터는 지어내지 않는다"는 원칙의 구체화입니다.
범례backing 4단계
full
모델·서비스·엔드포인트가 모두 존재. 그대로 렌더.
partial
데이터 백본은 존재하나 read-projection·파생이 필요.
model_only
모델만 있고 서비스/엔드포인트는 없음.
mock
시각화 전용. 백엔드를 만들지 않음.
화면대표 화면별 backing
| 화면 | backing | 설명 |
|---|---|---|
| 운영 대시보드 | partial | 데이터 백본은 코어가 보유. 메트릭 타일·리스크 피드·최근 WorkLog는 파생/신규 read. QA 점수·호출수·sparkline 히스토리는 드롭/stub |
| 승인 큐 | full | 승인 엔진·4-eyes는 전부 존재. 리스크 탭 필터·per-row 승인/반려가 그대로 바인딩 |
| 사용·ROI | partial | 신규 테이블 없이 기존 데이터에서 org 롤업 파생 — 볼륨·품질·거버넌스·커버리지 + 정직한 시간절감 추정 |
| 구성원·Agent | full | Agent·배정·토큰 모델 위에 발급/회전/폐기 서비스 + last4 컬럼(raw는 write-once) |
| 권한·정책 | partial | 권한 엔진이 모든 셀을 이미 계산. 갭은 read-projection 엔드포인트와 추상 행 → 실제 (자원,액션) 매핑 |
| 연동·API키 · 알림 | full | 연동·시크릿·금고 위에 provision/rotate/revoke/test + Slack 채널 연결/테스트/해제(키 노출 0) |
| 업무·스킬 | full | task 카탈로그 + 스킬 런북/지식 저작. 스킬은 DRAFT 생성 후 명시적 ACTIVATE(저작 시 본문 검증) |
| 스킬 신호 | partial | task별 암묵 평가(수정/거부율 + 스킬 유무)를 기존 세션 데이터에서 파생 — 손봐야 할 스킬을 자문 |
| 평가·측정 | full | task별 평가 루브릭 저작(org 스코프·버전드·단일 활성) + 신호 ⟂ 루브릭 루프 + AI 초안 |
| 지식·신선도 | partial | 스킬 런북 신선도 롤업(stale·미사용·미검토·drift). 신선도는 사람이 표시, 검색은 숨기지 않고 플래그 |
| 조직 지식 | full | 지식 Playbook 저작 + 결정적 엔티티 그래프 + 질의응답(검색→redact→구조화) |
| 지연 실행 | full | 좌초된 'executing' 행을 리퍼가 age-gate로 failed + UNKNOWN 마커로 복구. 읽기전용 미리보기 + reap 액션 |
| 조직 연결 | full | 동의 기반 cross-org 거버넌스 롤업(owner 승인 · 읽기 전용 · dual-org 감사) |
| WorkLog·지식 | full | 4축 playbook과 완료 WorkLog는 full. 제안→수정 delta 카드만 학습 합성(아래 §07)에 의존 |
| 온보딩·인수인계 | partial | 서비스·엔드포인트는 존재. 다만 전용 handover 테이블 없이 기존 Agent 배정 + 위임자 모델 재사용 |
| Agent 협업 | mock | 채팅 백엔드 없음. 대화는 시각화, 사이드 패널만 실제 read(권한·지식·학습·다음 액션) |
콘솔의 모든 엔드포인트는 같은 신뢰 경계를 통과한다
콘솔이 새로 추가하는 모든 엔드포인트는 신뢰 코어와 동일한 신뢰 경계를 통과합니다. 콘솔이라고 코어를 우회하는 지름길을 만들지 않습니다.
- org 스코프 — 모든 쿼리가 인증된 actor의
organization_id로 강제 스코프. 클라이언트가 보낸 org id는 신뢰하지 않음 - chokepoint 라우팅 — 외부/state-changing 액션은 4단 게이트 → 권한 → 승인 → 어댑터 → 금고 → 감사 순서를 그대로 통과
- default-to-safe — 미지 액션/자원은 기본 게이트(승인 필요/거부), 외부 write 기본 write_after_approval
- audit append-only — 승인 관련 액션·거부는 모두 감사 행으로. 수정/삭제 없이 정정도 새 행
- write-once 시크릿 — 토큰·API키·비밀번호는 1회 노출 후 last4만. 값은 미반환·미로깅·미audit. agent는 capability 핸들만
- 사람 세션 ↔ agent 토큰 분리 — 두 표면은 상호 인증하지 않으며 수명이 독립
- product 언어 — 응답·라벨은 제품 용어만. 내부 계산식이나 게이트 단계 나열을 UI에 노출하지 않음
- CSRF — 모든 state-changing POST에 세션 바인딩 CSRF 토큰 필수
- redaction 전수 통과 — 모든 응답·스냅샷이 redaction 필터를 통과
- risk-raising override — 위험을 올리는 권한 override는 admin 필요 + 항상 감사
명시적 범위 절제 (scope discipline)
무엇을 안 만들었는지가 무엇을 만들었는지만큼 중요합니다. 각 항목은 "무엇 + 왜 안 만들었나"입니다 — 디자인 mock을 맞추려 백킹 없는 기능을 발명하지 않는다는 약속입니다.
채팅 백엔드 / messages 테이블
BYO·제어판 원칙. 우리는 hosted chatbot이 아니므로 대화 transcript를 영속하는 백엔드를 만들지 않습니다(시각화로 유지).
조작된 QA 점수 · 달러 ROI
이제 측정은 있습니다 — 명시적 사람 판정(0–5)과 암묵 신호(수정/거부율)를 평가·측정 서브시스템이 다룹니다(§07). 다만 근거 없는 QA-점수 테이블이나 조작된 달러 금액은 여전히 만들지 않고, 정직한 신호로 대신합니다.
호출수(call-count) 텔레메트리
"1.2k 호출" 같은 카운트는 뒷받침할 데이터가 없습니다. 만들지 않습니다(사용·ROI는 기존 데이터에서 파생·live-computed).
sparkline 히스토리
현재값은 live로 계산하면 충분합니다. 일별 집계 버킷은 트렌드가 정말 필요해질 때 추가합니다.
전용 인수인계 테이블
기존 Agent 배정 + 위임자 모델로 충분합니다. 중복 테이블을 새로 만들지 않습니다.
stateless JWT 세션
폐기·강등을 즉시 반영할 수 없어 거버넌스 콘솔에 부적합합니다. DB 세션을 택했습니다.
학습·지식·평가·측정이 콘솔 위에서 실제로 맞물린다
콘솔이 자라며 가장 크게 늘어난 것이 지능·지식 층입니다. 개인 학습 루프(아래) 위에, 조직 지식 레이어 · 평가·측정 루프 · 스킬 층 · 사용·ROI가 얹혔습니다. 공통 원칙 하나 — 가능한 한 결정적으로, LLM은 좁고 감사된 한 지점에서만. 모두 코어의 chokepoint·redaction·감사를 그대로 통과합니다.
7.1개인 학습 합성 — delta에서 규칙으로
직원 워크스페이스의 학습 루프는 실제로 작동합니다. agent 제안과 직원 최종 선택의 차이(delta)를 캡처해 규칙으로 키웁니다.
7.2조직 지식 레이어 — LLM 없는 GraphRAG
관리자가 조직의 지식을 지식 Playbook으로 저작합니다(사실·해석·결정·미해결을 규율로 나눠). 핵심은 결정적이라는 점 — 값은 사람이 쓰고, 연결은 코드가 계산합니다.
결정적 엔티티 그래프
페이지마다 retrieval_terms(질의 → 페이지 발견성)와 선언된 entities(그래프 노드)를 답니다. 같은 엔티티를 공유한 페이지가 "관련"이 되어, LLM 추출 없이도 GraphRAG의 값을 냅니다. 검색은 DB 무관 다중토큰 AND + 랭킹.
결정적 우선 질의응답
질의응답은 검색 → redact → 구조화가 기본이고, LLM 의미 합성은 선택입니다. 신선도는 사람이 stale_at으로 표시하되 검색에서 숨기지 않고 플래그로 노출합니다. agent용 등가물은 context.ask MCP 도구 — 같은 게이트, 스코프상 보이는 페이지만.
7.3스킬 층 & 평가·측정 루프
"어떻게 하나"(스킬)와 "어떻게 판정하나"(평가 루브릭)를 쌍둥이로 둡니다. 관리자가 조직의 통제된 task 카탈로그를 정의하고, 각 task에 스킬과 루브릭을 저작합니다.
절차 런북 저작 → context.get_skill
스킬(절차 런북)은 DRAFT 생성 후 명시적 ACTIVATE(저작 시 본문 검증 = 서브 경로와 동일한 비신뢰-콘텐츠 방어). context.get_skill이 실제 내용을 반환합니다. 스킬 신호 = task별 암묵 평가(수정/거부율 + 스킬 유무) — 스킬이 있는데 지표가 오르면 약하거나 낡은 스킬 신호로 봅니다.
루브릭 = 버전드 판정 기준
평가 루브릭(EvalSpec)은 org 스코프·버전드·단일 활성입니다. 활성화 시 rationale + 암묵 신호 스냅샷을 동결해, 버전 체인 자체가 공동개발 기록이 됩니다. 루프 뷰는 라이브 암묵 신호(수정/거부율)를 활성 루브릭 옆에 두고 손봐야 할 task를 우선 정렬 + 명시적 사람 판정(과거 세션 0–5, 자문 감사행)합니다.
7.4사용·ROI — 정직한 롤업
사용·ROI는 신규 테이블 없이 기존 데이터에서 org 롤업을 파생합니다 — 볼륨 + 품질(수정/거부율) + 거버넌스(게이트가 막은 것) + 커버리지 + 정직한 시간절감 추정. 추정의 가정(minutes_per_action)을 겉으로 드러내고, 조작된 달러 금액은 만들지 않습니다.
OPENAI_API_KEY는 Authorization 헤더 전용·미로깅)만 있고, 3조건 게이트로 잠급니다 — ① 기능별 select-env(AISUIT_KNOWLEDGE_SYNTH=llm / AISUIT_RUBRIC_DRAFTER=llm) + ② AISUIT_LLM_EGRESS_ACKNOWLEDGED=1 + ③ 부팅 시 등록된 구현. 하나라도 없으면 결정적 경로로 fail-safe. 송신은 redacted 텍스트만이고 응답도 다시 redact(심층 방어). 쓰는 곳은 딱 둘 — 지식 의미 합성과 평가 루브릭 AI 초안뿐입니다.executing을 커밋(commit-claim-first)하기 때문에, claim과 finalize 사이 크래시가 행을 좌초시킵니다(부작용 발동 여부 불명). 리퍼가 age-gate(기본 900초)로 그런 행을 failed + 정직한 UNKNOWN 마커로 복구하고, 재실행은 언제나 의도적 사람 행위(자동 재시도 없음)입니다. 콘솔은 읽기전용 미리보기 + reap 액션을 제공합니다.db.query MCP 도구는 실 DB 연동 대기로 아직 미배선이며, 액션 레지스트리가 db.*를 기본 거부(safe-by-omission)합니다. 라이브 DB는 PostgreSQL 18.4로 cutover(코드가 AISUIT_DATABASE_URL env로 선택, Postgres면 pool_pre_ping+pool_recycle, pg_dump 자동 백업).팀과 함께 정할, 아직 열려 있는 것들
제품은 개발 완료·배포됐지만, 다음 단계에서 팀과 함께 결정할 항목이 남아 있습니다. 함께 논의해 주세요.