- 발행일
교통 데이터 플랫폼 프론트엔드·백엔드 2025 ~ 현재 경력 기술서
한눈에 보기
| 항목 | 내용 |
|---|---|
| 도메인 | 교통 분야 국제 표준 — 데이터 사전·차량 통신 메시지 규격 |
| 기간 | 2025.04 – 현재 (진행 중) |
| 역할 | 프런트엔드에서 백엔드까지 |
| 기술 스택 | Django 4.2, PostgreSQL(운영)·SQLite(개발), django-treebeard, Jinja 템플릿, JavaScript, jQuery, D3.js, jsTree, Tailwind CSS(v3→v4), Playwright, GitLab |
| 담당 영역 | 등록 신청, 트리 구조, 설문조사, 시각화, QA 자동화 |
화면을 만들던 사람이 모델과 쿼리까지 맡게 된 기록입니다. 재학 시절 파이썬으로 웹을 만들어 본 경험을 살려, 지금은 신청서 화면부터 승인 시점의 데이터 생성, 설문 모델 설계까지 한 기능을 앞뒤로 끝까지 맡고 있습니다. 데이터 지식이 필수인 도메인이라 처음엔 낯설었지만, 하나씩 풀다 보니 사용자가 어디서 막히는지가 보였고 그 지점을 고치는 데 집중했습니다.
1. 등록 신청
표준데이터·OID 등록 신청을 화면부터 데이터 생성까지 맡았습니다. 신청하는 순간 데이터를 만들면 반려된 신청의 흔적이 목록에 남기 때문에, 신청 내용을 JSON 초안 하나에 담아 두고 승인될 때 하위 항목부터 순서대로 만들도록 설계했습니다. 그러다 초안이 PostgreSQL 색인 크기 제한(2,704바이트)에 걸려 저장이 통째로 실패했고, 초안 행만 색인에서 빼는 부분 색인으로 풀었습니다.
화면 쪽에서는 신청서 항목 모달이 한 번 열 때마다 후보 조회를 20번 보내던 것을 2번으로 줄였고, 제출 조건을 "세 항목 중 하나만 있으면"으로 풀었습니다.
- 신청 내용은 초안으로 두고 승인할 때 만들기2026-08-25승인될 때까지 아무것도 만들지 않기 — 신청서 작성분을 초안으로 두고 승인 때 재생하기신청서에서 엘리먼트·프레임·메시지를 직접 쓸 수 있게 했는데, 신청 시점에 만들어 버리면 반려된 신청의 찌꺼기가 목록에 남습니다. 작성분을 JSON 초안 한 칸에 두고 승인 시점에 자식부터 순서대로 재생하게 했어요. 그러다 초안 JSON이 PostgreSQL btree 색인 상한 2704바이트에 걸려 INSERT가 통째로 실패했습니다.
- 신청서 모달의 후보 조회를 20번에서 2번으로 줄인 방법2026-09-02신청서 항목 모달에서 후보 조회 20회를 2회로 줄였다 — 체크박스 2,178개와 숨은 탭의 required등록 신청서의 항목 모달이 화면 4.1개 길이였습니다. 재 보니 67%가 체크박스 상자였고, 한 번 여는 데 체크박스 2,178개를 그리고 후보 조회가 20번 나갔어요. 후보가 많은 슬롯만 접힌 검색칸으로 바꾸고, 접힌 슬롯은 펼칠 때 조회하게 해서 2회로 줄였습니다.
- 제출 조건을 "셋 중 하나만 있으면"으로 바꾼 일2026-09-09신청 항목 셋 중 한 건이면 제출 — 조건이 단계를 가로지르면 안내도 단계 밖에 둔다표준데이터 신청서는 메시지 한 건을 반드시 써야 제출됐습니다. 엘리먼트만, 프레임만 내는 신청도 있어서 조건을 "셋 중 최소 한 건"으로 풀었어요. 판정은 팀원이 한 입구로 묶어 둔 함수 안의 조건만 바꾸면 됐는데, 정작 어려웠던 건 안내를 어디에 두느냐였습니다. 조건이 세 단계를 가로지르는데 안내는 한 단계 조각 안에 있어서 다른 단계에서 항목을 넣어도 낡은 채 남았거든요. 그리고 같은 규칙을 말하는 자리가 네 곳이었는데, 한 곳이 75분 늦게 따라왔습니다.
- 기록부터 배포까지, 신청 상태 7단계 설계2026-04-07ISO 14817-2 기반 7단계 워크플로우 — 기록부터 배포까지 상태 설계교통 데이터 플랫폼에 ISO 14817-2의 데이터 개념 라이프사이클을 적용해 기록→제출→사전검증→검증→사전인증→인증→배포의 7단계 상태 머신을 구성한 과정을 정리합니다.
2. 트리 구조
분류체계·메타클래스·OID가 전부 계층 데이터라, 저장·조회·화면 세 층을 함께 다뤘습니다. 도메인마다 따로 있던 트리 로직을 공통 헬퍼로 뽑았고, 번호로 갈라지는 OID 트리는 세로 목록 대신 가로 조직도로 다시 그렸습니다.
- 두 트리에 겹쳐 있던 서버 로직을 헬퍼로 묶은 기록2026-05-16분류체계와 메타클래스 트리 공통 로직을 헬퍼 4종으로 추출한 회고두 페이지가 따로 들고 있던 jstree 옵션과 이벤트 핸들러를 비교해 차이가 거의 없음을 확인하고, 공통 헬퍼 4종으로 추출한 리팩토링 회고입니다.
- OID 트리를 세로 목록에서 가로 조직도로 바꾼 이유2026-08-12OID 트리를 jsTree에서 조직도로 갈아탔다 — 네 화면 중 두 곳만OID는 번호로 갈라지는 계층인데 세로 목록 트리로는 형제 순서도 계층 폭도 안 읽혔습니다. d3.hierarchy로 가로 조직도를 새로 그렸는데, 네 화면 중 두 곳만 바꿨어요 — 경로 바가 있느냐로 갈랐습니다. 그리고 나서 트리 전체를 다 그리다 SVG가 12,691px가 됐습니다.
- 드릴다운을 뺐다가 같은 날 밤에 되살린 일2026-09-04OID 트리를 낮에 고정하고 밤에 되돌렸다 — 일곱 시간짜리 결정과 서버가 정하게 된 버킷OID 조직도의 드릴다운을 오후 2시에 걷어냈고 밤 9시 45분에 되살렸습니다. 잎을 트리 밖 카드 목록으로 내보낸 뒤 계층이 한 화면에 다 들어오니 드릴다운이 필요 없어 보였는데, 운영 데이터의 표준 가지 아래로 내려갈 길이 통째로 사라졌어요. 되돌리면서 "어느 노드가 카드 버킷인가"를 화면의 추론에서 서버 플래그로 옮겼습니다.
3. QA 자동화
사람이 눈으로 돌던 QA를 코드로 옮겼습니다. 기능목록 엑셀을 기준으로 메뉴 136종을 전부 열어 보는 Playwright 스윕을 만들었고, 오래 쌓여 있던 e2e 실패 25건을 원인별로 갈라 시나리오 274건을 실패 0으로 만들었습니다.
- 메뉴 136개를 Playwright로 한 번에 점검하기2026-07-20기능목록 엑셀을 테스트로 돌렸다 — 메뉴 136종 QA 스윕납품 문서의 기능목록 엑셀을 JSON으로 뽑아 메뉴 136종을 전부 열어보는 Playwright 스윕을 만들었습니다. 설정을 용도별 3종으로 나눈 이유, SQLite 때문에 워커를 1로 고정한 이유, 그리고 확인 못 한 항목을 스킵으로 남겨둔 게 옳은 선택이었는지까지 적었습니다.
- 실패로 남아 있던 e2e 25건, 진짜 버그는 1건이었다2026-09-03빨갛게 남아 있던 e2e 25건 중 코드 회귀는 1건이었다 — 낡은 계약·조용한 skip·잔재를 가르기Playwright 전체 스위트가 235 통과 · 25 실패 · 11 skip인 채로 한동안 있었습니다. 25건을 하나씩 열어 갈라 보니 코드 회귀 1 · 데이터 없음 4 · 나머지는 화면과 데이터를 못 따라간 낡은 스펙이었어요. 빨간불이 오래 쌓이면 진짜 회귀가 그 안에 묻힙니다. 같은 날 선택자가 사라져 영영 건너뛰던 스펙, 저장한 뒤에 건너뛰어 데이터를 남기던 스펙도 함께 고쳐, 다시 돌린 274건이 실패 0으로 끝났습니다.
4. 설문조사
공통 앱에 섞여 있던 설문 로직을 독립 앱으로 떼어 내고, 템플릿 → 섹션 → 질문 3단 구조의 모델 7개로 다시 설계했습니다. 소프트 삭제, 점수 자동 계산, 낮은 점수일 때 사유 필수 입력 같은 운영 규칙을 모델에 넣었고, 대상자 임시 계정 발급과 안내 메일 발송은 관리 명령으로 자동화했습니다.
- 설문조사 기능을 처음부터 다시 설계한 기록2026-02-15Django로 설문조사 시스템 처음부터 만들기 — 3-tier 재설계와 PDF 다운로드common 앱에 섞여 있던 설문조사 모델을 독립 앱으로 분리하고 3-tier 아키텍처로 재설계한 과정, 그리고 weasyprint 기반 PDF 다운로드와 개인정보 마스킹 구현을 정리합니다.
5. 시각화
서버에서 이미지로 굽던 트리를 D3 인터랙티브 트리로 바꿔 확대하고 탐색할 수 있게 했습니다. 화면마다 복제되던 줌 컨트롤은 공용 모듈로 뺐습니다.
- 이미지로 굽던 트리를 D3로 다시 그린 일2026-04-19ASN.1 트리 렌더링을 graphviz PNG에서 D3.js로 갈아탄 이유서버에서 graphviz로 PNG를 그려 내려주던 ASN.1 트리를 D3.js 기반 Collapsible Tree로 전환한 과정과 그 이유를 정리합니다. 서버 의존성 제거, 인터랙션, JSON 스키마 설계까지.
- 관계도를 따라 계속 탐색하게 하고, 겹치던 노드를 푼 일2026-07-23노드 두 개가 땅콩처럼 붙었다 — 연쇄 탐색 관계도와 forceCenter클래스 3개짜리 화면이 18개 노드로 그려지던 관계도를, 백엔드를 안 건드리고 중심 이동 탐색으로 바꿨습니다. 배치를 힘 시뮬레이션에서 고정 방사 좌표로 뺐더니 이번엔 노드 두 개가 땅콩처럼 붙었어요. 범인은 forceCenter였고, 고정 노드가 있는 그래프에서 왜 그게 겹침을 만드는지 정리했습니다.
- 화면마다 복사해 쓰던 줌 버튼을 하나로 합친 일2026-06-12여러 D3 그래프에 흩어진 줌 로직을 d3ZoomControls.js로 외부화한 회고데이터 관계도·워드클라우드·트리맵마다 복붙돼 있던 줌 설정을 공용 모듈 d3ZoomControls.js로 추출하고, 확대/축소/맞춤 버튼과 "최초 1회 fit-to-view"를 표준화한 작업입니다. SVG가 100% 크기일 때 뷰포트 크기를 어떻게 구하느냐가 핵심 함정이었어요.
참고 : 사이트 화면
