2 분 소요

왜 만들었나

개인 공부용으로 시작한 토이 프로젝트다. 목표는 두 가지 관계(부모-자식, 배우자)만 저장해두고, 형제자매/사촌/조상/자손/친족 호칭 같은 나머지는 전부 그래프 탐색으로 계산해서 도출하는 것. 그리고 그 결과물을 실제로 배포까지 해보면서 프론트엔드 따로, 백엔드 따로 배포하는 흐름을 익히는 것이 두 번째 목표였다.

추가로 코드를 하나도 모른 상태에서도 프로그램을 이렇게 만들 수 있는지 확인용으로 만들었다.

기술 스택

backend/   FastAPI + SQLAlchemy (로컬은 SQLite, 배포는 Supabase Postgres)
frontend/  React + TypeScript + Tailwind + React Flow(+dagre 자동 레이아웃)

만든 순서대로 정리

1. 기본 뼈대: FastAPI 백엔드 + React/Vite 프론트엔드

Person(사람)과 Relationship(부모-자식, 배우자) 두 테이블만 두고, React Flow로 자동 레이아웃되는 그래프를 그렸다. dagre가 노드 배치를 계산해주기 때문에 트리 레이아웃을 직접 짤 필요가 없었다.

2. 얼굴 사진 업로드

사람 추가 폼에서 jpg/png/webp/gif(5MB 이하) 파일을 선택하면 POST /upload/photo로 업로드하고, 반환된 URL을 photo_url로 저장하도록 했다.

3. 로그인 없이 가족관계도 분리하기

회원가입 없이도 사용자마다 다른 데이터를 보게 하려고, 브라우저 첫 접속 시 localStorage에 임의 ID를 발급하고 모든 API 요청에 X-Owner-Id 헤더로 실어보냈다. 당연히 진짜 인증은 아니고, ID 값만 알면 누구나 접근 가능한 수준의 “느슨한 구분”이다. 다른 사람에게 ID를 공유하면 같은 가족관계도를 같이 볼 수도 있다.

4. 배포: Render + Supabase + GitHub Pages

계획한 조합은 백엔드는 Render, DB는 Supabase(Postgres), 프론트엔드는 GitHub Pages였다. 과정에서 두 가지 문제를 만났다.

  • Python 버전 문제: Render가 기본으로 최신 Python(3.14)을 쓰다 보니 pydantic-core의 사전 빌드된 wheel이 없어서 Rust로 직접 컴파일을 시도했는데, Render의 읽기 전용 빌드 환경에서 실패했다. backend/runtime.txt로 Python 3.12.7을 고정해서 해결.
  • DB 드라이버 누락: SQLAlchemy에 DATABASE_URL만 Postgres로 바꿔준다고 드라이버까지 자동으로 설치되는 게 아니라서, psycopg2-binaryrequirements.txt에 추가해야 했다.

프론트엔드는 GitHub Actions 워크플로(.github/workflows/deploy-frontend.yml)를 만들어 master에 push되면 자동 빌드 후 GitHub Pages(공식 actions/deploy-pages)로 배포되게 했다. 이때 GitHub Pages는 프로젝트 페이지라 /FamilyRelationshipDiagram/ 같은 하위 경로에서 서빙되는데, 로컬 dev 서버는 여전히 /를 써야 하므로 vite.config.ts에서 빌드 명령일 때만 base를 바꾸도록 분기했다.

Jekyll GitHub Pages는 GitHub이 빌드까지 대신 해주지만, Vite 같은 SPA는 빌드 결과물을 직접(혹은 Actions로) 만들어서 올려야 한다는 차이가 있다 — 이 부분은 docs/DEPLOYMENT.md에 따로 정리해뒀다.

5. 가족 호칭 자동 계산 (혈족, 4촌까지)

이번 프로젝트에서 가장 재미있었던 부분. FamilyGraph.kinship_term()이 두 사람의 공통 조상까지 각자 몇 단계 떨어져 있는지(up, down) 를 구하고, 그 조합으로 호칭을 판정한다.

  • (1, 1) → 형제/자매
  • (2, 1) → 삼촌/고모 계열
  • (2, 2) → 사촌

여기에 부모 성별(친가/외가 구분)과 생년월일 비교(형/오빠/누나/언니, 큰아버지/작은아버지 구분)까지 더해서 실제 한국어 호칭에 가깝게 계산되도록 했다. 인척(처가/시댁 쪽)은 이번 범위에서는 제외했다.

프론트엔드에는 “이 사람을 나로 보기” 버튼을 추가해서, 기준 인물(ego)을 지정하면 그래프의 각 이름 아래에 그 사람 기준 호칭이 바로 표시되게 했다.

결과물 링크

https://leejeunghun.github.io/FamilyRelationshipDiagram/

배운 것

  • 관계형 데이터를 전부 저장하지 않고 최소 관계(부모-자식, 배우자)만 저장한 뒤 그래프 순회로 나머지를 계산하는 설계가 데이터 정합성 관리에 훨씬 유리하다는 걸 체감했다.
  • 정적 사이트(Jekyll)와 SPA 빌드(Vite/React)의 GitHub Pages 배포 방식이 근본적으로 다르다는 것 — 전자는 GitHub이 빌드를 대신 해주고, 후자는 빌드 산출물을 직접 올려야 한다.
  • PaaS(Render) 배포에서는 런타임 버전 고정과 DB 드라이버 의존성처럼, 로컬에서는 안 보이던 문제가 배포 환경 차이에서 튀어나온다는 것.
  • 코드 하나도 몰라도 엄청 따르게 만든는게 개인적으로 개발자의 위기감이 들어온다.

다음에 할 일

  • 인척(처가/시댁) 호칭까지 확장
  • 5촌 이상 원거리 친족 호칭 지원 여부 검토
  • 실제 로그인/인증 붙이기 (지금은 브라우저별 임의 ID 수준)

댓글남기기