← 전체 프로젝트

01. 한 줄로 보는 localhost:daegu

localhost:daegu

대구 예비 창업자가 계약 전에 상권을 확인하고 필요 자금을 계산해 은행 상담자료를 만드는 창업 금융 네비게이터 — 2026 AI Blockchain Challenge Daegu

기간
2026-09-15 ~ 2026-09-29
팀 · 역할
3명 · 팀장 · PM/아키텍트 (API 계약·배포 구조·DB 스키마·리뷰·제출)
  • FastAPI
  • SQLAlchemy 2 · Alembic
  • PostgreSQL · pgvector
  • Gemini
  • Ollama Gemma 4
  • Next.js 16
  • MapLibre
  • Docker
  • Vercel
  • Cloudflare Tunnel
localhost:daegu 대표 화면

↓ 스크롤 또는 ← → 키로 넘기기

02. 설계 원칙 - 계약 먼저, 기능 단위 풀스택

3명이 5일 안에 끝내야 했습니다. 팀장으로서 구현 대신 API 계약을 먼저 확정하고, 팀원에게는 기능 하나를 백엔드부터 프론트까지 통째로 맡겼습니다.

문제
화면 담당과 서버 담당으로 나누면 서로를 기다리느라 5일이 모자라고, 같은 파일을 동시에 고쳐 충돌이 난다
선택
구현 전에 API 계약 확정 → 기능별 브랜치 → PR → 팀장 승인 → main. 공용 파일은 추가만 허용, 같은 API를 건드리는 기능은 한 사람에게
대가
팀장이 코드를 쓰지 않는 대신 문서 동기화를 하루 한 번 직접 해야 했다
효과
9/19 18:00 코드 프리즈 → 9/20 접수. 결정 26건 · 열린 쟁점 13건을 번호로 기록해 공개
계약 → 브랜치 → PR → 승인 흐름 (도식)
계약 → 브랜치 → PR → 승인 흐름 (도식)

왜 이 선택인가 — 버린 대안

  • 프론트 · 백엔드로 역할 분리
    한 기능이 두 사람을 오가며 대기 시간이 생긴다 — 5일 일정에서는 치명적

API 계약이란?

화면과 서버가 주고받을 데이터의 모양(필드 이름, 단위, 기간)을 먼저 합의한 문서입니다. 계약이 먼저 있으면 두 사람이 동시에 만들어도 마지막에 딱 맞물립니다.

근거: docs/handoff.md — 팀 분담 확정안 · decisions.md — 결정 기록

03. 결론은 코드가, AI는 해석만

은행 상담자료에 틀린 숫자가 들어가면 신뢰를 잃습니다. RedOceanMap에서 검증한 원칙을 팀 설계로 옮겨, 금액 계산은 코드가 하고 AI는 해석 문단만 쓰게 했습니다.

문제
LLM이 대출 부족액 같은 금액이나 위험 점수를 지어낼 위험
선택
결정론적 재무 엔진이 계산하고, 섹션 제목 · 표도 코드가 먼저 스트리밍. AI는 해석 문단만 쓰고 "숫자 재계산 금지"
대가
문장의 자유도가 낮고, 프롬프트에 모든 수치를 미리 실어야 한다
효과
가상 고객 10명 테스트에서 "수치가 없다"는 자기부정 문단 10명 → 0명. AI가 실패해도 계산 결과는 남는다
자금 입력과 최초안 · 현재안 비교 — 코드가 계산
자금 입력과 최초안 · 현재안 비교 — 코드가 계산
AI 진행 상태와 상담자료 — AI는 해석 문단
AI 진행 상태와 상담자료 — AI는 해석 문단

왜 이 선택인가 — 버린 대안

  • LLM이 판단과 수치를 함께 생성
    환각 위험 — 은행 상담에서 틀린 금액은 되돌릴 수 없다

계산기와 해설자를 나누기

숫자는 공식이 들어간 프로그램이 정확히 계산하고, AI는 그 숫자를 받아 "그래서 무엇을 조심해야 하는지"만 문장으로 풉니다. AI가 멈춰도 계산기는 멈추지 않습니다.

근거: 배포 · 페르소나 테스트 기록 · decisions.md — DEC-007

04. DB 스키마 19 → 29 테이블

서울 서비스를 대구로 옮기면서 은행 상담에 필요한 영역만 더했습니다. 기존 컬럼은 한 줄도 바꾸지 않았습니다.

문제
금융상품 · 외부 데이터셋 · 지표 · 상담 데이터를 담을 곳이 없었고, 이미 돌아가는 기능을 깨면 안 됐다
선택
4개 영역 10테이블을 단일 마이그레이션으로 추가, 기존 컬럼 무변경. 마이그레이션 왕복 · alembic check 통과, ERD 문서화
대가
어디에도 연결되지 않은 고립 테이블 2건이 남아 테스트로 감시해야 했다
효과
기존 기능 회귀 없이 확장 — 이후 백엔드 테스트 603개 통과
기존 19 테이블 + 4개 영역 추가 (도식)
기존 19 테이블 + 4개 영역 추가 (도식)

왜 이 선택인가 — 버린 대안

  • 기존 테이블에 컬럼 추가
    돌아가던 서울 기능과 데이터가 함께 흔들린다

마이그레이션 왕복이란?

DB 구조 변경을 적용했다가(upgrade) 되돌려도(downgrade) 원래대로 돌아오는지 확인하는 것입니다. 되돌릴 수 있어야 배포 당일에 문제가 생겨도 안전하게 물러설 수 있습니다.

근거: tasks.yml — WBS-020 · decisions.md — DEC-021

05. 배포 구조 - 무료로, 스트리밍을 지키며

프론트는 Vercel, 백엔드는 로컬 GPU 머신을 Cloudflare Tunnel로 공개했습니다. AI 문단이 프록시 뒤에서도 끊기지 않고 순서대로 도착하는지까지 운영 주소에서 확인했습니다.

문제
공모전 예산 0원, GPU는 로컬 한 대. 프록시를 거치면 스트리밍(SSE) 응답이 버퍼에 묶여 한꺼번에 도착할 수 있다
선택
Vercel + Cloudflare Tunnel + Docker DB. SSE 버퍼링 · uvicorn 워커 1개(분석 요청을 메모리에 보관) · 운영 크론 · 키 관리를 먼저 정하고 두 사람에게 분배
대가
워커 1개라 동시 처리량이 낮고, 서버가 꺼지면 서비스도 멈춘다 (대회 종료 후 실제로 중단)
효과
운영 주소에서 첫 이벤트 0.2초, 첫 AI 문단 1.4초 도착 확인
Vercel → Tunnel → FastAPI → PostgreSQL (도식)
Vercel → Tunnel → FastAPI → PostgreSQL (도식)

왜 이 선택인가 — 버린 대안

  • 클라우드 GPU 서버
    공모전 기간 비용 — 이미 같은 구성으로 운영 중인 다른 서비스의 경험을 재사용

SSE 버퍼링 문제

서버가 글자를 조금씩 흘려보내도(스트리밍) 중간 프록시가 모아 두었다가 한꺼번에 넘기면 사용자는 한참 기다리게 됩니다. 프록시 설정과 서버 설정을 함께 맞춰야 실시간으로 보입니다.

근거: docs/architecture.md — 운영 구성 · decisions.md — DEC-020

06. 위험 점수는 확률이 아니라 순위로

위험 80점 같은 절대 점수는 폐업 확률처럼 읽힙니다. 대구 142개 동 가운데 몇 번째인지로 바꿔, 실패 확률이 아님을 화면에 명시했습니다.

문제
절대 점수는 사용자가 "80% 확률로 망한다"로 오해할 수 있다 — 은행 상담 자료로는 위험한 표현
선택
상대 위험 높음 · 중간 · 낮음 + 142개 동 중 순위로 표기하고 "실패 확률이 아님"을 명시. 데이터 표현 수위 원칙을 팀 규칙으로 정함
대가
한눈에 들어오는 단일 숫자의 직관성을 포기했다
효과
점수 옆에 비교 기준(142개 동 중 순위)이 함께 보인다 (오해 감소 효과는 측정 전)
행정동 지도와 상대 위험 순위
행정동 지도와 상대 위험 순위
iM뱅크 상담 후보 카드
iM뱅크 상담 후보 카드

왜 이 선택인가 — 버린 대안

  • 0~100 위험 점수
    확률로 읽혀 과신 또는 과도한 불안을 부른다

상대 순위로 보여주는 이유

점수의 기준이 무엇인지 모르면 숫자는 오해를 부릅니다. "142개 동 가운데 몇 번째로 위험이 높다"는 비교 기준이 문장 안에 들어 있어, 받아들이는 사람이 스스로 판단할 수 있습니다.

근거: tasks.yml — WBS-025

07. 결과와 회고

가상 고객 테스트 (운영 주소)
10명 전원 완주
1인 평균 소요
30.6초
상담자료 생성 평균
11.2초
테스트
백엔드 603 · 프론트 226
결정 기록
DEC 26 · OPEN 13

아쉬운 점 · 다음에 할 것

  • 백엔드를 팀원 PC에서 온프레미스로만 운영해 커밋이 한 계정으로 올라갔다 — 개인별 기여를 git에 남기는 방식을 미리 정했어야 했다
  • Neo4j · Redis를 구성만 하고 쓰지 않았다 — 범위를 더 일찍 잘랐어야 했다
  • 외부 AI 장애 시 로컬 모델로 자동 전환하지 못하고 수동 전환에 머물렀다