PROJECT DOCUMENTATION

3. 상위 설계서

첫 배포·11업종 지표 반영기준일 2026-09-19담당 장민석 · PM/아키텍트

실제로 구현한 모듈과 데이터 흐름, AI와 외부 서비스의 연결, 첫 배포와 남은 작업을 정리합니다.

개발 개요

9월 19일 밤 작업 로그의 첫 배포·데이터 배선·11업종 지표까지 반영한 구조입니다. 이전 자작 서비스 Metabole(서울 상권)을 대구 기준으로 바꿨고(DEC-006), 한 문장 질문 → 지도 선택 → 자금 계산·비교·선택 → 상담자료 → 공식 안내 흐름을 실백엔드로 완주했습니다. 9월 19일 첫 배포와 운영 페르소나 10건 검증을 마쳤습니다. 최신 프론트 변경 재배포는 남아 있습니다.

모듈 중심 Data Flow

한 문장 질문 → 지도·상권 확인 → 비용·자금 입력 → 최초안/수정안 비교·선택 → 상담자료 생성 → Markdown 저장·인쇄 → 사용자가 iM뱅크 상담에 지참합니다. 공식 상담 경로는 링크 안내이며 은행 자동 전송·예약은 없습니다. Next.js와 FastAPI는 REST·SSE로 연결되며 화면 초안은 sessionStorage, 서버 상담 기록·문서 해시는 PostgreSQL의 ORM 기준 31테이블에 저장합니다. 상권 진단에는 dataset·indicator의 동네 특성 지표를 포함합니다. 계산·표는 코드, 해석·질문은 AI가 담당합니다. Gemini가 기본이며 로컬 gemma4:12b·qwen3-embedding:4b 작성기·검색 배선은 완료됐습니다. 로컬 전환은 provider 설정 변경과 해당 임베더 재색인이 필요한 수동 작업이며 자동 장애 폴백은 없습니다. 2026-09-19 첫 배포 경로는 프론트 Vercel·백엔드 Cloudflare Tunnel·DB 로컬 Docker이며 :3300·:8300은 로컬 포트입니다.

2026-09-20 서비스 설계서·ORM·provider 설정·프론트 흐름 대조 기준. 2026-09-19 첫 배포 기록과 로컬 개발 구성을 구분했습니다. 색상별 박스는 기능 묶음으로 개별 모듈 수와 다르며, 화살표는 사용자 동선·요청·조회·적재 방향입니다.

  1. 사용자가 채팅 첫 화면에 한 문장을 입력하면 백엔드가 구·동·랜드마크, 업종, 예산을 추출합니다.
  2. 지도 화면이 해당 행정동을 보여 주고, 행정동 × 업종 지표와 위험도를 조회합니다.
  3. 비용·자기자본·예상 매출로 총 준비자금·조달 필요액·희망대출 반영 후 부족액을 계산하고, 최초안과 현재안을 비교·선택합니다. 상담 후보는 iM뱅크 연결 근거와 자격·자치구 조건으로 고릅니다.
  4. 상담자료 요청 시 입력을 서버 엔진으로 다시 계산하고 계획·비교·계산표·정책자금·확인 질문·상권 섹션을 SSE로 전달합니다. 수치·비교표·미확인 항목은 코드가 정하고 Gemini가 설명·질문을 씁니다. 선택 연도는 지표와 위험도까지 전달합니다.
  5. 화면 초안은 sessionStorage에 보관하고, 상담자료 생성 시 서버에 세션·계획·노트를 기록합니다. 재생성은 같은 세션을 갱신하며 완성된 자료 다운로드 시 선택안과 sha256 해시를 기록합니다. 공식 안내 이동은 은행에 자료를 전송하지 않습니다.
  6. 정기 수집 작업이 공공 데이터를 매일·매시 적재하고, 지표 재계산과 검색 색인을 갱신합니다.

모듈과 필수 조건

백엔드는 헥사고날 구조(도메인 · 유스케이스·포트 · 어댑터 · 조립)이며, 기능마다 bounded context를 둡니다.

기능 묶음 백엔드 모듈 프론트엔드 입력 → 출력 필수 조건
입력 해석 intent intent-gate(채팅 첫 화면) 한 문장 → 구·동 코드, 업종, 예산 긴 지명을 먼저 비교(“달서구”를 “서구”로 오인하지 않음), 단위가 붙은 금액 합산
상권 진단 master(구·동·업종·경계), store(인허가), metric(지표·위험도) map-explorer(지도·사이드 패널·위험도 카드) 행정동·업종·연도 → 점포 수·폐업률·점포 증감률, 위험도 기본 연도는 마지막 완결 연도. 위험도는 상대 순위이며 실패 확률로 표시하지 않음
자금 계산·매칭 finance(재무 엔진), matching(후보), product(상품 DB), shock(금리) simulator(계산안 비교·선택·후보 카드) 비용·자금·지역 → 자금 구성·시나리오·상담 후보 계산은 코드. 재무 미입력 시 계산·매칭 생략. matching은 product 입력 포트 사용
상담 기록 consultation 상담 초안·자료 내보내기 세션·계획·가정·확인 질문·문서 해시 화면 정본은 sessionStorage, 서버 기록은 감사·재현용. 저장 실패가 자료 생성을 막지 않음
외부 데이터 dataset·indicator 지도 패널 동네 특성·도시철도 승차 공공데이터 5종 → 행정동 지표 9/19 적재·화면 연결 완료. 센터 민간 데이터는 미확보
AI 리포트 analysis(목적별 구성·SSE), rag(검색), news·funding(근거 문서) agent-report(진행·자료 뷰) 지역·연도·재무·상담 입력 → review 또는 handoff 수치·비교표는 코드, 설명·질문은 AI. handoff에 재무·상담 입력 필수
수집 store·funding·news·rent·shock·rag 수집기, scripts/*.sh — 외부 API → DB·색인 소스별 오류 격리, 가장 나쁜 종료 코드 기록, 중복 실행 방지

편의점 상가정보 2,019건과 담배소매업 33,804건을 적재했습니다. 지표 원천은 인허가·담배소매인·어린이집 Strategy로 합성하며 등록 11업종을 연결합니다. 편의점은 담배소매인 대용, 학원·부동산·어린이집 폐업은 스냅샷 소실 추정으로 표시합니다.

AI 모델 학습·추론 흐름

학습·평가 준비 — 자체 학습 없음

모델을 직접 학습하거나 미세 조정하지 않습니다. 기본 경로는 외부 모델 API(Google Gemini)이고, 외부 API가 끊겼을 때를 위해 로컬 모델(Ollama) 경로를 같은 포트 뒤에 어댑터로 두었습니다.

용도 온라인(기본) 오프라인(대체, 평가 완료·전환 전) 비고
리포트 해석 문단 gemini-3.8-flash gemma4:12b (환경변수 REPORT_WRITER_PROVIDER=ollama) 팀 결정 “최신 정식 Flash 모델”(DEC-009). 로컬 대체는 DEC-022
검색 색인·질의 임베딩 gemini-embedding-001(2560차원) qwen3-embedding:4b(2560차원) 색인과 질의는 같은 임베더만 짝지어 사용. 9/19 halfvec(2560) 마이그레이션·Gemini 재색인·provider 설정화 완료. 로컬 전환 시 해당 임베더로 다시 재색인

9월 18일에 온라인·오프라인 후보를 같은 코퍼스(3,448건)·질문(80건)·프롬프트로 나란히 평가했습니다. 임베딩은 qwen@2560이 Top-1 0.762로 Gemini(0.700~0.738)와 동급 이상이었고, 리포트 생성은 gemma4:12b가 Gemini와 같은 게이트 전부 통과(1.000)를 냈습니다. 두 경로가 고르는 근거 문서는 절반가량 다릅니다. 상세는 모델 평가에 있습니다. 평가셋 80건은 자동 생성한 미검수 상태이며, 문장의 설득력·해석 정확도는 아직 재지 않았습니다.

서비스 추론 — 구현

분석 요청 저장(한 번만 쓰는 ID) → 에이전트가 차례로 자료 수집: 상권(지표·위험도) → 관련 뉴스 검색(pgvector) → 자금(재무 입력이 있으면 재무 계산, 금융상품 매칭, 정책 공고 검색) → 섹션마다 코드가 제목·점수·표를 먼저 전송 → Gemini가 해석 문단을 스트림 → 참고 자료와 함께 완료 이벤트 전송.

  • 에이전트 하나가 실패해도 오류 상태만 알리고 나머지를 계속 진행하며, 스트림은 항상 완료 이벤트로 끝납니다.

  • 사용자 질문과 검색 문서는 태그로 감싸고, 그 안의 지시는 따르지 않도록 시스템 지시에 명시했습니다.
  • 임베딩 호출은 호출 한도(429)·일시적 5xx 오류에 재시도합니다. 해석 문단 생성이 실패한 섹션은 대체 문구로 채웁니다.
  • 분석 요청 저장소가 메모리에 있어 백엔드는 워커 1개로 실행해야 합니다. 워커를 늘리려면 Redis 같은 공유 저장소 어댑터가 필요합니다.

개발 환경과 기술 요소

구분 사용 중인 기술 비고
문서 사이트 Jekyll + Just the Docs, GitHub Pages 서비스 저장소 개발 기록을 수동으로 반영
서비스 프론트엔드 Next.js 16 · React 19 · Tailwind CSS 4 · TanStack Query · MapLibre GL 포트 3300. 백엔드 계약을 흉내 낸 mock API 라우트 포함
서비스 백엔드 Python 3.14 · FastAPI · SQLAlchemy 2 · Alembic · Pydantic Settings · google-genai 포트 8300. 헥사고날 구조
데이터 저장소 PostgreSQL 17 + pgvector(Docker) 원천·지표·검색 색인 모두 저장
구성만 된 저장소 Redis 7 · Neo4j 5(Docker) 현재 코드에서 사용하지 않음. Neo4j를 쓸지 구성에서 뺄지는 여력 시 결정
AI Gemini API(생성·임베딩) · Ollama(로컬 대체 경로, 전환 전) 키는 환경변수로 주입. 작성기·임베더는 provider 레지스트리로 교체
테스트 pytest · Vitest · Testing Library · Playwright(headless) 시나리오 테스트 참고
정기 실행 서버 crontab + 셸 스크립트 뉴스 매시, 인허가·공고·색인 매일, 금리·임대료 주 1회
인프라 로컬 개발 머신 프론트엔드 Vercel · 백엔드 Cloudflare Tunnel · DB 로컬 Docker로 확정, 9/19 첫 배포 완료(아래 배포 구조 참고)

데이터 스토어 포트는 모두 127.0.0.1에만 열어 두었습니다(PostgreSQL 5437, Redis 6381, Neo4j 7476·7689).

외부 연동

연동 목적 현재 상태 남은 확인
공공데이터포털 인허가 7업종 개폐업 지표·위험도 연동·정기 수집 카페(휴게음식점) 단기 개폐업의 분류 근거
브이월드 행정동 경계, 지도 배경 연동(경계 142/144) —
한국부동산원 R-ONE · 한국은행 ECOS 임대료·공실률 · 금리 연동·주 1회 수집. 금리는 기본값, 임대료는 상권·평수 선택 도우미에 사용 행정동 자동 매핑 없음
기업마당 · 온통청년 지원사업·청년 창업 정책(리포트 근거) 연동·매일 수집 다른 구·군 전용 문서 제외 반영, 기간 필터 없음
구글 뉴스 RSS 상권 뉴스(리포트 근거) 연동·매시 수집 모든 키워드가 실패해도 정상 종료로 기록되는 문제
Gemini API 리포트 해석·임베딩 연동(유료 키) 운영 키 주입·SSE 확인. 로컬 대체 배선 완료, 전환은 수동이며 자동 폴백 없음
금융상품 상담 후보 매칭 은행 API 연동 없음. 공개 자료 12건을 JSON에서 DB로 시드. 9/18 원문 대조 완료, 9/18 direct 2·linked 3·unverified 7 → 9/19 direct 2·linked 7·unverified 3(재단 보증 4건 승격, 제도 구조에 대한 팀 확인 근거) 재단 4건 실제 취급은행·youth-1의 2026년 재공고 확인
DIP 빅데이터활용센터 카드 소비·생활인구 미확보 이용·반출·공개 조건(OPEN-004)
블록체인(리포트 해시 기록) 리포트 진위·시점 증명 범위 제외(DEC-018). 상담 자료의 sha256 해시만 서버에 기록 —

배포 구조 — 9월 19일 첫 배포 완료

배포 주소는 localhostdaegu.cloud이며 9월 19일 첫 배포했습니다. 프론트엔드는 Vercel, 백엔드는 로컬 GPU 머신에 Cloudflare Tunnel, DB는 로컬 Docker로 정했습니다(DEC-020). 절차는 서비스 저장소 docs/deploy-vercel-cloudflare.md에 있습니다. 네임서버 Cloudflare 이전과 TLS·CORS 확인을 마쳤습니다. Vercel Git 연동이 푸시마다 자동 배포하며, 9/19 밤 기록에서 프론트 최신 변경 5개 커밋은 미푸시였습니다.

결정·확인 항목 현재 코드에서 확인한 조건
AI 키 백엔드에 Gemini 키가 없으면 분석 시작 요청이 500. 리포트 모델은 환경변수로 바꿀 수 있고 코드 기본값은 gemini-3.8-flash
CORS 로컬 출처는 항상 허용하고 CORS_ALLOW_ORIGINS(쉼표 구분)로 운영 도메인을 추가(9/18 반영)
워커 수 분석 요청 저장소가 메모리라 워커 1개
프록시 Cloudflare 뒤 첫 이벤트 0.2초·첫 report_delta 1.4초·12초대까지 순차 도착 확인
정기 수집 crontab 수집 가동·9/19 온통청년 키 교체 확인. 추가 수집기 환경변수 배포 설정은 남음

요구사항별 구현 목표와 시나리오

REQ-002는 자금 구성·계산안 비교·지역별 상담 후보·자료 저장을, REQ-003은 선택 연도 전달과 목적별 리포트 구성을 확인합니다. 테스트 시나리오에 정상·예외 경로를 연결합니다. 기간 일치(①), AI 진행 안내(②), 자금 점검 동선·가정 표시(③), 데이터 신뢰 표시(④)는 9/19까지 반영 완료했습니다. 코드 프리즈는 해제했습니다.


맨 위로

053 · DAEGU · 2026