Refactoring Existing Legacy Code with AI
This might be the easiest kind of project for an AI. It also seems like the most efficient.
I took a service already running in production, riddled with hardcoding and ad-hoc exception handling, and had AI fix and rebuild it.
PHP Monolith to Java MSA: A 14-Day Record With AI
The time it took to refactor a legacy system of 1,499 PHP files and 65,048 lines into 12 microservices — 14 days. Here’s the data proving why that was possible.
1. Project overview
What we built
Zelotek — an unmanned kiosk system supporting 196 stores across 6 industries (study cafés, reading rooms, saunas, restaurants, and more).
We completely refactored the existing PHP monolith into a Java Spring Boot MSA.
Before → After
| Item | PHP legacy | Java MSA |
|---|---|---|
| Architecture | Monolith | 12 microservices |
| Language | PHP | Java 17 + Spring Boot 3.2 |
| DB strategy | Single DB | Database per service |
| Communication | Direct function calls | REST + RabbitMQ events |
| Frontend | PHP rendering | React + Electron |
| Deployment | Manual FTP | Docker Compose → AWS EKS |
2. Final output size
Overall code statistics
| Category | Files | Lines of code |
|---|---|---|
| Backend (Java) | 639 | 43,900 |
| Kiosk Desktop (Electron/React) | 62 | 12,318 |
| Admin Dashboard (React) | 34 | 8,741 |
| DB Migrations (SQL) | 106 | 9,142 |
| PDCA documents | 61 | 43,892 |
| Docker/Infra configuration | 14+ | 448+ |
| Other (config, scripts, etc.) | 226 | - |
| Total | 1,142+ | 118,441+ |
Note: excludes auto-generated files such as node_modules, build, and .gradle
Size by service
| Service | Role | Java files | Lines |
|---|---|---|---|
| Payment | Payment processing, PG integration, refunds | 150 | 9,893 |
| Store | Franchise management, kiosks, remote control | 85 | 6,500 |
| Member | Members, points, mileage | 76 | 5,053 |
| Seat | Seat management, live status | 76 | 4,809 |
| Auth | JWT authentication, 3-tier RBAC | 66 | 4,661 |
| Reservation | Reservation handling, event consumption | 36 | 3,578 |
| Goods | Product management, bundles, coupons | 52 | 3,234 |
| Notification | SMS, KakaoTalk alerts | 35 | 2,445 |
| Analytics | Sales statistics (MongoDB) | 20 | 1,415 |
| File | File upload (S3) | 12 | 858 |
| Board | Bulletin board | 17 | 806 |
| Config | Configuration server | 14 | 648 |
| Total | 12 services | 639 | 43,900 |
Architecture component counts
| Component | Count |
|---|---|
| JPA/MongoDB entities | 75 |
| Repositories | 70 |
| Services | 67 |
| REST controllers | 59 |
| DTOs (request/response) | 143 |
| RabbitMQ event files | 25 |
| Feign clients | 10 |
| Schedulers | 10 |
| Strategy/conditional patterns | 16 |
| Flyway migrations | 106 |
| Dockerfiles | 14 |
3. System architecture
Overall architecture
┌─────────────────┐
│ Eureka Server │
│ (8761) │
└────────┬────────┘
│ Service Discovery
┌───────────────────────┼───────────────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Auth │ │ Payment │ │ Store │
│ (8081) │ │ (8084) │ │ (8088) │
│ JWT/RBAC │ │ PG/payment│ │ franchise │
└───────────┘ └─────┬─────┘ └───────────┘
│
┌──────────────────────┼──────────────────────┐
│ payment.confirmed │ payment.cancelled │ payment.refunded
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│Reservation│ │ Seat │ │ Member │
│ (8086) │ │ (8085) │ │ (8082) │
│ auto-book │ │ seat alloc│ │ points │
└───────────┘ └───────────┘ └───────────┘
│ │
│ │
┌─────┴─────┐ ┌───────────┐ ┌─────┴─────┐
│ Goods │ │ Analytics │ │Notification│
│ (8087) │ │ (8090) │ │ (8089) │
│goods/coupon│ │ MongoDB │ │SMS/Kakao │
└───────────┘ └───────────┘ └───────────┘
│ │
┌─────┴─────┐ ┌─────┴─────┐
│ File │ │ Board │
│ (8091) │ │ (8092) │
│ S3 storage│ │ board │
└───────────┘ └───────────┘
Service communication patterns
┌─────────────────────────────────────────────────────────┐
│ Synchronous (REST/Feign) │
│ │
│ Payment ──→ Member (member lookup) │
│ Payment ──→ Store (store info) │
│ Store ──→ Member (member verification) │
│ Notification ──→ Member (contact lookup) │
│ Member ──→ Store (store info) │
│ Reservation ──→ Goods, Payment, Seat (booking) │
│ Goods ──→ Store, Payment (product-store linkage) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Asynchronous (RabbitMQ) │
│ │
│ [payment.events] Exchange │
│ ├─ payment.confirmed → Reservation (auto-create) │
│ ├─ payment.confirmed → Seat (seat allocation) │
│ ├─ payment.confirmed → Member (points accrual) │
│ ├─ payment.confirmed → Analytics (sales aggregation) │
│ ├─ payment.confirmed → Notification (payment alert) │
│ ├─ payment.cancelled → Seat (seat release) │
│ └─ payment.refunded → Member (points deduction) │
│ │
│ [store.events] Exchange │
│ ├─ store.updated → Goods, Notification │
│ ├─ kiosk.registered → Store (auto-provisioning) │
│ └─ kiosk.command.* → Kiosk (remote commands) │
│ │
│ [member.events] Exchange │
│ ├─ member.registered → Notification (signup alert) │
│ └─ member.mileage_expiring → Notification (expiry) │
│ │
│ [auth.events] Exchange │
│ ├─ auth.login → Analytics (login stats) │
│ └─ auth.logout → Analytics (session stats) │
└─────────────────────────────────────────────────────────┘
Tech stack diagram
┌─────────────────────────────────────────────────────────┐
│ Client layer │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Electron + │ │ React │ │ Browser │ │
│ │ React │ │ Admin │ │ (customer) │ │
│ │ (kiosk) │ │ Dashboard │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Infrastructure layer │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Eureka │ │ Nginx │ │ Docker │ │
│ │ Discovery│ │ Gateway │ │ Compose │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Service layer (12) │
│ │
│ Java 17 + Spring Boot 3.2.1 + Spring Cloud 2023.0.0 │
│ Clean Architecture (API → App → Domain → Infra) │
│ JWT + RBAC (SUPER_ADMIN / FRANCHISE_ADMIN / STORE_ADMIN)│
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Data layer │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │PostgreSQL│ │ MongoDB │ │ Redis │ │RabbitMQ│ │
│ │ (11 DBs) │ │(Analytics)│ │ (Cache) │ │(Events)│ │
│ └──────────┘ └──────────┘ └──────────┘ └────────┘ │
└─────────────────────────────────────────────────────────┘
Clean Architecture (inside each service)
┌─────────────────────────────────────┐
│ API Layer │
│ Controller, DTO (Request/Response) │
├─────────────────────────────────────┤
│ Application Layer │
│ Service, Scheduler, Event Handler │
├─────────────────────────────────────┤
│ Domain Layer │
│ Entity, Repository Interface, │
│ Enum, Value Object │
├─────────────────────────────────────┤
│ Infrastructure Layer │
│ JPA Repository Impl, Feign Client, │
│ RabbitMQ Publisher/Listener, │
│ Security (JWT, RBAC), Gateway │
└─────────────────────────────────────┘
4. Development timeline
| Date | Work | Key output |
|---|---|---|
| 1/27 (Day 1) | PDCA documents, service design | 5 Plans, 8 Designs, 43,892 lines of docs |
| 1/27–2/3 (Days 1–8) | Base implementation of 12 services | 639 Java files, 43,900 lines |
| 2/5 (Day 10) | Multi-brand UI design | Theme system for 6 industries |
| 2/6 (Day 11) | v5.0 gap analysis + fixes | 93% design-implementation match |
| 2/7 (Day 12) | Docker integration + API testing | 8/8 services up, all APIs PASS |
| 2/8 (Day 13) | Payment verification + device porting + admin dashboard | 56/56 tests, seed data |
| 2/9 (Day 14) | v6.0 completeness + MongoDB Analytics | 98%+ match, 0 TODOs |
Design-implementation match rate by version
v4.0 (Day 8) ████████░░░░░░░░░░░░ 82%
v5.0 (Day 11) █████████████████░░░░ 93%
v5.1 (Day 12) ███████████████████░░ 95.3%
v6.0 (Day 14) ████████████████████░ 98%+
5. Efficiency: without AI vs. with AI
5-1. Time estimates by task
Baseline: one senior Java developer + one senior frontend developer (a 2-person team)
| Task | Without AI (traditional) | With AI (actual) | Reduction |
|---|---|---|---|
| Requirements analysis + design docs | 3–4 weeks | 1 day | 95% |
| Project setup for 12 services | 1–2 weeks | 0.5 day | 93% |
| DB schema design + migrations | 2–3 weeks | 2 days | 86% |
| 75 domain entities | 3–4 weeks | 2 days | 93% |
| 59 REST API controllers | 4–6 weeks | 3 days | 90% |
| 67 business logic services | 6–8 weeks | 4 days | 88% |
| RabbitMQ event integration (12 services) | 3–4 weeks | 1 day | 95% |
| 10 Feign clients | 1–2 weeks | 0.5 day | 93% |
| JWT + RBAC authn/authz | 2–3 weeks | 1 day | 90% |
| Payment system (6 methods + refunds + receipts) | 4–6 weeks | 2 days | 92% |
| Admin dashboard (React) | 3–4 weeks | 2 days | 88% |
| Electron kiosk app | 4–6 weeks | 3 days | 88% |
| Docker integration (16 containers) | 1–2 weeks | 0.5 day | 93% |
| Integration testing + debugging | 2–3 weeks | 2 days | 85% |
| Total | 40–56 weeks (10–14 months) | ~14 days | ~95% |
5-2. Headline comparison
┌─────────────────────────────────────────────────────────┐
│ Development efficiency summary │
├─────────────────┬──────────────┬─────────────────────────┤
│ Item │ Traditional │ With AI │
├─────────────────┼──────────────┼─────────────────────────┤
│ Total duration │ 10–14 months │ 14 days │
│ Headcount │ 2–3 people │ 1 person + AI │
│ Lines (Java) │ 43,900 │ 43,900 (same quality) │
│ Documentation │ 4–6 weeks │ 1 day │
│ Design match │ 70–80%* │ 98%+ │
│ TODOs remaining │ tens–hundreds │ 0 │
│ Labor cost (est.)│ ₩100–200M │ ~₩2M (AI subscription) │
│ Daily code output│ 200–400 LOC │ ~3,100 LOC │
└─────────────────┴──────────────┴─────────────────────────┘
* The traditional design-implementation match rate tends to fall as project size grows
5-3. Labor cost comparison (Korean market)
Traditional (10–14 months)
| Role | Monthly rate | Duration | Subtotal |
|---|---|---|---|
| Senior backend developer | ₩9M | 12 months | ₩108M |
| Senior frontend developer | ₩8.5M | 10 months | ₩85M |
| DevOps engineer (part-time) | ₩9M | 3 months | ₩27M |
| PM/architect (part-time) | ₩10M | 12 months | ₩120M |
| Total | ~₩340M |
With AI (14 days)
| Item | Cost |
|---|---|
| 1 developer (14 days) | ~₩6.5M |
| Claude Pro subscription (monthly) | ~₩30,000 |
| Total | ~₩6.53M |
Cost reduction: about 98% (₩340M → ₩6.53M) This is of course an extreme comparison, and the traditional approach can be optimized too. Even with AI, judgment from a developer with domain knowledge is indispensable.
6. Where AI was especially strong
6-1. Generating repetitive boilerplate
75 entities, 70 repositories, 143 DTOs — bulk generation of structurally similar code in a consistent pattern.
Traditional: 30–60 minutes to write one entity
With AI: 75 entities generated in a day, pattern consistency preserved
6-2. Cross-service integration design
RabbitMQ event routing and Feign client wiring across 12 services — the AI keeps the whole architecture in memory and integrates consistently.
Real example: routing key mismatch between Payment → Reservation
(payment.completed vs payment.confirmed)
The AI found it by exhaustively analyzing event flow across all 12 services
(exactly the kind of thing a human misses)
6-3. Automatic PDCA documentation
43,892 lines of design documentation written in a day — precise enough that the design matched the code at 98%.
6-4. Gap analysis + automatic fixes
Found 37 TODOs, understood the context of each, and replaced them with correct implementations.
v5.1: 95.3% match, 37 TODOs
↓ AI analysis + fixes (single session)
v6.0: 98%+ match, 0 TODOs
7. What AI can’t do (where humans are essential)
| Area | Description |
|---|---|
| Domain knowledge | Per-industry business logic across 196 stores requires field experience |
| Decision-making | The final call on choices like “MongoDB vs PostgreSQL” |
| UX sense | Kiosk user flow, touch interface optimization |
| Security verification | Real PG integration, payment security certification (PCI DSS, etc.) |
| Operational judgment | Production deployment strategy, incident response, monitoring thresholds |
| Stakeholder communication | Aligning client requirements, negotiating schedules |
8. Methodology: PDCA + AI
┌────────────────────────────────────────────┐
│ PDCA Cycle with AI │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Plan │───→│ Design │ │
│ │ AI: docs │ │ AI: design│ │
│ │ auto-gen │ │ auto-gen │ │
│ └──────────┘ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Act │←───│ Do │ │
│ │ AI: auto │ │ AI: code │ │
│ │ fix/improve│ │ auto-gen │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ │ ┌────┴─────┐ │
│ └──────────│ Check │ │
│ │ AI: gap │ │
│ │ analysis │ │
│ └──────────┘ │
│ │
│ Human role: verification and final sign-off│
│ at each stage │
└────────────────────────────────────────────┘
The AI’s role at each PDCA stage
| Stage | AI role | Human role |
|---|---|---|
| Plan | Turn requirements into structured documents | Define business requirements |
| Design | Auto-generate detailed design + API specs | Approve architectural decisions |
| Do | Auto-generate code from the design | Code review + domain verification |
| Check | Auto-analyze design-implementation gaps | Set quality criteria |
| Act | Auto-fix based on gaps | Judge the direction of fixes |
9. Technical challenges and solutions
Challenge 1: mapping legacy status values
PHP: FAIL → SUCCESS → INUSE → COMPLETE → REFUND
Java: PENDING → CONFIRMED → INUSE → COMPLETE → REFUNDED
CANCELLED
FAILED
The AI analyzed the PHP code, auto-generated the state transition map, and extended it into DB CHECK constraints.
Challenge 2: event routing consistency
Twelve services share six exchanges, and the routing keys of published events must match the queue bindings exactly.
CRITICAL bug found:
Payment publishes: payment.confirmed (routing key)
Reservation subscribes: payment.completed (queue binding)
→ a fatal bug where reservations were never auto-created after payment
The AI found it by cross-checking event flow across every service.
Challenge 3: 6 industries × 6 payment methods
Post-payment logic differs across 6 industries (study cafés, reading rooms, saunas, restaurants, coin laundries, unmanned convenience stores) and 6 payment methods (card, cash, points, NFC, coupons, mileage) — 36 combinations, resolved with the Strategy pattern.
10. Conclusion
The result in numbers
┌──────────────────────────────────────┐
│ AI-collaboration results │
│ │
│ Duration: 14 days (vs 10–14 mo) │
│ Code size: 118,000+ lines │
│ Services: 12 microservices │
│ APIs: 59 controllers │
│ DB tables: 106 migrations │
│ Event coverage: 12/12 services (100%)│
│ Design match: 98%+ │
│ TODOs left: 0 │
│ Tests: 56/56 PASS (100%) │
│ Cost saving: ~98% (₩340M → ₩6.53M) │
│ │
│ Speed: ~20–30× faster │
│ Daily code: ~3,100 LOC (vs 200–400)│
└──────────────────────────────────────┘
Key insights
-
AI is a tool, not a replacement. The optimal structure is a developer with domain knowledge setting direction while the AI supplies execution.
-
PDCA + AI compound each other. Cycling design → implementation → verification → improvement quickly through AI got us to 98%+ quality.
-
AI’s value in repetitive work is overwhelming. 75 entities, 143 DTOs, 106 migrations — on high-volume work with a pattern, AI shows tens of times the productivity.
-
AI’s real strength is consistency. Event routing across 12 services, package structure, coding conventions — the AI holds the consistency humans easily lose.
-
The cost structure fundamentally changes. One person finishing in two weeks what ten people would do in a year isn’t a simple efficiency gain; it’s a paradigm shift in how software gets built.
Every figure in this post is based on real project data, and the line and file counts were verified with automated measurement tools.
| _Written by Wan Ki Kim | Project: Zelotek (Hunik) | Date: 2026-02-09_ |
| _AI tool: Claude Code (Anthropic) | Methodology: PDCA + AI Native_ |