<?xml version='1.0' encoding='utf-8'?>
<mxfile host="drawio" version="26.0.0" agent="drawio-skill / justfun" modified="2026-10-15T00:00:00.000Z">
  <diagram id="system" name="전체 시스템 구성도">
    <mxGraphModel dx="1480" dy="900" grid="1" gridSize="10" page="1" pageScale="1" pageWidth="1480" pageHeight="900" background="#151b17">
      <root>
        <mxCell id="0" />
        <mxCell id="1" parent="0" />
        <mxCell id="system-title" value="전체 시스템 구성도" style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=middle;fillColor=none;strokeColor=none;fontFamily=Arial;fontSize=23;fontColor=#dce8df;spacing=0;fontStyle=1;" vertex="1" parent="1">
          <mxGeometry x="30" y="20" width="1420" height="32" as="geometry" />
        </mxCell>
        <mxCell id="system-subtitle" value="브라우저 임베딩 · Python LangChain 검색 · Supabase 데이터 · PC 모델/큐" style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=middle;fillColor=none;strokeColor=none;fontFamily=Arial;fontSize=13;fontColor=#94aa9b;spacing=0;" vertex="1" parent="1">
          <mxGeometry x="30" y="59" width="1420" height="26" as="geometry" />
        </mxCell>
        <mxCell id="client-tier" value="01  방문자 브라우저" style="swimlane;startSize=40;html=1;whiteSpace=wrap;rounded=1;arcSize=6;container=1;pointerEvents=0;collapsible=0;fillColor=#19231c;swimlaneFillColor=#151b17;strokeColor=#3c4c41;fontColor=#94aa9b;fontFamily=Arial;fontSize=13;align=left;spacingLeft=18;fontStyle=1;" vertex="1" parent="1">
          <mxGeometry x="30" y="120" width="270" height="650" as="geometry" />
        </mxCell>
        <mxCell id="cloud-tier" value="02  Vercel · Next.js" style="swimlane;startSize=40;html=1;whiteSpace=wrap;rounded=1;arcSize=6;container=1;pointerEvents=0;collapsible=0;fillColor=#19231c;swimlaneFillColor=#151b17;strokeColor=#3c4c41;fontColor=#94aa9b;fontFamily=Arial;fontSize=13;align=left;spacingLeft=18;fontStyle=1;" vertex="1" parent="1">
          <mxGeometry x="330" y="120" width="310" height="650" as="geometry" />
        </mxCell>
        <mxCell id="data-tier" value="03  Supabase · 유일한 문서 DB" style="swimlane;startSize=40;html=1;whiteSpace=wrap;rounded=1;arcSize=6;container=1;pointerEvents=0;collapsible=0;fillColor=#19231c;swimlaneFillColor=#151b17;strokeColor=#3c4c41;fontColor=#94aa9b;fontFamily=Arial;fontSize=13;align=left;spacingLeft=18;fontStyle=1;" vertex="1" parent="1">
          <mxGeometry x="670" y="120" width="310" height="650" as="geometry" />
        </mxCell>
        <mxCell id="local-tier" value="04  제작자 PC · 터널 안쪽 서비스" style="swimlane;startSize=40;html=1;whiteSpace=wrap;rounded=1;arcSize=6;container=1;pointerEvents=0;collapsible=0;fillColor=#19231c;swimlaneFillColor=#151b17;strokeColor=#3c4c41;fontColor=#94aa9b;fontFamily=Arial;fontSize=13;align=left;spacingLeft=18;fontStyle=1;" vertex="1" parent="1">
          <mxGeometry x="1010" y="120" width="440" height="650" as="geometry" />
        </mxCell>
        <mxCell id="browser" value="문서 챗봇 화면&#10;업로드 · 질문 · 출처 확인" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="client-tier">
          <mxGeometry x="30" y="65" width="210" height="100" as="geometry" />
        </mxCell>
        <mxCell id="browser-session" value="3일 쿠키 UUID&#10;업로드 본문 추출 · 청킹&#10;MPNet 768차원 임베딩" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="client-tier">
          <mxGeometry x="30" y="250" width="210" height="120" as="geometry" />
        </mxCell>
        <mxCell id="web" value="Next.js API&#10;입력·세션 권한 검증&#10;검색 요청 · 대기열 접수" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="cloud-tier">
          <mxGeometry x="50" y="65" width="220" height="120" as="geometry" />
        </mxCell>
        <mxCell id="api-storage" value="문서·청크·벡터 저장&#10;세션 쿠키 증명 생성&#10;응답·근거 반환" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="cloud-tier">
          <mxGeometry x="50" y="280" width="220" height="120" as="geometry" />
        </mxCell>
        <mxCell id="supabase" value="PostgreSQL + pgvector&#10;문서·청크·768차원 벡터&#10;세션 소유권 RPC" style="shape=cylinder3;size=12;boundedLbl=1;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="data-tier">
          <mxGeometry x="45" y="230" width="220" height="130" as="geometry" />
        </mxCell>
        <mxCell id="supabase-example" value="예제 문서·청크&#10;미리 임베딩한 검색 데이터" style="shape=cylinder3;size=12;boundedLbl=1;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="data-tier">
          <mxGeometry x="45" y="470" width="220" height="95" as="geometry" />
        </mxCell>
        <mxCell id="tunnel" value="Cloudflare Tunnel&#10;인증된 HTTPS 진입점" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="local-tier">
          <mxGeometry x="30" y="60" width="180" height="85" as="geometry" />
        </mxCell>
        <mxCell id="gateway" value="Node 게이트웨이&#10;인증 · PC MPNet 임베딩&#10;Python / Redis 경로 연결" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="local-tier">
          <mxGeometry x="230" y="60" width="180" height="100" as="geometry" />
        </mxCell>
        <mxCell id="retriever" value="Python · FastAPI&#10;LangChain BaseRetriever&#10;유사도 기준 · BM25 + RRF" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="local-tier">
          <mxGeometry x="30" y="220" width="180" height="115" as="geometry" />
        </mxCell>
        <mxCell id="redis" value="Redis 대기열&#10;FIFO · 동시 실행 1개" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="local-tier">
          <mxGeometry x="230" y="250" width="180" height="90" as="geometry" />
        </mxCell>
        <mxCell id="worker" value="Python FIFO 워커&#10;Redis 작업 소비 · RAG 실행" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="local-tier">
          <mxGeometry x="30" y="430" width="180" height="100" as="geometry" />
        </mxCell>
        <mxCell id="models" value="Cross-Encoder&#10;Ollama · Gemma 4&#10;CUDA 언어 모델 36/36&#10;비전 인코더는 CPU" style="rounded=1;arcSize=10;html=1;whiteSpace=wrap;fontFamily=Arial;fontSize=15;fontColor=#dce8df;fillColor=#223c2c;strokeColor=#7ee2b8;strokeWidth=1.3;spacing=12;align=center;verticalAlign=middle;" vertex="1" parent="local-tier">
          <mxGeometry x="230" y="440" width="180" height="110" as="geometry" />
        </mxCell>
        <mxCell id="serve-pages" value="HTTPS 질문 / 문서" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="browser" target="web">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="browser-session-save" value="쿠키·업로드 벡터" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="browser" target="browser-session">
          <mxGeometry relative="1" as="geometry">
            <mxPoint x="55" y="0" as="offset" />
          </mxGeometry>
        </mxCell>
        <mxCell id="store-document" value="저장·목록·세션 RPC" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=1;exitY=0.4;exitDx=0;exitDy=0;entryX=0;entryY=0.4;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="api-storage" target="supabase">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="640" y="435" />
              <mxPoint x="640" y="425" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="search-tunnel" value="검색·큐 요청" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=1;exitY=0.7;exitDx=0;exitDy=0;entryX=0;entryY=0.35;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="web" target="tunnel">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="980" y="285" />
              <mxPoint x="980" y="210" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="gateway-python" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=0.1;exitY=1;exitDx=0;exitDy=0;entryX=0.9;entryY=0;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="gateway" target="retriever">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="1340" y="320" />
              <mxPoint x="1140" y="320" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="retriever-db" value="pgvector RPC · 검색 결과" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=0;exitY=0.45;exitDx=0;exitDy=0;entryX=1;entryY=0.8;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="retriever" target="supabase">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="990" y="400" />
              <mxPoint x="990" y="520" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="tunnel-gateway" value="인증" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="tunnel" target="gateway">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="gateway-queue" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="gateway" target="redis">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="queue-worker" value="FIFO 작업" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="redis" target="worker">
          <mxGeometry relative="1" as="geometry">
            <mxPoint x="70" y="0" as="offset" />
          </mxGeometry>
        </mxCell>
        <mxCell id="worker-model" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="worker" target="models">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="api-answer" value="답변·출처·상태" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;endSize=8;strokeWidth=1.4;strokeColor=#7ee2b8;fontColor=#94aa9b;fontFamily=Arial;fontSize=12;labelBackgroundColor=#151b17;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=block;startFill=1;startSize=8;" edge="1" parent="1" source="worker" target="web">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="1450" y="540" />
              <mxPoint x="1450" y="100" />
              <mxPoint x="320" y="100" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="legend-current" value="● 현재 동작 중인 연결" style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=middle;fillColor=none;strokeColor=none;fontFamily=Arial;fontSize=13;fontColor=#7ee2b8;spacing=0;" vertex="1" parent="1">
          <mxGeometry x="35" y="800" width="280" height="24" as="geometry" />
        </mxCell>
        <mxCell id="system-note" value="Python LangChain: 검색·임계값·RRF·리랭킹·LLM. Python 워커가 Redis FIFO를 소비합니다. Node 게이트웨이는 로컬 모델·임베딩·리랭커를 중계합니다." style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=middle;fillColor=none;strokeColor=none;fontFamily=Arial;fontSize=12;fontColor=#94aa9b;spacing=0;" vertex="1" parent="1">
          <mxGeometry x="335" y="800" width="1110" height="24" as="geometry" />
        </mxCell>
        <mxCell id="system-security" value="문서 데이터는 Supabase에 저장합니다. 세션 권한은 검색 RPC에서 검증하고, DB·모델 비밀값은 서버 간 요청으로만 전달합니다." style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=middle;fillColor=none;strokeColor=none;fontFamily=Arial;fontSize=12;fontColor=#94aa9b;spacing=0;" vertex="1" parent="1">
          <mxGeometry x="35" y="838" width="1410" height="24" as="geometry" />
        </mxCell>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>