21 KiB
개인 가계부 PWA 개발 요구사항
1. 프로젝트 목표
NAS의 Docker 환경에서 직접 운영할 개인용 가계부 웹앱을 개발한다.
주 사용 환경은 PC가 아니라 스마트폰이므로 모바일 UX를 가장 우선해서 설계한다. 일반 반응형 웹이 아니라 설치 가능한 PWA를 지원해야 한다.
앱을 홈 화면에 설치한 뒤 일반 모바일 앱처럼 사용할 수 있어야 하며, 실행할 때마다 로그인을 반복해야 하는 불편이 없도록 로그인 상태가 안정적으로 유지되어야 한다.
전체적인 방향은 복잡한 자산관리·재무관리 서비스가 아니라,
빠르게 기록하고 → 나중에 기간별/분류별로 확인하는 가계부
에 집중한다.
2. 핵심 원칙
기능을 불필요하게 복잡하게 만들지 않는다.
특히 일반적인 가계부에서 제공하는 아래 기능은 필요 없다.
- 계좌이체
- 복식부기
- 카드 대금 결제 처리
- 카드 청구 예정금액
- 카드 결제일에 맞춘 지출 이동
- 은행 계좌 자동 연동
- 카드사 자동 연동
- 투자/주식/자산 가치 추적
- 예산 관리
- 그래프/차트
- 복잡한 회계 기능
신용카드로 결제했더라도 사용한 날짜에 바로 지출한 것으로 처리한다.
예:
8월 13일 신용카드로 30,000원 사용
→ 8월 13일 지출 30,000원
카드 결제일에 다시 어떠한 거래도 생성하지 않는다.
할부 역시 특별한 카드 기능으로 구현하지 않는다.
예:
120,000원 / 3개월 할부
8월 40,000원
9월 40,000원
10월 40,000원
처럼 매월 반복되는 지출 거래로 처리하면 된다.
3. 기술 방향
구현 기술은 유지보수성과 Docker 배포를 고려해서 선택한다.
권장 예시:
Frontend / Fullstack
Nuxt 3 + Vue 3 + TypeScript
Database
PostgreSQL
Deployment
Docker Compose
PWA
Nuxt PWA 계열 또는 동등한 방식
Responsive
Mobile First
반드시 이 기술을 사용할 필요는 없지만, 특별한 이유가 없다면 이 구성을 우선 고려한다.
데이터베이스는 장기간 사용할 예정이므로 SQLite가 아니라 PostgreSQL을 기본 DB로 사용한다.
4. PWA 요구사항
모바일에서 사실상 앱처럼 사용할 수 있어야 한다.
필수 요구사항:
- 홈 화면 설치 가능
- 앱 아이콘
- Standalone 모드
- 모바일 전체 화면에 가까운 UI
- 로그인 상태 유지
- 페이지 새로고침 후에도 인증 유지
- PWA로 다시 실행해도 로그인 유지
- Android / iOS 모바일 브라우저 대응
- 반응형 PC 화면 지원
단, 현재 단계에서는 복잡한 Offline First 기능이나 오프라인 상태에서의 거래 동기화까지 구현할 필요는 없다.
5. 거래 종류
거래 종류는 2개만 존재한다.
수입
지출
이체라는 거래 타입은 만들지 않는다.
사용자가 어떤 계좌로 돈을 이동했는지와 실제 지출인지 판단하기 애매해질 수 있기 때문이다.
6. 거래 입력 항목
수입과 지출 모두 기본 구조는 동일하다.
6.1 날짜
거래가 발생한 날짜와 시간을 저장한다.
기본값:
현재 날짜 / 현재 시간
날짜 옆에는 반복 설정 버튼을 둔다.
6.2 반복
필요한 경우 거래를 반복 생성할 수 있도록 한다.
예:
KT 통신요금
매월 13일
36,300원
또는
Patreon Membership
매월 12일
23,642원
반복 거래는 최소한 아래 정도를 고려한다.
반복 없음
매일
매주
매월
매년
할부를 표현할 수 있도록 반복 횟수 또는 종료일도 설정할 수 있으면 좋다.
예:
매월
3회 반복
= 3개월 할부와 동일한 방식으로 사용 가능.
복잡한 신용카드 할부 기능을 별도로 만들지는 않는다.
자산 타입 요구사항 추가
7. 자산
각 거래에는 반드시 자산을 지정할 수 있어야 한다.
여기서 자산은 단순히 은행 계좌나 카드의 종류를 표현하는 것이 아니라, 수입/지출을 어떤 기준으로 집계하고 잔액을 보여줄 것인지 결정하는 단위다.
예:
현금
생활비
공동생활비
현대카드
개인용
여행비
자산에는 반드시 아래 두 가지 계산 타입 중 하나를 지정한다.
7.1 누적형 자산
Cumulative Asset
이전 기간의 잔액이 계속 다음 기간으로 이어지는 일반적인 자산이다.
예:
8월 1일 시작 잔액 1,000,000원
8월 수입 +500,000원
8월 지출 -300,000원
8월 말 잔액
1,200,000원
↓
9월 1일 시작 잔액
1,200,000원
즉 모든 거래가 계속 누적된다.
주로 다음과 같은 용도로 사용할 수 있다.
은행 계좌
현금
저축 계좌
장기 생활비
개인 자산
잔액 계산 개념:
현재 잔액
= 최초 잔액
+ 전체 수입
- 전체 지출
사용자는 자산 생성 시 최초 잔액을 입력할 수 있어야 한다.
최초 잔액 기본값은 0원이다.
7.2 월별 초기화형 자산
Monthly Reset Asset
매월 새로운 기간이 시작되면 표시 잔액을 0원부터 다시 계산하는 자산이다.
이전 달의 잔액은 다음 달로 이월하지 않는다.
예:
8월
수입 1,000,000원
지출 700,000원
8월 잔액
300,000원
그러나 9월이 시작되면:
9월 1일
시작 잔액
0원
으로 다시 시작한다.
8월에 실제로 300,000원이 남아 있더라도 9월 화면에는 이를 이월하지 않는다.
이 타입은 실제 금융계좌의 잔액을 추적하기보다 해당 월에 얼마를 벌고 얼마를 사용했는지 독립적으로 관리하고 싶은 경우를 위한 것이다.
예:
월 생활비
개인 용돈
공동 생활비
취미비
카드 사용액
프로젝트 비용
월별 표시 잔액 계산:
해당 월 잔액
= 해당 월 수입
- 해당 월 지출
중요:
실제 데이터를 매월 삭제하거나 자산의 DB 잔액 값을 0으로 변경하는 방식으로 구현하지 않는다.
거래 데이터는 그대로 영구 보존한다.
화면에서 잔액을 계산할 때 해당 월의 시작일부터 마지막 날까지의 거래만 조회하여 계산한다.
따라서 과거 월의 데이터와 잔액 역시 언제든 다시 조회할 수 있어야 한다.
7.3 자산 생성 UI
자산 생성/수정 시 다음 설정을 제공한다.
자산 이름
계산 방식
○ 누적형
○ 월별 초기화형
최초 잔액
[ 원 ]
최초 잔액은 누적형에서만 의미가 있다.
월별 초기화형에서는 최초 잔액을 사용하지 않거나 항상 0원으로 처리한다.
사용자가 이해하기 쉽도록 UI에서는 기술적인 명칭보다 다음 표현을 우선한다.
잔액 계산 방식
● 계속 누적
이전 달의 잔액을 계속 이어갑니다.
○ 매월 새로 시작
매월 1일 잔액을 0원부터 계산합니다.
신용카드, 체크카드, 은행계좌 같은 고정된 자산 종류를 시스템이 강제하지 않는다.
사용자가 어떤 이름의 자산이든 자유롭게 만들고 해당 자산의 잔액 계산 방식만 선택하도록 한다.
예를 들어 같은 현대카드라도 사용자의 취향에 따라:
현대카드
→ 계속 누적
또는
현대카드
→ 매월 새로 시작
으로 설정할 수 있어야 한다.
7.4 자산 타입 변경
이미 거래가 존재하는 자산에서도 계산 방식을 변경할 수 있도록 한다.
단, 변경 시 거래 데이터 자체는 수정하지 않는다.
예:
누적형
→ 월별 초기화형
으로 변경하면 기존 거래는 그대로 두고 이후 조회 시 잔액 계산 방식만 변경한다.
반대로:
월별 초기화형
→ 누적형
으로 변경하면 전체 기간 거래를 기준으로 다시 누적 잔액을 계산한다.
계산 방식 변경은 데이터 손실을 발생시키지 않아야 한다.
7.5 전체 자산 합계
전체 자산을 보여줄 때는 두 타입의 의미가 다르므로 주의한다.
누적형 자산은 실제 누적 잔액으로 계산한다.
월별 초기화형 자산은 현재 조회 중인 월의 잔액으로 계산한다.
예:
2026년 8월
국민은행 3,200,000원 [누적]
현금 150,000원 [누적]
생활비 420,000원 [월별]
개인용돈 -80,000원 [월별]
전체 합계를 제공한다면 현재 화면에서 계산된 각 자산 값을 합산한다.
다만 누적형과 월별 초기화형은 의미가 서로 다르므로 가능하면 UI에서 타입을 구분해서 보여준다.
8. 분류 / 카테고리
수입과 지출은 서로 완전히 다른 카테고리 목록을 가진다.
카테고리는 최대 2 Depth 구조를 지원한다.
예를 들어 수입:
근로
├─ zenn
└─ 배우자
사업
├─ A 프로젝트
└─ B 프로젝트
기타수입
├─ 중고판매
└─ 환급
지출:
주택환경 개선
├─ 가전제품
├─ 가구
└─ 인테리어
식비
├─ 외식
├─ 배달
└─ 장보기
통신
├─ 휴대폰
└─ 인터넷
DB상으로는 부모 카테고리를 갖는 구조로 설계하되 현재 UI에서는 최대 2단계까지만 허용한다.
카테고리는 사용자가 직접:
추가
수정
순서 변경
비활성화
할 수 있도록 한다.
기존 거래가 존재하는 카테고리는 데이터 손실을 막기 위해 가급적 완전 삭제보다 비활성화를 우선한다.
9. 금액
금액은 정수 기준으로 입력한다.
대한민국 원화 사용을 우선으로 한다.
입력 시:
14980
이라고 입력하면 화면에는
14,980원
처럼 표시한다.
10. 내용
내용은 거래의 대표 제목이다.
즉 거래 목록에서 가장 크게 표시되는 항목이다.
예:
이마트칠성점
네이버페이 - 알라딘
Patreon Membership
파스쿠찌대명역점
KT통신요금자동납부
월급
프로젝트 정산
단순한 메모가 아니라 거래처 / 소비처 / 수입원 등을 표현하는 핵심 제목으로 사용한다.
11. 위치정보
모바일에서 거래를 입력하는 경우 현재 위치를 자동으로 가져올 수 있도록 한다.
브라우저의 Geolocation API 등을 사용한다.
저장 정보 예:
latitude
longitude
위치정보는 강제가 아니다.
사용자는 거래 작성 화면에서 위치정보 옆의 삭제 버튼을 눌러 위치를 제거할 수 있어야 한다.
위치가 저장된 거래를 조회할 때는 위치를 눌러 대략적인 위치를 확인할 수 있도록 한다.
초기 버전에서는 별도의 지도 서비스를 앱 안에 복잡하게 구현하지 않아도 된다.
예를 들어:
위치 보기
→ Google Maps 등으로 해당 좌표 열기
정도도 충분하다.
위치 권한이 거부된 경우 거래 입력 자체에는 아무런 문제가 없어야 한다.
12. 메모
사용자가 자유롭게 긴 내용을 기록할 수 있는 메모 영역을 제공한다.
예:
할인쿠폰 5,000원 사용
아이와 같이 방문
다음번에는 온라인 구매
메모에는 사진 첨부 기능을 지원한다.
사진은 PostgreSQL DB에 binary로 직접 저장하지 말고 파일 스토리지에 저장하고 DB에는 파일 정보 및 경로만 기록하는 방향으로 설계한다.
하나의 거래에 여러 사진을 첨부할 수 있도록 구조적으로 확장 가능한 형태가 좋다.
13. 거래 입력 UI
첨부한 두 번째 이미지의 입력 화면 구조를 참고한다.
상단에는 명확하게:
수입 | 지출
선택 영역을 둔다.
이체 탭은 존재하지 않는다.
입력 화면의 기본 순서는 다음과 같이 한다.
[ 수입 ] [ 지출 ]
날짜 반복
자산
분류
금액
내용
위치 삭제
────────────────────
메모
사진 첨부
저장하기
모바일에서 한 손으로 빠르게 입력할 수 있어야 한다.
거래 한 건을 기록하기 위해 화면을 여러 페이지 이동하게 만들지 않는다.
가능하면 한 화면 또는 최소한의 스크롤 안에서 완료할 수 있도록 한다.
저장 버튼은 충분히 크고 모바일 하단에서 누르기 편해야 한다.
14. 거래 목록 화면
첨부한 첫 번째 이미지의 구성과 사용성을 참고한다.
화면 상단에는 현재 조회 중인 기간을 표시한다.
예:
‹ 2026년 8월 ›
모바일에서는 날짜 이동을 빠르게 할 수 있도록 최근 날짜를 가로로 보여주는 방식도 좋다.
예:
일 월 화 수 목 금 토
9 10 11 12 13 14 15
4,000 99,450 37,200 167,692 4,300 ...
선택된 날짜 아래에는 해당 날짜의 거래 목록을 보여준다.
거래 한 건의 기본 표시:
[아이콘] 이마트칠성점 14,980원
19:55 · 현대카드
주택환경 개선 > 생활용품
또는 필요한 정보량에 맞춰 조금 더 단순화해도 된다.
중요도 순서는:
1. 내용
2. 금액
3. 시간
4. 자산
5. 카테고리
이다.
거래 목록은 지나치게 카드 UI로 분리하지 말고 첨부 이미지처럼 밀도 높고 빠르게 훑어볼 수 있는 리스트 형태를 우선한다.
15. 조회 기간
가계부 데이터는 아래 기간 단위로 확인할 수 있어야 한다.
월
분기
반기
연도
예:
2026년 8월
2026년 3분기
2026년 하반기
2026년
각 기간마다 최소한 다음 숫자를 보여준다.
총 수입
총 지출
차액
예:
2026년 8월
수입 5,200,000원
지출 2,314,500원
──────────────────
차액 2,885,500원
그래프는 필요 없다.
숫자와 목록을 깔끔하게 보여주는 것에 집중한다.
16. 분류별 조회
기간별 전체 수입/지출뿐만 아니라 카테고리별 합계를 확인할 수 있어야 한다.
예:
2026년 8월 지출
식비 420,000원
├ 외식 180,000원
├ 배달 140,000원
└ 장보기 100,000원
주택환경 개선 310,000원
├ 가전제품 250,000원
└ 생활용품 60,000원
통신 102,600원
항목을 누르면 해당 카테고리에 속하는 실제 거래 목록으로 이동한다.
수입도 동일한 구조를 사용한다.
17. 검색 / 필터
거래가 장기간 쌓이는 것을 고려해 기본 검색 기능을 제공한다.
검색 가능한 주요 항목:
내용
메모
필터:
기간
수입 / 지출
자산
대분류
소분류
금액 범위
정렬은 기본적으로 최신 거래가 위로 오도록 한다.
18. 데이터 모델 초안
최소한 다음 Entity 정도로 시작한다.
User
Asset
Category
Transaction
TransactionAttachment
RecurringTransaction
Transaction의 개념적인 구조:
id
type
- income
- expense
occurredAt
assetId
categoryId
amount
title
latitude
longitude
memo
createdAt
updatedAt
Category:
id
type // income / expense
name
parentId
sortOrder
active
최대 2 Depth.
Attachment:
id
transactionId
fileName
filePath
mimeType
size
createdAt
반복 거래 정의와 실제 발생한 거래는 분리하는 것을 권장한다.
19. 데이터 안전성
이 앱은 수년~수십 년간 데이터를 저장할 수 있으므로 UI보다 데이터 보존을 중요하게 생각한다.
반드시 고려할 것:
PostgreSQL 영속 볼륨
첨부파일 영속 볼륨
DB migration 관리
Transaction 삭제 시 안전장치
기존 Category/Asset 삭제 시 데이터 보존
정기 백업 가능한 구조
CSV Export
특히 서비스가 나중에 없어지더라도 데이터를 가져갈 수 있도록 전체 거래 CSV Export 기능을 반드시 넣는다.
가능하면 Import 역시 향후 추가하기 쉬운 구조로 만든다.
20. 디자인 방향
첨부 이미지의 장점은 참고하되 그대로 복제하지 않는다.
원하는 느낌:
- 흰색 중심의 깔끔한 화면
- 지나치게 장식적이지 않음
- 모바일 네이티브 앱처럼 자연스러운 UI
- 충분한 여백
- 숫자의 가독성 중시
- 거래 목록은 정보 밀도가 높음
- 큰 카드가 화면을 과도하게 차지하지 않음
- 둥근 모서리를 남발하지 않음
- 필요한 곳에만 포인트 컬러 사용
- 수입/지출 상태를 색상만으로 구분하지 않음
- 모바일 터치 영역은 충분히 크게 확보
- 하단 네비게이션 사용 가능
추천 메인 메뉴는 대략:
내역
추가
통계
설정
정도로 단순하게 유지한다.
통계라는 이름을 사용하더라도 그래프는 만들 필요 없다.
21. 모바일 UX에서 특히 중요하게 볼 것
거래 입력 빈도가 높은 앱이므로 입력 속도를 최우선으로 한다.
가능하면 다음과 같은 UX를 고려한다.
마지막으로 사용한 자산 기억
최근 사용 카테고리 빠른 선택
최근 입력했던 거래 내용 제안
숫자 입력 시 숫자 키패드 자동 표시
저장 후 바로 다음 거래 입력 가능
날짜 기본값 현재 시각
위치 자동 입력
단, 자동완성 기능이 오입력을 만들어서는 안 되므로 최종 저장 값은 사용자가 명확하게 확인할 수 있어야 한다.
22. 초기 개발 범위
처음부터 모든 기능을 구현하지 말고 다음 순서로 진행한다.
Phase 1
프로젝트 기본 구조
PostgreSQL 연결
로그인
PWA
자산 관리
카테고리 관리
수입/지출 CRUD
모바일 거래 입력 화면
거래 목록
월별 조회
Phase 2
분기 / 반기 / 연도 조회
카테고리별 집계
검색 / 필터
위치정보
사진 첨부
Phase 3
반복 거래
할부에 사용할 수 있는 횟수 제한 반복
CSV Export
백업 편의 기능
UX 개선
23. 구현 시 가장 중요한 금지사항
기능을 추가하면서 일반 금융앱처럼 복잡하게 만들지 않는다.
다음과 같은 판단은 하지 말 것.
신용카드니까 부채 계좌를 만들어야 한다.
카드 결제일 거래가 필요하다.
이체 기능이 일반적이니 넣어야 한다.
가계부니까 예산 기능이 필요하다.
통계니까 그래프를 넣어야 한다.
자산마다 잔액 정산 로직이 필요하다.
이 프로젝트는 회계 프로그램이 아니다.
사용자가 실제로 돈을 얻거나 사용한 사실을 빠르게 기록하고, 나중에 기간/자산/카테고리별 숫자를 확인하는 것이 목적이다.
24. 개발 진행 방식
바로 전체 기능을 한꺼번에 구현하지 말고 먼저:
- 전체 Architecture와 DB Schema를 제안한다.
- 모바일 화면 구조와 Route 구성을 제안한다.
- 구현에 들어가기 전에 불명확하거나 충돌하는 요구사항이 있으면 정리한다.
- 그 다음 Phase 1부터 개발한다.
UI를 구현할 때에는 첨부한 두 이미지를 정보 구조와 모바일 사용성 참고자료로 활용한다.
첫 번째 이미지는 거래 내역 조회 화면, 두 번째 이미지는 수입/지출 입력 화면의 주요 레퍼런스다.
완전히 동일하게 복제하지 말고 이 프로젝트에 맞게 더 깔끔하고 현대적인 디자인으로 재구성한다.
데이터 모델 반영
Asset에는 최소 다음 필드를 고려한다.
Asset
id
name
balanceType
- cumulative
- monthly_reset
initialBalance
active
sortOrder
createdAt
updatedAt
balanceType의 의미:
cumulative
→ 모든 기간의 거래가 누적됨
monthly_reset
→ 조회 중인 월의 거래만 이용해 잔액 계산
중요:
DB에 현재 잔액을 직접 저장하고 거래 발생 때마다 값을 증감시키는 구조를 가급적 피한다.
기본적으로 거래 데이터가 Source of Truth가 되도록 하고 잔액은 거래 합계를 통해 계산한다.
필요한 경우 성능 개선을 위한 캐시 또는 집계 테이블은 추후 추가할 수 있지만, 초기 구현에서는 데이터 정확성과 단순성을 우선한다.