윤정현

    윤정현

    백엔드 · 풀스택 개발자

    경력
    4년 1개월 · 2022.04 – 2026.07
    주력
    Java · Spring Boot  /  PHP · Laravel
    Go · Node.js · Next.js · Flutter
    교육
    DBMS기반 빅데이터 응용 SW개발자 전문과정
    중앙정보처리학원 · 2018.08 – 2019.03
    이메일
    yjhzzzzdev@gmail.com
    GitHub
    github.com/yjh-dev
    • 개월총 경력 · 3개 회사
    • 개월Java · Spring Boot 백엔드 · 저장소 6개 · 52,146줄
    • %Laravel 본 서비스 커밋 기여 · 1,585 / 2,349
    • 0건레거시 이관 기간 중 서비스 중단
    • %신규 스택 커밋 · 1,755 / 1,772

    Career

    레거시에서 시작해 레거시를 옮기기까지

    • 2024.09 — 2026.07
      모바일파트너스
      책임연구원 · 1년 10개월 · 자체 솔루션

      모바일 앱 운영 B2B SaaS AppBox의 본 서비스를 Laravel 11로 1년 9개월간 개발·운영했습니다. 팀 전체 2,349커밋 중 1,585건이 제 커밋입니다. 이후 같은 시스템을 Next.js + Go 구조로 서비스 중단 없이 옮겼고, 새 구조는 제가 맡아 만들었습니다. GPS 실시간 채팅 돌콩의 채팅 서버와 백오피스도 혼자 만들었습니다.

    • 2025.03 — 2026.01
      프리랜스
      인슈플러스 · 플라잉닥터스 (재직 중 병행)

      전 소속사에서 담당하던 여행보험 B2C 서비스(PHP 레거시)를 위탁받아 혼자 유지보수했습니다. 요청 60건을 처리하며 ISMS-P 인증 요건을 운영 서버에 반영했고 — 개인정보 마스킹, 컬럼 암호화, 조회 통제, 동시접속 제한 — 결제·알림톡 장애와 AWS EC2 운영을 맡았습니다.

    • 2023.05 — 2024.05
      코드아이디어
      주임 · 1년 1개월 · SI

      Java · Spring Boot로 B2B 플랫폼 마켓해머의 백엔드를 담당했습니다. 1세대(Spring Boot 2.7 · Java 8)에서 기능을 만들다, 퇴사 전 2개월간 PC 백엔드·프론트를 Java 17 · Spring Boot 3로 다시 세웠습니다(231파일 · 첫 커밋부터 제가 작성). 여행보험 PG 결제 모듈 교체와 Laravel 10 고객사 웹 2건도 맡았습니다.

    • 2022.04 — 2023.05
      비젠소프트
      사원 · 1년 2개월 · 웹에이전시

      JSP · Spring과 PHP 레거시로 사내 ERP, 장비 예약, 전자계약 등 고객사 웹 서비스 6건을 개발했습니다. 남이 쓴 레거시 코드를 읽고 고치는 훈련을 이때 했습니다.

    01 — AppBox

    웹사이트를 앱으로
    만들고 운영합니다

    앱 빌드부터 푸시·인앱 메시지, 구독 결제까지 처리하는 B2B SaaS입니다. 기존 시스템은 팀으로 운영하고, 새 구조는 제가 맡아 만들었습니다.

    모바일파트너스 · 책임연구원 · 2024.09 – 2026.07

    01 / 04

    앱 빌드

    고객사 웹사이트를 클라우드에서 Android · iOS 앱으로 컴파일·패키징합니다. 빌드는 수 분이 걸려 웹 요청 안에서 처리할 수 없었습니다. 접수만 응답하고 실제 빌드는 큐로 넘겨 웹 응답 시간과 분리했습니다.

    앱 빌드 마법사 — OS 선택부터 디자인 설정까지

    02 / 04

    푸시 메시지

    토큰 선택 · CSV 업로드 · 테스트 발송을 지원합니다. API는 요청을 대기열에 쌓아 두기만 하고, 실제 발송은 별도 서버의 프로그램이 하나씩 꺼내 처리합니다. 덕분에 외부 Push API를 붙일 때 발송 파이프라인은 한 줄도 고치지 않았습니다.

    발송 대상 지정과 미리보기

    03 / 04

    인앱 메시지

    위치 · 크기 · 딤 · 애니메이션을 설정하고 실시간으로 미리 봅니다. 캠페인 메타는 PostgreSQL, 콘텐츠는 MongoDB로 나눠 저장합니다 — 집계·정합성은 관계형이 유리하고, 자유로운 콘텐츠 구조는 스키마리스가 유리하기 때문입니다.

    프레임 설정과 실시간 미리보기

    04 / 04

    사용자 여정 · 토큰 적재

    SDK가 수집한 디바이스 토큰을 적재·갱신하고, 발송 대상 산출의 기준으로 씁니다. 여정 인스턴스는 유저가 아니라 디바이스 단위로 잡았습니다 — 한 사람이 기기를 여러 대 쓰면 발송 대상이 달라지기 때문입니다.

    사용자 여정 캔버스 — 진입 · 대기 · 발송 노드

    운영 백오피스

    고객사·발송·빌드를 한자리에서 관제합니다

    푸시 발송 상세
    클라우드 빌드 내역

    고객사명 · 담당자 정보 · 접속 IP는 마스킹 처리했습니다.

    본 서비스 — Laravel 11 · 1년 9개월

    “레거시”라고 불렀지만
    매일 돌아가던 제품이었습니다

    이관 이야기를 하기 전에 — 저는 이 Laravel 시스템을 1년 9개월 동안 계속 만져 온 사람입니다. 고객사가 매일 쓰는 기능이 전부 여기 있었고, 신규 구조는 이 코드를 충분히 안 뒤에야 그릴 수 있었습니다.

    • 1,585본인 커밋 · 팀 전체 2,349건 중 67%
    • 24,656제가 맡아 운영한 애플리케이션 코드 줄 수
    • 1년 9개월2024.10 – 2026.06 연속 커밋
    Laravel 11 · PHP 8.2
    컨트롤러 49 · 서비스 13 · 미들웨어 13 · 마이그레이션 31 · 라우트 229 · Blade 뷰 126
    아티즌 커맨드 34
    빌드·발송·정산 배치를 스케줄러가 부르는 커맨드로 떼어냈습니다 — 웹 요청과 배치가 같은 실행 경로를 쓰지 않게 한 자리입니다
    이관과의 관계
    Next.js·Go 구조는 이 코드를 버리고 다시 쓴 게 아니라 여기서 알아낸 도메인을 옮긴 것입니다. 구독 게이팅·인증 회귀 2건을 운영 반영 전에 잡을 수 있던 것도 원본을 알고 있었기 때문입니다

    레거시 무중단 점진 이관

    한 번에 바꾸면
    실패가 곧 장애가 됩니다

    저장소를 성격으로 나눴다

    관계·정합성은 PostgreSQL, 디바이스·이벤트처럼 쓰기가 많고 스키마가 흔들리는 것은 MongoDB로 옮겼습니다. Redis는 캐시와 큐를 별도 인스턴스로 갈랐습니다 — 큐가 캐시 eviction에 쓸려가면 발송이 그대로 증발하기 때문입니다.

    접수와 발송을 떼어냈다

    API는 요청을 대기열에 쌓아 두기만 하고, 별도 서버의 프로그램이 하나씩 꺼내 발송합니다. 대기열 전용 제품(Kafka·RabbitMQ) 대신 Redis를 쓴 건, 이미 캐시로 쓰고 있어 운영할 서버를 늘리지 않기 위해서였습니다.

    포기한 것

    전면 재작성을 포기하고, 대신 두 시스템을 한동안 동시에 유지하는 비용을 받아들였습니다. 정기결제 스케줄러도 Go로 옮기지 않고 Console에 남겼습니다 — 결제 로직이 전부 TS에 있어 이중 유지보수가 생길 자리였습니다.

    이관 결과

    • 0건이관 기간 중 서비스 중단
    • 운영 반영 전 발견·복원한 기능 회귀
    • 수정 없이 확장기존 파이프라인 그대로 Push API 대응

    회귀 2건은 이런 것이었습니다 — 구독을 정지시킨 앱에도 인앱 메시지가 계속 노출됐고(구버전에 있던 게이팅이 신버전에서 누락), 브라우저 대응으로 인증을 뺀 인앱 엔드포인트로는 타사 캠페인 열람과 통계 조작이 가능했습니다. 게이팅 복원 · 경로별 CORS 분기 · IP Rate limit(20rps)으로 막았습니다.


    web 서버 push 서버 콘솔 고객사 발송 요청 외부 Push API 나중에 붙인 경로 Go API 접수만 한다 Redis Stream queue 인스턴스 Go 워커 실제 발송 FCM · SMTP MongoDB 발송 이력 XADD consume
    접수(web)와 발송(push)이 서버까지 갈라져 있습니다. 대기열은 캐시와 다른 Redis에 둡니다 — 캐시는 자리가 부족하면 오래된 값을 스스로 지우기 때문에, 같은 곳에 두면 보내야 할 알림까지 함께 사라집니다. 나중에 외부 Push API를 붙일 때 발송 파이프라인은 한 줄도 고치지 않았습니다 — 접수 경로만 하나 늘었습니다.

    데이터 설계

    이미 결제한 달은 흔들리면 안 됩니다

    관리자 플랜 수정 plan_quotas 플랜의 정의 · PUSH 10만건/월 subscription_quotas 이번 기간에 실제로 받은 제공량 + used 수정 결제 시 1회 복사 이후 플랜을 고쳐도 여기엔 닿지 않는다
    제공량을 참조가 아니라 복사로 뒀습니다. 참조로 두면 관리자가 플랜을 수정하는 순간 이미 결제한 고객의 이번 달 잔여량이 소급 변동합니다. plan_name까지 복사해, 이력에서 “그때 무슨 플랜이었나”를 볼 수 있게 했습니다.

    차감은 원자적으로

    Console 스케줄러(TS)와 Go API가 같은 테이블에 동시 접근합니다. 읽고·계산하고·쓰면 경합에서 잔량이 마이너스로 갑니다.

    UPDATE billing.charge_balances SET remaining = remaining - :qty WHERE remaining >= :qty;

    두 지갑을 쓰는 순서

    월 제공량(subscription_quotas)을 먼저 쓰고 부족분만 크레딧(charge_balances)에서 뺍니다. 기간이 지나면 사라지는 것부터 쓰는 순서 — 고객에게 유리한 쪽입니다.

    UNIQUE(app_id, balance_type)로 행 자체를 하나로 묶어 경합 지점을 좁혔습니다.

    정리 못 한 부채

    journey_instances정의가 PostgreSQL에 남아 있는데 실제 읽기·쓰기는 MongoDB에서 일어납니다. 디바이스 단위 고쓰기라 Mongo가 맞고, 초기에 PG로 설계했다가 옮기면서 PG 정의를 지우지 않았습니다. 발견했고 정리 대상으로 보고 있습니다 — 숨기면 저장소에서 바로 걸리는 종류입니다.

    규모
    PostgreSQL 9스키마 81테이블 — core · billing · messaging · build · cms · mailing · support · backoffice · audit / MongoDB 22컬렉션 / Redis 4인스턴스

    스키마 지도 — 도메인 경계를 스키마로 갈랐습니다

    cms 16 core 15 billing 15 messaging 12 support 6 backoffice 6 mailing 4 build 4 audit 2
    9개 스키마 · 81개 테이블. 도메인마다 스키마를 갈라 둔 덕에 이관을 한 스키마씩 끊어서 할 수 있었습니다. core가 허브고 — apps 테이블을 중심으로 나머지 스키마가 이 앱을 참조합니다.

    서비스 구성 — 저장소 6개를 서버 3대에

    web · 107
    console 고객 콘솔 (Next.js 16) · backoffice 운영 (Next.js) · api SDK·콜백·스케줄러 (Go/Echo) · landing 레거시 본 서비스 (Laravel 11) · demo 가상 고객사
    push · 103
    push 발송 워커 (Go) — Redis Stream 을 소비해 FCM·SMTP 로 보냅니다. 접수와 물리적으로 분리한 자리입니다
    db · 106
    PostgreSQL · MongoDB · Redis 4인스턴스 (dev·prod × cache·queue)
    환경 분리
    같은 서버 안에서 dev·prod 를 포트와 systemd 유닛으로 가릅니다. 설정은 _infra/ 에 저장소로 관리합니다

    02 — 마켓해머

    웹과 앱이 같은 API를
    부르게 만들었습니다

    기업 간 B2B 플랫폼의 Java · Spring Boot 백엔드입니다. 운영 중인 1세대 시스템에서 기능을 만들다, 마지막에는 같은 서비스를 Java 17 · Spring Boot 3 구조로 다시 세웠습니다.

    코드아이디어 · 주임 · 2023.05 – 2024.05

    재구축 — 한 덩어리를 넷으로 갈랐습니다

    v1 — Spring Boot 2.7 · Java 8 화면 · API · 배치가 한 앱 Thymeleaf + REST + Quartz 데이터 접근 3종 혼재 JPA · JDBC · MyBatis 세션 인증 · 엔드포인트 567 다시 세움 v2 — Spring Boot 3.0 · Java 17 PC 화면 서버 Thymeleaf 전용 모바일 화면 서버 Thymeleaf 전용 PC API REST · MyBatis · 엔드포인트 154 모바일 API REST · MyBatis · 엔드포인트 66 Spring Security + JWT 두 API가 같은 인증을 공유합니다
    v1은 화면·API·배치가 한 애플리케이션에 있었고, 데이터 접근이 JPA·JDBC·MyBatis 세 갈래로 갈려 있었습니다. 같은 테이블을 세 방식으로 읽으니 고칠 때마다 어디를 건드려야 하는지부터 찾아야 했습니다. v2에서는 화면 서버와 API 서버를 갈라 PC·모바일이 각자 배포되게 하고, 데이터 접근을 MyBatis 하나로 단일화했으며, 세션 인증을 Spring Security + JWT로 바꿨습니다.

    규모와 기여

    • 6Spring Boot 저장소 · Java 569파일 52,146줄
    • 787매핑된 엔드포인트 · 컨트롤러 68 · MyBatis 매퍼 55
    • 5주PC v2 백엔드·프론트 — 첫 커밋부터 제가 작성

    기여를 나눠서 말하면 이렇습니다 — v1(2023.05–2024.04)에서는 147커밋으로 팀의 한 명이었고, 모바일 v2는 절반(백 58/120 · 프론트 70/149)이었으며, PC v2는 2024.04 첫 커밋부터 2024.05까지 5주간 제가 작성했습니다(백 231파일 10,835줄 · 프론트 18파일). 어디까지가 팀이고 어디부터가 저인지 저장소로 확인할 수 있습니다.


    맡은 기능
    웹·앱 공용 RESTful API 설계 · 기업 간 채팅과 푸시 알림 · 기업별 구독 플랜과 구독 상태 관리 · Quartz 배치 · Flutter WebView 앱 패킹
    다음으로 이어진 것
    여기서 만든 구독·결제 상태 관리가 AppBox 구독 게이팅 설계로 이어졌습니다 — 이관 중 발견한 회귀 2건 중 하나가 정확히 그 게이팅이었습니다

    03 — 돌콩

    반경 5km,
    지금 여기의 대화

    GPS 기반 실시간 위치 채팅 서비스입니다. 핵심 문제는 프로세스를 여러 개로 늘려도 같은 이벤트를 모두에게 전달하는 것이었습니다.

    모바일파트너스 · 2026.03 – 2026.07 · 채팅 서버와 운영 백오피스 구축

    01 / 03

    클러스터 실시간 동기화

    Socket.IO 서버를 PM2 클러스터로 확장하고 Redis Adapter로 프로세스 간 이벤트를 동기화했습니다. JWT 소켓 미들웨어로 연결 단계에서 인증합니다.

    API 문서 — 엔드포인트와 WebSocket 이벤트 규격

    02 / 03

    위치가 곧 채팅방

    MongoDB의 위치 검색 인덱스로 반경 5km 안의 채팅방을 찾고, 메시지는 마지막으로 읽은 지점부터 거슬러 올라가며 나눠 불러옵니다.

    운영 백오피스 — 닉네임 · 이메일 · Provider ID 마스킹

    03 / 03

    안전한 운영 체계

    같은 방에서 3회 신고되면 자동으로 내보내고 영구 차단합니다. 백오피스에서 내린 조치는 Redis를 거쳐 채팅 서버에 곧바로 전달됩니다.

    설계 기준
    반경 5km · 방 24h / 메시지 7d TTL · 동일 방 신고 3회 자동 차단 · FCM 3초 스로틀
    채팅방
    신고 · 차단

    돌콩 · 앱 화면

    지도 — 반경 안의 방
    채팅 목록
    채팅방
    신고 · 차단
    기술
    Node.js · Socket.IO · Redis · MongoDB · Next.js

    데이터 모델 — 인덱스가 곧 기능입니다

    User fcmToken (sparse) ChatRoom location 2dsphere · 반경 5km expiresAt TTL · 24시간 Message {room, createdAt:-1} 커서 expiresAt TTL · 7일 Report {reporter, reportedUser, reportedRoom} → 같은 방 3회면 자동 강퇴 Block blocker · blocked 모두 User Terms · 약관 버전 관리 creator · participants sender room
    컬렉션은 6개뿐이고, 기능은 대부분 인덱스가 만듭니다. 반경 검색은 2dsphere, 방 24시간·메시지 7일 정리는 expiresAt TTL(expireAfterSeconds:0)이 대신합니다 — 삭제 배치가 없습니다. 대용량 메시지 조회는 {room, createdAt:-1} 복합 인덱스 위에서 커서로 거슬러 올라갑니다.
    왜 TTL 인가
    지워야 할 것을 애플리케이션이 기억하지 않아도 되게 만들었습니다. 배치가 죽어도 데이터는 제때 사라집니다
    왜 sparse 인가
    푸시를 끈 사용자는 fcmToken 이 없습니다. 없는 값을 인덱스에서 빼 발송 대상 조회만 빠르게 했습니다

    프리랜스 · 여행보험 B2C

    개인정보를 다루는 화면은
    기능보다 통제가 먼저입니다

    전 소속사에서 담당하던 서비스를 퇴사 후 위탁받아 11개월간 혼자 유지보수하며, ISMS-P 인증 요건을 운영 서버에 반영했습니다.

    노출 통제

    이름 · 주민번호 뒷자리 · 휴대전화를 출력 단계에서 마스킹하고, 복사 · 드래그를 차단했습니다. 검색 조건 없는 전체 조회를 막고, 쓰지 않는 관리자 게시판은 접근 자체를 닫았습니다.

    저장 · 반출 통제

    단체 가입 저장 시 개인정보 컬럼이 암호화되지 않던 결함을 찾아 고치고, 암호화 키를 환경별 설정으로 분리했습니다. 개인정보가 든 엑셀 · CSV 반출에는 암호화를 걸었습니다.

    접근 통제

    관리자 동시접속을 제한해 다른 브라우저로 로그인하면 기존 세션이 끊기게 했고, 접속 IP를 등록해 관리하도록 했습니다.

    그 외
    이니시스 · 토스페이먼츠 결제 전환, 가상계좌 자동전환 · 카드 취소 오류, 카카오 알림톡 발송 장애, 제휴사 전용 가입 페이지 3종, AWS EC2 운영 · SSL 갱신
    규모
    2025.03 – 2026.01 · 11개월 · 유지보수 요청 60건 처리 · PHP 레거시

    04 — 투인원

    기획부터 운영까지,
    두 스토어에 올렸습니다

    커플 미디어 앱입니다. App Store와 Google Play에 출시해 운영 중이며, 앱(Flutter)과 서버(NestJS), 인프라까지 전 과정을 혼자 담당했습니다.

    개인 프로젝트 · 1인 개발 · 5개 배포 단위 · Flutter + NestJS · AWS EC2 · Cloudflare R2

    투인원 · 앱 화면

    초대
    수락
    연결 완료
    공유 캘린더

    직접 부딪힌 문제

    혼자 만들면 어느 층위든 내가 고쳐야 합니다

    층위를 고르는 문제 해결

    "한 사람은 한 커플에만 속한다"를 앱 코드에서 검사했더니, 두 요청이 동시에 들어올 때 규칙이 깨졌습니다. 코드를 더 조이는 대신 데이터베이스가 두 번째 저장을 직접 거절하도록 조건을 걸었습니다. 문제를 어느 층위에서 풀지 고르는 것이 절반입니다.

    릴리스에서만 터지는 크래시

    디버그는 멀쩡한데 릴리스만 부팅 즉시 죽었습니다. 원인은 코드가 아니라 빌드 설정이었습니다 — 빌드 도구가 "쓰이지 않는다"고 판단해 지운 클래스를, 앱이 실행 중에 이름으로 찾고 있었습니다. 개발 환경의 초록불은 프로덕션을 보장하지 않습니다.

    중복 요청 제거

    로그인 만료 응답이 한꺼번에 오면 토큰 갱신 요청도 여러 번 나갑니다. 갱신할 때마다 이전 토큰이 무효가 되는 방식이라 먼저 받은 토큰이 곧바로 못 쓰게 되고, 이유 없는 로그아웃이 생겼습니다. 동시에 들어온 갱신 요청을 하나로 합쳐 처리하도록 고쳤습니다.

    기술
    Flutter · NestJS · PostgreSQL · Docker · AWS

    스키마 설계 — 제약은 나중에 못 붙입니다, 이미 깨진 데이터가 막습니다

    수락 요청 A 수락 요청 B 수락 핸들러 “이미 커플인가?” 검사 INSERT 성공 DB가 거절 — UNIQUE(user_id) WHERE is_active 둘 다 통과 검사한 순간과 저장하는 순간 사이에 틈이 있다
    앱 코드에서 검사했더니 동시에 들어온 두 요청이 모두 통과했습니다. 검사한 순간과 실제로 저장하는 순간 사이에 틈이 있기 때문입니다. 코드를 더 조이는 대신 데이터베이스가 두 번째 저장을 직접 거절하게 했고, 앱은 그 오류를 사용자 안내 문구로 바꿔 보여 주기만 합니다.

    제약에 담은 의도

    UNIQUE(user_id) WHERE is_active
    동시 수락으로 한 사람이 두 커플에 속하는 것 — 앱 코드로만 막으면 검사와 저장 사이의 틈으로 뚫립니다
    (ownerScope, ownerId, sourceHash)
    같은 사진 중복 업로드 — 재시도·네트워크 끊김에도 멱등하게
    (ownerScope, ownerId, authorId, date)
    작성자당 하루 1엔트리 — upsert 키로 그대로 씁니다
    (mediaId, userId, emoji)
    같은 이모지 중복 — 토글 구현이 자연히 따라옵니다

    데이터 모델 — 개인과 커플을 한 테이블에서

    혼자 쓸 때 ownerScope = user 커플이 된 뒤 ownerScope = couple 같은 테이블 media · diary_entries · events wish_items · wish_categories 제약도 그대로 (ownerScope, ownerId, …) 유니크 키에 소유자가 들어감 소유자만 바뀐다 — 테이블도 쿼리도 그대로
    솔로와 커플을 별도 테이블로 나누지 않았습니다. ownerScope(user | couple)와 ownerId 두 컬럼이 소유자를 표현하고, 유니크 제약도 이 두 컬럼을 앞에 둡니다. 커플이 되는 순간 데이터를 옮기는 대신 소유자를 바꿉니다 — 테이블을 나눴다면 여기서 마이그레이션이 필요했습니다.
    22 모델 · 5 배포 단위
    사용자·인증(User SocialIdentity AuthSession PushToken) / 관계(Couple CoupleMember Invite) / 콘텐츠(Media Reaction Comment DiaryEntry Event WishItem) / 기록(MoodLog HeartNote QuestionAnswer LoveLanguageResult) / 운영(AdminUser AuditLog CsInquiry)
    append-only 감사
    AuditLog 는 수정·삭제하지 않습니다. media.view 같은 행위별 조회 인덱스를 둬 관리자가 무엇을 봤는지까지 남깁니다

    05 — 윤사무실

    지어내지 않는 구조로
    에이전트를 관찰합니다

    AI 코딩 에이전트의 활동을 실시간으로 관제하는 데스크톱 앱입니다. 에이전트가 하는 일을 픽셀 사무실 화면에 공간으로 배치했습니다.

    개인 프로젝트 · Electron 33 · v0.21.0 · 런타임 의존성 0

    01 / 03

    지어내지 않는 구조

    CLI 출력을 파싱하는 대신 훅 이벤트를 구독합니다. 이벤트가 없으면 캐릭터가 움직일 근거가 없어 가짜 활동이 구조적으로 불가능합니다.

    기본 화면 — 에이전트의 활동이 곧 캐릭터의 움직임

    02 / 03

    테스트를 의심하는 절차

    검사를 만들 때마다 결함을 일부러 주입해 검출 여부를 확인했습니다. ‘초록불이지만 동작하지 않는’ 상태 4건을 발견해 수정했습니다.

    자동 검사 4종 실행 결과 — 로직 단언 710건 · 화면 갈래 57가지

    03 / 03

    되돌릴 수 있는 실행

    git plumbing으로 임시 저장소에 스냅샷을 만듭니다. 사용자의 git은 건드리지 않고, 스냅샷은 30개까지 보관합니다.

    스냅샷 되돌리기 — 사용자의 git은 건드리지 않습니다

    검증 결과

    • 36.8%검사 코드 비중 — 6,776 / 18,433줄
    • 로직 단언 — 43초 내 실행
    • 결함 주입으로 찾아낸 거짓 검사
    • 0런타임 의존성

    스스로 지운 것

    정확하지 않은 지표는 없느니만 못합니다

    사용량 게이지를 만들어 붙였는데, 재는 기간도 분모도 값도 실제 도구의 화면과 전부 달랐습니다. 한도가 아닌 것을 한도처럼 보이게 만든 셈이라 기능을 통째로 걷어냈고, 되돌아오지 못하도록 검사를 심었습니다. 만든 것을 지우는 판단까지가 제 몫이라고 봅니다.

    기술
    Electron · Node.js · Python

    데이터 모델 — 파일이 곧 프로토콜입니다

    에이전트 훅 Python · 표준 라이브러리만 프로젝트/.claude/ — 전부 로컬 team-events.jsonl · 화면의 유일한 근거 team-commands.jsonl · 지시 대기열 team-worker.json · 큐 소유권 (TTL 600s) team-cancel.flag · 도구 차단 윤사무실 앱 Electron · 화면과 지시 append 집어감 읽기 지시 넣기
    이 앱에는 데이터베이스가 없습니다 — 파일 규약이 데이터 모델입니다. 훅은 활동을 jsonl 에 한 줄씩 붙이고 앱은 그것만 읽습니다. 이벤트가 없으면 화면이 움직일 근거 자체가 없습니다. 파일이 프로젝트 폴더 안에 있어서, 회사를 3개 열어도 서로 모르는 채 각자 돕니다 — 규약을 전역에 뒀다면 셋이 같은 큐를 집었을 겁니다.
    이벤트 9종
    session · prompt · agent_start · tool · agent_stop · error · reply · command_taken · cancel — 공통 필드 ts발생 시각이라 재생할 때 그대로 씁니다
    귀속은 추론하지 않는다
    어느 에이전트가 한 일인지 훅이 남긴 값만 씁니다. 로그에서 유추하면 그럴듯한 거짓말이 화면에 뜹니다

    Stack

    기술 스택

    주력
    Java · Spring Boot (2년 3개월 · 저장소 6개)  /  PHP · Laravel (4년 · 본 서비스 커밋 67%)
    실무 4년 대부분을 이 두 스택 위에서 일했습니다
    그 외 언어
    Go · Node.js · TypeScript · Dart
    백엔드
    Spring Boot (MyBatis · JPA · Spring Security · Quartz) · Laravel (Eloquent · Artisan · Blade) · Echo(Go) · Express · NestJS
    프론트엔드 · 앱
    Thymeleaf · Blade · jQuery  /  Next.js · React  /  Flutter · Electron
    데이터
    MySQL · MariaDB · PostgreSQL · MongoDB · Redis
    인프라 · 보안
    Nginx · Docker · PM2 · systemd · AWS  /  Spring Security · JWT · AES-256 · 개인정보 마스킹·암호화
    대외 활동
    조코딩의 AI 비트코인 자동 매매 시스템 만들기 표지코딩셰프의 플러터 맛집 표지「조코딩의 AI 비트코인 자동 매매 시스템 만들기」(한빛미디어)
    「코딩셰프의 플러터 맛집」(루비페이퍼) — 기술 감수

    Contact

    문제를 찾아 정의하고, 구조로 해결하며, 변경의 결과까지 책임지겠습니다.

    투인원 내려받기

    교육
    DBMS기반 빅데이터 응용 SW개발자 전문과정
    중앙정보처리학원 · 2018.08 – 2019.03
    경력
    4년 1개월 · 2022.04 – 2026.07

    © 2026 윤정현

    확대한 화면