HWANG JUNHYEOK · PORTFOLIO 2026
PORTFOLIO
AI 작업의 범위와 완료 조건을 먼저 정하고, 결과는 코드 버전과 reviewer 승인에 묶어 확인한 뒤 완료로 봅니다.
CONTACT
WEB
GITHUB

안녕하세요
황준혁입니다.
HWANG JUNHYEOK · JUSTN
AX Engineer
학력
2024.03 - 2027.01
부산소프트웨어마이스터고 소프트웨어개발과 졸업 예정
자격
2025.07 정보처리산업기사
2026.03 SQL 개발자 (SQLD)
2026.04 리눅스마스터 2급
다루는 영역
AI-native 제품 개발
사용자 문제를 화면·API·AI 기능으로 구현하고, 실패와 검증 조건까지 제품에 연결합니다. 개발 과정에서도 agent가 반환한 코드와 실행 결과를 다시 확인합니다.
기반 역량 · Frontend
TypeScript·React·Next.js로 사용자 흐름을 구현합니다. 입력과 제출, 편집 상태와 복원이 일치하도록 조건을 정합니다.
목차
입력과 복구에서 AI 실행·검증까지 확장합니다.
01
AI 기능의 실행과 결과 검증
자갈치플랫폼의 실행 실패 처리와 코드 버전 재검증
02
개인 제품
라피 · stackot의 중복 방지와 재전송
03
조직 운영
제품 팀과 공개 프로젝트 조직의 서로 다른 책임
04
제품 구현의 기반
Maru의 입력 · 제출과 자갈치의 저장 · 복원
구조화·검증
01 자갈치플랫폼
AI 호출·작업 실행·제출 코드 상태를 검사와 사람 승인으로 확인합니다.
자갈치플랫폼
AI 학습 로드맵 서비스
자갈치플랫폼
개발자의 학습 목표·문서·질문을 받아 AI가 로드맵 생성, 문서 변환, 설명·추천·코칭을 해 주는 학습 서비스입니다. AI 기능마다 티켓 비용이 있어, 작업 전에 예약하고 실패하면 환불, 성공하면 확정합니다.

#개인 주도 제품 #AI 실행 검증
기간
2026.08 – 진행 중
GitHub
기여
01 Web·API·Infra 담당
02 AI 티켓 예약·환불·확정 경계 구현
03 closed alpha 직접 운영
기술
Next.js · NestJS · Django · PostgreSQL · GitHub App · Docker
자갈치플랫폼 · 결과 신뢰
제출한 코드가 바뀌면 이전 검증과 승인을 다시 받습니다
상황
검증과 별도 reviewer 승인이 끝난 PR에도 새 커밋이 push될 수 있습니다.
원인
승인이 코드 버전에 묶여 있지 않으면, 바뀐 코드가 이전 검증과 승인을 그대로 가져갑니다.
해결
완료 조건, GitHub 증거와 별도 reviewer 승인을 같은 PR head에 묶고, head가 바뀌면 이전 검증과 승인을 무효로 했습니다.
결과
2026-08-27 운영에서 PR head를 e5f8c58 → ce45ade로 바꾸자 webhook 직후 APPROVED → BOUND로 돌아갔고, 재검증·별도 reviewer 재승인 뒤에만 다시 APPROVED가 됐습니다(작성자 승인은 403).
jagalchi-platform #13 · closed alpha 증거 ↗
실제로 확인한 코드 버전 변화
A → B
새 커밋 뒤 상태 변화를 확인했습니다.
코드 버전 A
검증·승인 완료
↓
코드 버전 B
A의 검증·승인 무효
↓
같은 버전 B
재검증·재승인 완료
검증과 승인은 같은 코드 버전에만 유효합니다
버전 B 재검증·재승인 완료
자갈치플랫폼 · 운영과 복구
API 재기동 46초, 이전 버전 복귀 45초를 확인했습니다
closed alpha 운영 환경에서 재기동·rollback·DB 복원을 직접 실행했습니다. stop→start 46초 안에 readiness 200 · rollback 45초 / forward 35초 · DB 13개 테이블 행 수 일치.
jagalchi-infra · deploy/smoke.sh · self-hosted compose 점검
01 deadline=$((SECONDS + 300)) 02 while ((SECONDS < deadline)); do 03 health_endpoints_ready || continue 04 healthy=$(check_services api ai ai-db minio cloudflared) 05 ((healthy == 0)) && break 06 done 07 ((SECONDS >= deadline)) && exit 1 08 echo "production smoke check passed"
✓ compose로 띄운 서비스의 준비 상태 점검 스크립트
이 스크립트는 compose로 띄운 서비스의 준비 상태를 확인합니다. 재기동·rollback·DB 복원 시간은 closed alpha 운영 기록(#13)에서 측정했습니다.
jagalchi-platform #13 · closed alpha 증거 ↗
확인한 범위
재기동 46초 rollback 45초 forward 35초
개인 제품
01 라피
재시작해도, 겹쳐 돌아도 같은 기간의 브리핑은 한 번만
02 stackot
전달에 실패해도 잃지 않는 이벤트
라피
개인 에이전트
라피
여기저기 흩어진 소식을 모아 Discord와 이메일(SMTP)로 브리핑하고, 제가 승인한 일만 대신 하는 개인 에이전트입니다. 2026-09-28에 v0.1.2를 배포했습니다.

#개인 에이전트 #v0.1.2 배포
기간
2026.09 – 지금
GitHub
기여
01 RSS · GitHub · 웹훅 수집
02 Discord · 이메일(SMTP) 브리핑
03 공개 분석만 올리는 블로그
04 USER · ADMIN · SUPERADMIN 권한
05 승인한 작업만 실행
06 취소하면 프로세스 종료
기술
TypeScript · Node.js · PostgreSQL · Zod · MDX · Discord
라피 · 개인 에이전트 · v0.1.2 배포
같은 기간의 브리핑이 두 번 나가지 않게 했습니다
상황
여기저기 흩어진 소식을 모아 Discord와 이메일(SMTP)로 브리핑하는 개인 에이전트를 직접 만들었습니다. 스케줄러가 재시작되거나 겹쳐 돌 수 있습니다.
원인
"이 기간은 이미 만들었다"를 가릴 기준이 없으면, 재시작이나 동시 실행 때마다 같은 기간의 브리핑 묶음이 새로 생깁니다.
해결
(구독, 기간 시작, 기간 끝)이 같으면 묶음을 하나만 인정하도록 데이터베이스가 막고, 이미 있으면 그 묶음을 다시 씁니다.
결과
동시 요청 4건에도 묶음은 1개만 생깁니다. 이 동작을 담아 2026-09-28에 v0.1.2를 배포했습니다.
근거 · rapi-agent · postgres-store.ts ↗
같은 기간 · 같은 구독
묶음 1개
몇 번을 돌려도 결과가 같습니다.
스케줄러 실행
묶음 생성 → 브리핑 발송
재시작 후 실행
있던 묶음을 다시 씀
동시에 4번
묶음 1개만 생성
ON CONFLICT DO NOTHING → 있던 묶음 사용
같은 기간의 브리핑은 한 번만
stackot · GitHub → Discord 봇
Gateway가 잠깐 죽어도 이벤트를 잃지 않게 했습니다
상황
GitHub 이벤트를 받아 Discord 스레드로 이어 주는 봇입니다. 이벤트를 넘겨받는 OpenClaw Gateway가 잠깐 502를 낼 수 있습니다.
원인
웹훅에는 이미 성공으로 응답했기 때문에 GitHub는 다시 보내 주지 않고, 받자마자 보내고 끝내면 실패한 전달을 되살릴 곳이 없습니다.
해결
응답하기 전에 받은 이벤트를 outbox에 pending으로 적고, 실패하면 간격을 늘려 최대 5번 다시 보내고, 모두 실패하면 dead_letter로 남깁니다. 전달되면 sent로 바꾸고, 재시작하면 남은 pending부터 보냅니다.
결과
Gateway 502 뒤 보존과 재시작 후 재전달을 확인했습니다. 백업은 VACUUM INTO 스냅샷으로 바꿔 integrity_check를 통과합니다.
이벤트 한 건의 흐름
pending → sent
전달될 때까지 디스크에 남습니다.
웹훅 수신
응답 전에 outbox에 기록
↓
Gateway 502
간격을 늘려 다시 시도
↓
서버 재시작
남은 pending부터 재전송
SQLite WAL · synchronous=FULL
받은 이벤트는 사라지지 않습니다
조직 운영
01 stacking-money-forever
제품별 책임을 분리하고 자동화 개입 조건을 명시했습니다.
02 BSSM-OSS
프로젝트 선정·소개·문서·유지 기준
조직 운영 · stacking-money-forever
제품별 담당 범위와 공개 상태를 구분했습니다
자갈치플랫폼 Web·API·Infra와 벙개 프론트엔드·디자인을 맡았습니다.
제품별 책임 · 공개 범위
프로젝트
본인 기여
공개·개발 단계
자갈치플랫폼
Web·API·Infra
공개 저장소 · alpha
벙개
frontend · design
공개 저장소 · 2인 협업
Watchdog
프로세스 제어 전 대상 재확인
공개 v0.2.1
stackot
승인 기반 agent 작업
공개 저장소 · MVP
rapi-agent
승인 기반 Agent 설계
v0.1.2 배포

조직 체계 · BSSM-OSS
외부에서 찾고 기여할 수 있게 공개 기준을 정리했습니다
외부 사람이 프로젝트를 이해하고 실행·기여할 수 있도록 공개 기준을 정리했습니다.
대표 목록
대표 프로젝트를 첫 화면에서 바로 찾을 수 있게 정리했습니다.
README
조직 소개 README를 영/한으로 분리하고 분야별 카탈로그로 재구성했습니다.
기여 경로
조직 공통 Issue 양식 5종과 PR 양식을 만들었습니다.
유지 기준
운영 중인 저장소만 대표 목록에 올렸습니다.
조직 전체 공개 저장소 98개 · 2026.09.08

구현의 기반
01 Maru
사용자가 보는 입력과 실제 제출값의 일치
02 자갈치
함께 바뀐 편집 상태를 같은 시점으로 복원
부산소프트웨어마이스터고 입학 전형 서비스
Maru
입학전형 지원서에서 늦게 온 임시저장 응답이 사진 값을 덮어쓰던 race와 검정고시 원서 제출 400을 수정했습니다. 화면에 보이는 값과 전송 데이터가 어긋나는 두 문제입니다.

#입학 전형 서비스 #Frontend · DX
기간
2025.04 – 2026.03
GitHub
기여
01 사진 값 덮어쓰기 race 수정
02 검정고시 원서 제출 400 해결
기술
Next.js · React · TypeScript · Recoil · TanStack Query
Maru · 입학전형 지원서
사진을 올렸는데 다음 단계가 열리지 않았습니다
상황
증명사진을 올려 화면에 보이는데도 '다음' 단계 검증이 실패할 수 있었습니다.
원인
사진 값이 반영된 뒤 늦게 도착한 임시저장 응답이 사진 값을 빈 값으로 덮어썼습니다.
해결
다음 단계 버튼을 누른 시점의 이미지와 업로드 주소를 함께 읽어 진입 조건을 판단하도록 바꿨습니다.
결과
늦은 응답 순서에서 '다음' 막힘 100% → 0%, 무작위 순서 100회에서 21회 → 0회.
근거 · PR #268 · 사진 값 덮어쓰기 race ↗
다음 단계 검증 기준
2개 상태
보이는 이미지와 업로드 주소를 같은 시점에 확인합니다.
이미지 미리보기
READY
AND
업로드 URL
READY
두 값이 모두 준비되면
다음 단계 진입 조건 충족
구현 조건
image && (downloadUrl || uploadUrl)
Maru · 전형별 입력
검정고시 지원자의 원서 제출이 400으로 거절됐습니다
상황
검정고시를 선택하면 학교 입력 항목이 사라지는데, 제출하면 서버가 거절했습니다.
원인
숨긴 학교 칸이 빈 문자열로 전송돼 서버의 schoolCode 7자 검사에 걸렸습니다.
해결
제출 직전에 graduationType을 확인하고 학교 관련 7개 필드를 null로 만들었습니다.
결과
검정고시 지원서도 학교 정보 없이 정상 제출되고, 숨긴 학교 값 전송은 7개 → 0개가 됐습니다.
BEFORE · 화면만 변경
학교 정보는 숨겨졌지만
제출값에는 빈 값이 남았습니다.
서버는 빈 schoolCode를 400으로 거절했습니다.
AFTER · 제출값도 변경
지원 유형을 다시 확인하고
학교 관련 7개 값을 비웠습니다.
검정고시 전형에서는 학교 관련 값을 비웁니다.
결과
보이는 조건과 보내는 조건을 하나의 기준으로 맞췄습니다.

개발자 학습 경로를 만드는 노드 편집기
자갈치
노드와 선으로 학습 경로를 만들고 공유하는 6인 팀 프로젝트입니다. 학습 경로 편집기의 상태·저장·복구 구현을 맡았습니다.

#Team Lead · Frontend Lead · PM
기간
2025.12 – 2026.05
GitHub
기여
01 변경 빈도와 역할에 따른 상태 분리
02 노드·선의 통합 실행 취소와 복원
03 실행 취소 깨짐 59.9% → 0%
04 손상 항목만 제외하는 부분 복구
05 복사한 노드의 ID와 연결 관계 갱신
기술
Next.js · React · TypeScript · Jotai · React Flow
자갈치 · 로드맵 저장
자동 저장 한 번에 다른 로드맵이 지워졌습니다
상황
텍스트 상자나 섹션이 든 로드맵이 하나라도 있으면, 자동 저장할 때 저장돼 있던 다른 로드맵이 사라졌습니다.
원인
저장할 때마다 목록 전체를 한 번에 검사했고, 이름 칸이 없는 게 정상인 텍스트 상자·섹션이 규칙 위반으로 걸렸습니다. 검사에 실패하면 목록을 빈 것으로 보고 덮어썼습니다.
해결
로드맵을 하나씩 검사해 깨진 것만 건너뛰고, 텍스트 상자·섹션은 label 없이도 통과하게 규칙을 바로잡았습니다.
결과
저장할 때 다른 로드맵이 사라지는 비율 100% → 0% (무작위 저장 1,000회).
BEFORE · 목록 전체 검사
하나라도 검사에 걸리면
목록 전체를 버렸습니다.
지금 로드맵 하나만 남기고 덮어썼습니다.
AFTER · 로드맵마다 검사
깨진 항목만 건너뛰고
나머지는 그대로 남깁니다.
텍스트 상자·섹션은 이름 없이도 통과합니다.
결과
다른 로드맵 손실 100% → 0% (1,000회)
황준혁