장소의 좌표보다 그곳을 기억하는 이유를 기록하는 AI 기반 장소 아카이빙 플랫폼
PinLog는 장소와 함께 사용자의 경험·감정·목적을 Context로 기록하고, 장소 이름이 기억나지 않아도 자연어로 다시 찾게 해줍니다. 기록은 익명 컬렉션으로 엮어 공유하며, 타인의 Context 원문은 공개하지 않고 장소와 AI Keyword만 노출합니다.
이 저장소는 포트폴리오와 프로젝트 탐색을 위한 대표 모노레포입니다. Backend, Frontend, AI, Infrastructure, 공식 명세 저장소의 Git 이력을 보존해 한곳에 모았습니다.
전체 서비스 화면 보기 · 아키텍처 자세히 보기 · 전체 ERD 보기
- 맥락 중심 장소 기록: Kakao 장소 검색·지도로 장소를 선택하고 방문 이유와 경험을 Context로 남깁니다.
- AI 자연어 검색: 임베딩, Keyword, 문자열 검색, LLM 관련도 신호를 결합해 개인 기록을 다시 찾습니다.
- 이미지 기반 장소 제안: 대화·사진을 분석해 장소 후보와 기록할 맥락을 제안합니다.
- 익명 컬렉션과 탐색: 기록을 책처럼 묶어 발행하고 다른 사용자의 공개 컬렉션과 선반을 탐색합니다.
- 개인정보 경계: 타인의 Context 원문과 내부 식별자는 숨기고 공개 가능한 장소·Keyword만 응답합니다.
- 관측 가능한 GitOps 운영: k3s, Argo CD, Sealed Secrets, Prometheus/Grafana 기반으로 배포와 운영을 자동화합니다.
장소명·주소 검색 또는 대화 캡처 이미지 분석으로 장소 후보를 찾습니다. 사용자가 장소와 Context를 함께 저장해야 Record가 만들어지므로 위치만 남고 이유가 사라지는 기록을 허용하지 않습니다.
| 장소 검색·이미지 분석 | Context 작성 |
|---|---|
![]() |
![]() |
“치즈케이크 한 조각과 진한 커피를 앞에 두고 쉬었던 곳”처럼 사용자가 남긴 Context를 자연어로 검색합니다. AI 서버가 후보를 찾고 Backend가 소유권과 원문을 다시 확인한 뒤 Record 단위 결과를 지도와 함께 제공합니다.
내 Record를 Collection으로 구성하면 지도와 목차를 가진 한 권의 책이 됩니다. 다른 사용자는 공개 Collection의 장소와 공개 Keyword만 볼 수 있으며 작성자의 Context 원문과 내부 ID는 볼 수 없습니다.
| 익명 Collection 탐색 | Collection 상세 |
|---|---|
![]() |
![]() |
Library는 내 Collection과 팔로우한 사용자의 선반을 함께 보여줍니다. 팔로우 대상에게 사용자가 직접 별칭을 붙일 수 있고, 같은 선반도 사람마다 다른 이름으로 관리할 수 있습니다.
| 나의 책장 | 활동 기록 |
|---|---|
![]() |
![]() |
17개 화면을 기능 흐름대로 설명한 Product Tour →
| 경로 | 원본 저장소 | 책임 | 주요 기술 |
|---|---|---|---|
back/ |
Team-PinLog/back |
인증, 장소·기록·컬렉션·팔로우, AI 오케스트레이션 API | Java 21, Spring Boot, PostgreSQL, Redis, Kafka |
front/ |
Team-PinLog/front |
지도 기반 기록, 자연어 검색, 컬렉션·피드 UI | React 19, TypeScript, Vite, TanStack Query/Router |
ai/ |
Team-PinLog/ai |
임베딩·Keyword 판정, 개인 검색, 이미지 장소 제안 | Python 3.12, FastAPI, pgvector, LLM/Embedding API |
infra/ |
Team-PinLog/infra |
Kubernetes 배포, 보안, 관측, 백업, GitOps | k3s, Argo CD, Helm, Sealed Secrets, Prometheus/Grafana |
specs/ |
Team-PinLog/docs |
제품 정책, AI 설계, 데이터 모델, API 계약 | Markdown, Mermaid |
cowork, image, seed, mockup, pico-agent는 제품 개발을 지원한 별도 도구·실험 저장소이므로 대표 저장소의 실행 구성에서는 제외했습니다.
flowchart LR
User[Web User] -->|HTTPS| Edge[Cloudflare Tunnel / Ingress]
Edge --> Front[React SPA]
Edge -->|/api/core| Back[Spring Boot API]
Front --> Kakao[Kakao Maps / Local API]
Back --> Redis[(Redis)]
Back --> Core[(PostgreSQL core)]
Back --> Kafka[(Kafka)]
Back -->|Internal API| AI[FastAPI AI]
Kafka --> AI
AI --> Derived[(PostgreSQL ai + pgvector)]
AI --> Models[Embedding / LLM / Vision]
Argo[Argo CD] --> Edge
Monitor[Prometheus / Grafana / Loki] -. observe .-> Back
Monitor -. observe .-> AI
브라우저는 Backend를 통해 개인 데이터와 권한이 필요한 작업을 수행합니다. AI 서버는 외부에 노출되지 않으며 ai 스키마의 파생 데이터만 소유합니다. Backend가 core 도메인, 인증, 최종 응답 조립을 담당해 AI 모델과 개인정보 사이의 신뢰 경계를 유지합니다.
erDiagram
MEMBER ||--o{ SOCIAL_ACCOUNT : authenticates
MEMBER ||--o{ RECORD : owns
PLACE ||--o{ RECORD : identifies
RECORD ||--|{ CONTEXT : contains
MEMBER ||--o{ COLLECTION : creates
COLLECTION ||--|{ COLLECTION_RECORD : contains
RECORD ||--o{ COLLECTION_RECORD : included_in
MEMBER ||--o{ FOLLOW : follows
CONTEXT ||--o| CONTEXT_AI_STATE : tracks
CONTEXT ||--o| CONTEXT_EMBEDDING : indexed_as
CONTEXT ||--o{ CONTEXT_KEYWORD : tagged_with
KEYWORD_PRESET ||--o{ CONTEXT_KEYWORD : classifies
Core와 AI 스키마는 같은 PostgreSQL 인스턴스를 사용하지만 소유권과 DB Role을 분리합니다. Context 수정은 기존 행을 덮어쓰지 않고 새 Context를 생성하며, 삭제·수정 중 도착한 AI 결과는 CANCELLED 상태와 저장 직전 재검사로 폐기합니다.
개인별 pgvector exact cosine 검색을 기본 경로로 두고 질의 재작성·Keyword 재정렬·본문 문자열 검색·LLM 관련도 판정을 강등 가능한 보조 신호로 결합했습니다. 단어형 질의는 별도의 절대 임계값을 적용하고, Record마다 가장 유사한 Context 하나만 남깁니다. 외부 모델 호출이 실패하면 기본 벡터 검색으로 복귀하며, 오프라인 실측 게이트를 통과한 신호만 운영 환경에 활성화했습니다.
Context 저장 요청은 즉시 사용할 수 있도록 먼저 완료하고 Embedding·Keyword 분석은 비동기로 처리합니다. AI 서버는 모델 호출 전후 상태를 검사하고 저장 직전에 짧은 행 잠금을 사용합니다. PENDING → PROCESSING → COMPLETED/FAILED 전이를 단계별로 관리하며, 처리 중 Context가 삭제·교체되면 CANCELLED를 확인해 늦게 도착한 결과를 폐기합니다. Embedding만 성공했다면 Keyword 단계부터 부분 재개합니다.
Google·Kakao·Naver OAuth 로그인 뒤 Access·Refresh Token을 HttpOnly Cookie로 전달하고 별도 CSRF Cookie/Header 계약을 적용합니다. Refresh Token은 사용할 때마다 회전하며 이전 토큰 재사용이 감지되면 회원 단위 세션을 폐기합니다. Frontend는 탭 내부 Promise 공유와 Web Locks로 여러 탭의 동시 재발급을 single-flight 처리하고, DB 장애로 발생한 503은 인증 거절인 401과 분리해 세션을 유지합니다.
활성 Record는 Context를 최소 하나, 활성 Collection은 Record를 최소 하나 가져야 합니다. 마지막 Context·Record를 제거할 때는 상위 객체까지 함께 사라질 수 있음을 안내하고 강제 삭제 경로에서만 연쇄 처리합니다. 타인 조회는 활성·발행 상태와 공개 Keyword를 쿼리 단계에서 제한하고, 응답 DTO에서도 내부 Member·Record·Context ID와 Context 원문을 제외합니다.
각 애플리케이션 CI가 검증된 commit SHA 기반 불변 이미지 태그를 GHCR에 발행하면 Infra 저장소의 후보 검증과 PR을 거쳐 Argo CD가 선언 상태를 k3s 클러스터에 동기화합니다. Cloudflare Tunnel과 Traefik이 공개 진입점을 담당하고, Sealed Secrets·NetworkPolicy·Pod Security·리소스 제한을 배포 선언과 함께 관리합니다. Prometheus·Grafana·Loki로 메트릭과 로그를 관측하며 PostgreSQL 백업·복구 절차를 Runbook으로 고정했습니다.
| 문제 | 적용한 해결책 | 사용자·운영 효과 |
|---|---|---|
| AI 처리 중 Context가 삭제되거나 수정됨 | 불변 Context ID, 상태 재검사, 저장 직전 행 잠금, CANCELLED 전이 |
삭제한 기록의 Keyword·Embedding이 검색에 다시 나타나지 않음 |
| 짧은 단어와 긴 문장 검색의 점수 분포가 다름 | 질의 길이별 임계값, 벡터·Keyword·문자열·LLM 신호의 단계적 결합 | 장소 이름을 몰라도 당시 표현으로 찾되 관련도 낮은 결과를 억제 |
| 여러 탭이 Refresh Token을 동시에 회전 | Promise 공유, Web Locks, 재사용 감지 시 회원 세션 폐기 | 정상 사용자는 로그아웃되지 않고 탈취·재사용은 차단 |
| 서비스별 배포 버전과 GitOps 선언 불일치 | SHA 불변 이미지, 후보 검증, Argo CD 선언 상태 동기화 | 어떤 코드가 배포됐는지 추적하고 이전 버전으로 되돌리기 쉬움 |
| 익명 탐색에서 개인정보가 노출될 위험 | 공개 Keyword Preset, 타인 조회 전용 Projection, 내부 ID·Context 원문 제외 | 공개 Collection은 탐색할 수 있지만 작성자의 원문과 신원은 보호 |
flowchart LR
Login[소셜 로그인] --> Map[지도에서 장소 탐색]
Map --> Record[장소 + Context 기록]
Record -. async .-> Analyze[Embedding + Keyword 분석]
Analyze --> Search[자연어로 내 기록 검색]
Record --> Collection[기록을 Collection으로 구성]
Collection --> Feed[익명 발행·탐색]
Feed --> Follow[선반 팔로우]
가입·로그인, 장소 기록, Context 관리, AI 검색, 컬렉션 생성·편집, 피드·팔로우, 탈퇴까지의 예외 조건은 전체 유저플로우에 정리되어 있습니다.
| GitHub | 이름 | 역할 | 주요 작업 |
|---|---|---|---|
@minyongP |
박민용 | Backend / Data | Core 스키마와 Record·Context·Collection·Follow 도메인, 연쇄 삭제·동시성 제어, 지도·피드 조회 성능 개선, 대용량 데이터 벤치마크와 API 계약을 구현했습니다. |
@cherry-go-round |
홍석호 | Backend / Security | Google·Kakao·Naver OAuth, Cookie 기반 JWT·Refresh 회전, CSRF와 세션 재사용 방어, 회원 탈퇴 시 공급자 연결 해제 및 인증 장애 계약을 담당했습니다. |
@colosair |
이정헌 | AI / Search | Context 임베딩·Keyword 파이프라인, pgvector 개인 검색, 질의 재작성·Keyword 재정렬·문자열 RRF·LLM 관련도 판정, 로그 비식별화와 실측 게이트를 구현했습니다. |
@tpals0409 |
김세민 | Infra / DevOps | k3s·Argo CD GitOps, 불변 이미지 자동 배포, Sealed Secrets·NetworkPolicy·Pod Security, PostgreSQL 백업, Prometheus/Grafana/Loki 관측 체계를 구축했습니다. |
@ghkim1632 |
김가현 | AI Feature / Frontend | 이미지 업로드 기반 장소·맥락 제안 기능을 AI–Backend–Frontend 전 구간에 연결하고 검색 결합 신뢰도 게이트와 장소 기록 UI를 구현했습니다. |
@TrossYou |
유승주 | Frontend / UX | 지도·검색·피드·책장·컬렉션 화면과 서버 상태 계층을 구현하고 종이·책 메타포의 반응형 UI, 접근성, 폰트·이미지 성능과 상호작용 회귀를 개선했습니다. |
- 박민용: Core 도메인 기반, Record·Context API와 지도, 천만 건 벤치 환경, 피드 인덱스 사용 복원
- 홍석호: 소셜 로그인과 Cookie JWT, Kakao·Naver 로그인, Refresh 재사용 세션 폐기, 공급자 연결 해제 후 탈퇴
- 이정헌: 검색 3신호 고도화, LLM 관련도 4번째 신호, GMS 오류 로그 차단, 검색 결과 Backend 조립
- 김세민: 전체 시스템 아키텍처 문서화, Sealed Secrets 인증서 교체, PostgreSQL 자격정보 부트스트랩, Cloudflare Tunnel 복구
- 김가현: 이미지 기반 장소 제안 AI, Spring 중계 API, Frontend 기록 흐름, 검색 신뢰도 게이트
- 유승주: Home 지도·핀 시스템, 컬렉션 책 펼침면 UI, 검색 결과 카드, 검색 갤러리와 업로드 UI
각 구성요소는 독립 실행·배포 단위를 유지합니다. 환경변수의 실제 값은 저장소에 포함하지 않습니다.
# Backend: Java 21, Docker 필요
cd back
docker compose up -d
./gradlew bootRun
# Frontend: Node.js 22
cd front
npm ci
npm run dev
# AI: Python 3.12, Backend Flyway 완료 후 실행
cd ai
python3.12 -m venv .venv
python -m pip install -r requirements.lock -r requirements-dev.lock
uvicorn app.main:app --port 8000운영 배포 절차는 infra/README.md, 환경변수 이름과 테스트 명령은 각 하위 디렉터리의 README를 따릅니다.
back/, front/, ai/, infra/, specs/는 각 원본 저장소의 전체 Git 이력을 subtree 방식으로 보존합니다. 기능 개발과 이슈·PR은 기존 구성요소 저장소에서 확인할 수 있습니다.







