Full-stack Developer · Spring · Next.js · Flutter · AI · Backend 지원

백엔드부터 프론트엔드까지 직접 짜며,
클라이언트 영향까지 보는 백엔드 개발자.

Spring Boot 백엔드와 Next.js 그리고 Flutter 프론트까지 한 사람이 끝까지 짜 본 풀스택 개발자입니다.
외부 의존성과 동시성 그리고 실시간성 문제를 끝까지 파고드는 트러블슈팅으로 해결합니다.

01 · About

한 줄의 코드가 운영 현장에 닿는 순간

남상도 프로필 사진
잡모아 풀스택 정보처리산업기사 학점은행제 진행 중

남상도 / Namsangdo

풀스택 개발자 · Backend 지원 — 1~2년차 주니어

잡모아에서 풀스택 개발자로 일하고 있는 남상도입니다. Spring Boot 백엔드부터 Next.js와 Flutter 클라이언트까지 한 사람이 끝까지 짜며 매일 운영 데이터로 사용자 영향을 직접 확인합니다.

특성화고 스마트소프트웨어과에서 프로그래밍을 처음 만났고 코리아IT아카데미의 임베디드 소프트웨어 융합 풀스택 개발자 양성 과정B를 거쳐 정보처리산업기사를 취득했습니다. 학력의 출발선이 다른 만큼 책으로 증명되지 않는 부분은 GitHub 33개 공개 저장소와 사이드 프로젝트로 채워 왔고 현재 학점은행제 소프트웨어 전공으로 이론을 보강하고 있습니다.

"끝까지 파고든다"는 말이 가장 잘 맞습니다. 트랜잭션 경계 밖에 있는 외부 의존성과 동시성 문제를 만나면 임시방편으로 우회하지 않고 책임 계층부터 다시 봅니다. 백엔드만 짜는 사람이 아니라 그 API를 소비하는 화면까지 직접 짜기 때문에 변경의 끝단 영향을 머릿속에서 함께 시뮬레이션하며 결정합니다.

1인 개발자로서 자체 제작한 kr-resume-skill을 사내에 공유했고 동료들이 AI를 실무에 활용할 수 있도록 사내 AI 활용 교육 세션도 직접 진행해 왔습니다. 꾸준하고 성실하며 체력도 강한 편이라 길게 가는 일을 좋아합니다. 일 외에는 운동과 AI 사용법을 꾸준히 익히는 것이 취미입니다.

운영을 책임지는 풀스택

잡모아 운영 시스템에서 Spring Boot 백엔드와 Next.js 화면 그리고 Flutter 사내 앱까지 한 사람이 끝까지 짜고 운영합니다. 같은 도메인을 양쪽에서 보기 때문에 변경의 끝단 영향이 머리에 들어옵니다.

클라이언트 영향까지 보는 백엔드

API를 설계할 때 응답 스키마가 화면에서 어떻게 보이는지 WebSocket 메시지가 클라이언트 상태와 어떻게 동기화되는지를 함께 시뮬레이션합니다. STOMP destination 네이밍도 후속 알림 추가의 프론트 비용까지 함께 보고 결정합니다.

트러블슈팅으로 검증된 문제해결력

다중 상담사 동시 요청 시 Gemini API 중복 호출을 ConcurrencyManager로 단독 해결했습니다. 알림 폴링 부하는 STOMP/SockJS와 Redis pub/sub 결합으로 제거하고 다중 인스턴스 동기화까지 확보했습니다.

AI를 만드는 개발자

Claude와 Claude Code 그리고 MCP를 단순 사용을 넘어 직접 사내 도구와 오픈소스로 만들어 봤습니다. 채용공고 자동화 chatJobmoa와 자가진단 챗봇 NESS 그리고 자기소개서·포트폴리오 자동화 kr-resume-skill을 만들었고 1인 개발자로서 사내에 kr-resume-skill을 공유하고 AI 활용 교육 세션도 직접 진행했습니다.

02 · Skills

Tech Stack

실무 운영에 직접 사용한 주력 기술과, 사이드 프로젝트로 다뤄본 보조 기술을 분리해 표기.

Backend 주력

  • Java 17
  • Spring Boot 3.4.1
  • Spring MVC
  • MyBatis 3.5.6
  • Spring AOP

Frontend 실무 운영

  • Next.js 16 (App Router)
  • React 19
  • TypeScript
  • Tailwind CSS 4
  • Framer Motion
  • JSP

Mobile

  • Flutter
  • Dart

Datastore

  • MSSQL Server (T-SQL)
  • Redis (Jedis 5.2.0)
  • SQLite

Realtime / Async

  • Spring WebSocket
  • STOMP / SockJS
  • Redis pub/sub
  • OkHttp

AI Integration 차별점

  • Google Gemini API
  • Anthropic Claude API
  • Prompt Engineering
  • Claude Code Skills · MCP

Secondary

  • NestJS
  • Node.js
  • Python
  • C#

Infra / DevOps

  • Maven (WAR)
  • Ubuntu/Nginx/PM2
  • Git / GitHub
  • Apache POI
03 · Projects

대표 프로젝트 — 아키텍처와 함께

실 운영 프로젝트를 중심으로, 아키텍처와 핵심 의사결정을 함께 설명합니다.

P1

잡모아 국민취업지원제도 참여자 관리 시스템

Spring Boot · MyBatis · MSSQL · Redis · WebSocket — 실 운영 백엔드

GitHub ↗
조직 (주)잡모아 / 고용노동부 위탁 역할 백엔드 개발 · 도메인 모델링 백엔드 다인 협업 (담당: 도메인 1축, AI 통합, 실시간 알림)
Java 17Spring Boot 3.4.1Spring MVC MyBatis 3.5.6MSSQLRedis · Jedis 5.2.0 WebSocket / STOMP / SockJSMaven (WAR)

고용노동부 국민취업지원제도 위탁 운영을 위한 통합 관리 시스템입니다. 세 도메인 모듈(상담관리와 취업알선 그리고 채용정보)로 책임을 분리해 설계했고 AOP 트랜잭션 분리(select* 읽기전용과 PROPAGATION_REQUIRED)로 운영 데이터 무결성을 확보했습니다.

📐 시스템 아키텍처

flowchart LR
  Client[Browser] -->|Login Session| LI[LoginInterceptor]
  LI --> CTRL[Controller Layer]
  CTRL --> SVC[Service / *Impl]
  SVC --> DAO[DAO + SqlSessionTemplate]
  DAO --> MB[MyBatis XML Mappers x15]
  MB --> DB[(MSSQL Server)]

  SVC -. AOP Tx .-> AOP{{TxAdvisor: select* readonly / else REQUIRED}}
  SVC -- Cache --> RC[(Redis · Jedis)]
  SVC -- Realtime --> WS[STOMP /ws-notification]
  WS -- pub/sub --> RPS[(Redis pub/sub)]
  SVC -- AI --> GAS[GeminiApiService]
  GAS --> CMG{{RecommendConcurrencyManager}}
  GAS --> Gemini[(Google Gemini API)]

  subgraph DomainModules
    M1[CounselMain
상담·교육·취업·AI] M2[jobPlacement
비동기 REST · WS] M3[recruitmentFormation
채용 스케줄 동기화] end CTRL --> M1 & M2 & M3

핵심 의사결정

  • 세 모듈 분리로 모듈별 매퍼와 서비스 그리고 뷰를 나눠 변경 영향 범위를 최소화했습니다.
  • 명시적 컴포넌트 스캔만 허용하고 RootConfig와 WebMvcConfig에 등록해 의도된 빈만 살아 있도록 했습니다.
  • AOP 트랜잭션 정책은 select* 읽기전용으로 책임을 명확히 하고 그 외에는 PROPAGATION_REQUIRED를 적용했습니다.
  • 세션 인증 JOBMOA_LOGIN_DATA에 6시간 타임아웃을 두어 위탁 운영 보안 가이드를 충족했습니다.
P2

NESS — 국민취업지원제도 자가진단 챗봇

Next.js 16 · React 19 · Gemini · SQLite — 도메인 결정트리 + 대화형 UI

GitHub ↗
조직 (주)잡모아 역할 백엔드 · 도메인 규칙 설계
Next.js 16 (App Router)React 19TypeScript Tailwind CSS 4Framer Motion Google GeminiSQLite (better-sqlite3) JWT / bcryptUbuntu · Nginx · PM2

법령상 자격 요건(소득과 재산 그리고 연령과 구직이력)을 결정 트리로 도메인 모델링하고 Gemini 대화형 인터페이스로 풀어 일반 사용자가 답하는 동안 자동으로 자격을 판별합니다.

📐 진단 흐름

flowchart TB
  U[사용자] --> CH[채팅 UI]
  CH --> NRR{Next.js Route Handler}
  NRR --> DT[Decision Tree
자격 규칙 도메인 모델] NRR --> GA[Gemini API
자연어 응답 생성] DT --> RES{유형 판별} RES -->|I 유형| OUT1[취업 지원 + 수당] RES -->|II 유형| OUT2[취업 지원] RES -->|비대상| OUT3[대안 안내] NRR --> DB[(SQLite · 지점·계정·프롬프트)] ADM[관리자 대시보드] --> DB ADM -. bcrypt JWT .- DB

주요 성과

  • 법령 자격 요건을 결정 트리 도메인 모델로 구조화
  • 대화형 UI로 진입 장벽 완화 → 운영 부서 1차 상담 부담 경감
  • 관리자 대시보드: 지점·계정(bcrypt)·Gemini API 키·프롬프트 실시간 업데이트
P3

chatJobmoa v2.0 — AI 채용공고 자동 생성

NestJS · TypeScript(Strict) · Prisma · Gemini — 사내 첫 LLM 자동화 사례

GitHub ↗
조직 (주)잡모아 역할 AI 통합 백엔드
NestJSTypeScript StrictPrisma ORM Google Gemini APIMulter@nestjs/schedule (Cron) JWT

채용공고 1건 평균 30분의 반복 작성 병목을 LLM 자동화로 해소했습니다. Gemini 초안 생성에 후처리 파이프라인을 두어 형식과 용어 그리고 금지어를 검증하도록 설계했습니다.

📐 AI 생성 파이프라인

flowchart LR
  IN["기업·직무·자격 입력"] --> NEST["NestJS Controller"]
  NEST --> AISVC["AI Generation Service"]
  AISVC -- "Prompt" --> Gem["Gemini API"]
  Gem --> Draft["Draft 응답"]
  Draft --> POST["후처리 Pipeline
형식·용어·금지어 검증"] POST -- "OK" --> HTML["HTML 채용공고
Tailwind 기반"] POST -- "이미지" --> IMG["포스터·배너 이미지"] POST -- "Reject" --> RETRY["재요청 / 사람 검수"] HTML --> DB[("Prisma DB")] IMG --> FS[("uploads/")] CRON["nestjs/schedule Cron"] --> AISVC

대표 엔드포인트

  • POST /ai/recommend/keywords 직종과 직무 기반 키워드 추천
  • POST /generate/:id/html Tailwind HTML 채용공고 생성
  • POST /generate/:id/images 포스터와 배너 이미지 생성
  • GET /benefits 중소기업 혜택 조회 (SmeBenefit)
P4

kr-resume-skill — Claude Skill 기반 자기소개서·포트폴리오 생성기 (오픈소스)

Python · ReportLab · python-pptx · Claude Code Skills

GitHub ↗
조직 — 개인 사이드 프로젝트 (사내 공유) 역할 — 기획·개발 100%
PythonReportLabpython-pptx PillowlxmlClaude Code Skills

한국 취업 시장 형식에 맞춘 자기소개서와 포트폴리오 자동 생성 Claude Code Skill입니다. 대화형 정보 수집과 STAR 기법 적용 그리고 글자수 자동 조정을 거쳐 ATS 호환 자기소개서 PDF와 Canva 스타일 포트폴리오 PPTX 출력까지 파이프라인화했습니다.

주요 산출

  • Claude Code Skill로 패키징해 누구나 재사용 가능한 도구로 배포했습니다.
  • 자기소개서 PDF와 포트폴리오 PPTX 템플릿 3종(공공·대기업, IT·스타트업, 디자인·크리에이티브)을 제공합니다.
  • 한글 텍스트 선택이 가능한 PDF를 ReportLab과 한글 폰트 자동 등록 파이프라인으로 직접 구현했습니다.
  • 1인 개발자로 일하는 잡모아 사내에도 공유해 동료들의 취업 서류 작성을 도왔습니다.
04 · Troubleshooting

두 건의 트러블슈팅 — 외부 의존성과 다중 인스턴스

트랜잭션 경계만으로는 잡히지 않는 문제를 책임 계층(락과 캐시 그리고 외부 의존성)으로 분리해서 해결한 사례입니다.

T1

Gemini AI 직무 추천 — 동시성 이슈

단독 해결

🔍 문제 (Problem)

다수 상담사가 동일 참여자에 대해 동시에 'AI 직무 추천' 버튼을 클릭하면 다음과 같은 일이 벌어졌습니다.

  • Gemini API가 N번 중복 호출되어 비용과 지연이 누적되었습니다.
  • 응답 시점에 따라 서로 다른 추천 결과가 DB에 덮어써졌습니다 (race condition).
  • 트랜잭션 경계만으로는 외부 API 호출 비용을 막을 수 없었습니다.

🧪 원인 분석 (Investigation)

  • 재현 스크립트로 동일 participantId에 3개 동시 요청을 보내자 항상 3건의 Gemini 호출과 race가 확인되었습니다.
  • ParticipantJobRecommendServiceImpl이 매 호출마다 새 컨텍스트로 Gemini를 호출해 중복 제거 계층이 부재한 상태였습니다.
  • 락과 캐시 그리고 외부 의존성의 책임을 분리해야 풀 수 있는 지점이었습니다.

🛠 해결 (Solution)

// 핵심 아이디어
class RecommendConcurrencyManager {
  // participantId → 진행 중인 CompletableFuture
  ConcurrentHashMap<Long, CompletableFuture<Result>> inflight;

  CompletableFuture<Result> runOrJoin(Long pid, Supplier<Result> task) {
    return inflight.computeIfAbsent(pid,
      k -> CompletableFuture.supplyAsync(task)
            .whenComplete((r, e) -> inflight.remove(k)));
  }
}
  • participantId를 키로 진행 중인 CompletableFuture를 공유합니다.
  • 후속 요청은 새 호출 없이 같은 Future를 반환받습니다.
  • 완료나 예외 시 자동 정리로 누수를 차단합니다.
  • ParticipantJobRecommendServiceImpl 진입부에 결합한 얇은 게이트로 동작합니다.

✅ 결과 (Result)

  • 100%동일 참여자 Gemini 중복 호출 차단
  • 외부 AI API 호출 비용과 응답 지연 감소
  • 동일 참여자 추천 결과 일관성 보장

Lesson. 외부 의존성 호출의 비용과 일관성은 트랜잭션 경계 밖에서 별도 계층으로 다뤄야 합니다. AOP와 락 그리고 캐시 중 어디에 책임을 둘지를 분리해서 보는 습관을 얻었습니다.

📐 동시성 제어 흐름

sequenceDiagram
  autonumber
  participant C1 as 상담사 A
  participant C2 as 상담사 B
  participant SVC as RecommendService
  participant CMG as ConcurrencyManager
(participantId key) participant Gem as Gemini API participant DB as MSSQL C1->>SVC: recommend(participantId=42) SVC->>CMG: runOrJoin(42, task) CMG->>Gem: call once (only first) C2->>SVC: recommend(participantId=42) SVC->>CMG: runOrJoin(42, task) CMG-->>C2: join existing Future Gem-->>CMG: result CMG->>DB: save (single write) CMG-->>C1: same result CMG-->>C2: same result
T2

WebSocket 실시간 알림 — 폴링 부하 + 다중 인스턴스

주요 기여

🔍 문제 (Problem)

  • 상담사 화면이 1분 폴링과 수동 새로고침에 의존했습니다.
  • 동시 접속자가 증가하면 DB 부하가 비례해 늘었습니다.
  • 다중 WAS 환경에서 한 노드의 알림이 다른 노드 사용자에게 전달되지 않았습니다.

🧪 원인 분석 (Investigation)

  • 폴링 간격을 줄이는 임시방편은 곧 부하 폭증으로 이어졌습니다.
  • 단일 STOMP simple broker만으로는 인스턴스 간 메시지가 격리되었습니다.
  • 노드 안 브로커와 노드 간 pub/sub을 분리하는 구조가 적합하다고 판단했습니다.

🛠 해결 (Solution)

  • /ws-notification STOMP/SockJS 엔드포인트를 신규 구축했습니다.
  • /topic 구독과 /app 발신 prefix로 알림 종류를 분리해 확장성을 확보했습니다.
  • Redis pub/sub 어댑터를 STOMP 브로커 앞단에 두어 다중 인스턴스를 동기화했습니다.
  • 기존 폴링 로직을 제거하고 이벤트 기반 push로 전환했습니다.

✅ 결과 (Result)

  • ↓↓폴링 제거로 DB 조회 부하 큰 폭 감소
  • 다중 WAS 인스턴스 알림 동기화 달성
  • +알림 종류 추가가 코드 수정 없이 가능

Lesson. 실시간성과 확장성은 한 노드의 브로커와 노드 간 pub/sub을 분리해서 설계해야 안정적입니다. STOMP destination 네이밍을 도메인 단위로 잡아두니 후속 알림 추가가 비용 없이 흘러갔습니다.

📐 다중 인스턴스 알림 동기화

flowchart LR
  Producer[Domain Event
참여자 배정·일정 변경] --> N1[WAS Node 1] Producer --> N2[WAS Node 2] N1 -- publish --> RPS[(Redis pub/sub
channel: notify)] N2 -- publish --> RPS RPS -- subscribe --> N1 RPS -- subscribe --> N2 N1 --> S1[STOMP /topic/...] N2 --> S2[STOMP /topic/...] S1 --> U1[상담사 A · Node1 접속] S2 --> U2[상담사 B · Node2 접속] classDef node fill:#EFF6FF,stroke:#2563EB class N1,N2 node
05 · Experience

Career Timeline

  1. (주)잡모아 — 풀스택 개발자

    현재 재직 중

    고용노동부 국민취업지원제도 위탁 운영 시스템

    • [Backend] Spring Boot와 Java 17 그리고 MyBatis와 MSSQL 기반 운영 시스템을 직접 개발하고 운영합니다.
    • [Backend] 세 도메인 모듈을 분리 설계하고 AOP 트랜잭션 정책을 수립했습니다.
    • [Backend] Gemini AI 직무 추천의 동시성 이슈를 단독으로 해결했습니다.
    • [Backend] STOMP/SockJS WebSocket과 Redis pub/sub을 결합해 실시간 알림을 구축했습니다.
    • [Frontend] Next.js 16과 React 19 그리고 Tailwind 기반 NESS 챗봇 UI와 관리자 대시보드를 직접 구현했습니다.
    • [Frontend] 잡모아 운영 시스템 JSP 화면 신규 개발과 유지보수를 담당하며 사용자 워크플로우를 개선했습니다.
    • [Mobile] Flutter 기반 사내 장비관리 앱을 단독으로 설계하고 개발했습니다.
    • [AI] 사내 첫 LLM 기반 업무 자동화 사례 chatJobmoa의 백엔드와 생성 결과 화면까지 정착시켰습니다.
  2. 정보처리산업기사 — 한국산업인력공단

    국가기술자격

    정보처리 분야 국가기술자격 취득

  3. 학점은행제 — 소프트웨어 전공

    진행 중 (현업 병행)

    이론 보강 — 자료구조와 알고리즘 그리고 데이터베이스와 네트워크

  4. 코리아IT아카데미 — 임베디드 소프트웨어 융합 풀스택 개발자 양성 과정B

    수료

    HTML/CSS/JS와 Java 그리고 Spring과 DB 기초부터 프로젝트까지 정규 훈련 (국민내일배움카드 · 고용24 등록 과정)

  5. 특성화고등학교 · 스마트소프트웨어과

    졸업

    프로그래밍 기초 학습 — 개발자의 출발선

함께 좋은 시스템을 만들고 싶습니다.

헬스케어 백엔드, AI 통합, 운영 안정성에 관한 어떤 얘기든 환영합니다.