Track My Cash: Spring Boot, Vanilla JS, 그리고 Gemini를 활용한 안전하고 분리된 원장 구축

발행: (2026년 2월 28일 오후 09:55 GMT+9)
8 분 소요
원문: Dev.to

Source: Dev.to

위 링크에 있는 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. (코드 블록, URL 및 마크다운 형식은 그대로 유지됩니다.)

Google Gemini로 만든 것

저는 BookKeeping이라는 풀스택 금융 원장 애플리케이션을 만들었습니다. 이 앱은 매우 구체적인 문제, 즉 친구에게 빌려준 돈을 복잡한 회계 도구 없이 추적하는 문제를 해결합니다.

  • 프론트엔드 – 프레임워크 없이 순수 JavaScript, HTML, CSS (프레임워크 의존성 없음) 를 Google Cloud Run에 안전하게 배포했습니다.
  • 백엔드 – Java, Spring Boot 3, Spring Security 6, 그리고 Render에 호스팅된 PostgreSQL 데이터베이스.

Google Gemini는 전체 개발 주기 동안 저의 페어 프로그래밍 파트너 역할을 하며, 분리된 아키텍처의 복잡한 부분들을 연결하는 데 도움을 주었습니다.

Gemini가 도와준 방법

  • 보안 흐름 설계 – HttpOnly 쿠키와 표준 Bearer 토큰을 사용한 무상태 JWT 인증을 구현했습니다.
  • 브라우저 보안 장벽 처리 – 엄격한 CORS와 JSON 페이로드 전략을 설계하여 서드파티 쿠키 차단(예: Safari ITP)을 극복하고 CSRF 공격을 원천적으로 방지했습니다.
  • 수학 엔진 구축 – 대출 금액을 동적으로 감소시키고 잔액이 0이 되면 데이터베이스 행을 자동으로 삭제하는 맞춤형 “Partial Repayment” 알고리즘을 공동 개발했습니다.
  • Cloud Run Docker 환경 구성 – 프론트엔드를 위한 가벼운 Alpine‑Nginx 컨테이너를 만들었습니다. Gemini가 Cloud Run이 표준 포트 바인딩을 무시한다는 점을 알려주어, 배포 시 Cloud Run의 $PORT 환경 변수를 주입하는 동적 nginx.conf.template를 추가했습니다.
  • 네이티브 OS 로컬라이제이션 설계 – 다중 통화 로직에 하드코딩된 'en-US' 로케일을 수정했습니다. Intl.NumberFormatundefined를 전달함으로써 UI가 운영 체제의 로케일 설정을 상속받게 되었으며(예: 올바른 유로화 포맷).

인증에 대한 참고

로그인 시스템은 의도적으로 간단하게 설계되었습니다. 이 앱은 매우 집중된 개인 작업(우리 자신의 돈을 추적)만을 다루므로 복잡한 OAuth나 다중 역할 계층이 필요하지 않았습니다. 간단한 무상태 JWT 로그인은 앱을 가볍게 유지하고 완전히 우리 통제 하에 두게 합니다.

데모

Bookkeeping

Record the debts that we are lending to other people.


## 구현된 내용  

### Spring Boot 애플리케이션  
- **Java 21**와 **Gradle**로 구축된 견고한 REST API.

### 데이터베이스 모델  

| 모델      | 필드                                                                 |
|------------|------------------------------------------------------------------------|
| **Borrower** | `name`, `email`, `phone`                                            |
| **Loan**     | `amount`, `dateLent`, `dueDate` (대출 후 정확히 1 개월), `status` (`ACTIVE` \| `REPAID`) |

### 핵심 API 엔드포인트  

| Method | Endpoint                     | Description               |
|--------|------------------------------|---------------------------|
| `POST` | `/api/borrowers`             | 새 차용인 생성 |
| `GET`  | `/api/borrowers`             | 모든 차용인 목록 |
| `POST` | `/api/loans`                 | 새 대출 생성 |
| `GET`  | `/api/loans`                 | 모든 대출 목록 |
| `PUT`  | `/api/loans/{id}/repay`      | 대출을 상환 처리 |

### 알림 작업  

- **`NotificationService`**가 매일 **오전 08:00**에 실행됩니다.  
- `dueDate`가 **오늘 또는 이전**인 활성 대출을 조회하고 지정된 개인 Gmail 계정으로 이메일을 전송합니다.

### 시스템 아키텍처 업그레이드  

- **인터페이스 기반 설계** – 서비스 레이어는 느슨한 결합과 확장성을 위해 계약(`BorrowerService`, `LoanService`)을 사용합니다.  
- **데이터 전송 객체 (DTO)** – 모든 API 페이로드는 `BorrowerDto`와 `LoanDto`로 표현됩니다.

## 배운 점  

- **Security & Distributed Environments** – 프런트엔드(Google Cloud Run)와 백엔드(Render)를 분리하면서 교차 도메인 쿠키 처리, 사전 비행 `OPTIONS` 요청, 그리고 브라우저 개인정보 보호 기능을 강조하게 되었습니다.  
- **Multi‑Tenancy & Data Migration** – 사용자 프로필 매핑을 추가하면서 기존 데이터가 “손실된” 것처럼 보였습니다. Gemini와 협업하여 `DataMigrationRunner`를 구축했으며, 이는 시작 시 PostgreSQL에서 고아 레코드를 스캔하고 새로운 외래 키를 통해 다시 연결합니다.  
- **Interactive Debugging** – StackOverflow를 뒤져 보는 대신 로그를 Gemini에 붙여넣음으로써 Nginx Alpine 템플릿 처리 방식을 빠르게 파악하고, 단일 변수 치환 수정으로 `gcloud run deploy` 포트 바인딩 오류를 해결할 수 있었습니다.

## Google Gemini 피드백  

### 잘 작동한 점  
- **Context Retention** – Gemini는 복잡한 파일 구조를 추적하여 `JwtAuthenticationFilter`를 쿠키와 Bearer 토큰 모두를 지원하도록 정밀하게 리팩터링할 수 있었습니다.  
- **Deep Architectural Awareness** – 이는 PostgreSQL 스키마 마이그레이션 및 Cloud Run Nginx 최적화 과정에서 필수적인 역할을 했습니다.  

### 마주친 어려움  
- **Premature Fix Suggestions** – 때때로 Gemini가 프런트엔드 JavaScript 문제(예: 간단한 문자열 보간 오류로 인한 `onclick` 오작동)를 설명하기 전에 백엔드 수정을 제안했습니다.  
- **Superficial Script Loops** – 에이전트가 실제 답변을 제공하기 전에 시스템 작업 경계 검사를 만족시키기 위해 `echo "do something"`와 같은 사소한 내부 스크립트를 실행하는 경우가 있었습니다.
0 조회
Back to Blog

관련 글

더 보기 »

일이 정신 건강 위험이 될 때

markdown !Ravi Mishrahttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...