Daily Chore Tracker API
TypeScript + NestJS 기반의 backend quick-start template이다.
작은 프로젝트에서 자주 등장하는 CRUD / schema design / testing 구조를 보여주는 것을 목표로 한다.
이 서버는 다음 개념을 관리한다.
- User : 서비스를 사용하는 사용자
- Project : 사용자가 생성한 프로젝트
- Chore : 특정 프로젝트에서 특정 날짜에 해야 하는 일 수행 여부
핵심 특징
- TypeScript 기반 NestJS 서버
- pnpm workspace
- Vitest 기반 테스트
- 간단하지만 현실적인 데이터 모델
- 확장 가능한 구조
User
└ Project
└ Chore (date unique per project)
Mermaid ER diagram
erDiagram
USER {
uuid id PK
string email
string name
timestamp created_at
}
PROJECT {
uuid id PK
uuid user_id FK
string title
timestamp created_at
}
CHORE {
uuid id PK
uuid project_id FK
date chore_date
boolean completed
timestamp created_at
}
USER ||--o{ PROJECT : owns
PROJECT ||--o{ CHORE : has
Chore는 다음이 unique
(project_id, chore_date)
이유
- 한 프로젝트에서
- 같은 날짜의 chore는 하나만 존재
POST /projects
request
{
"userId": "uuid",
"title": "Workout Plan"
}response
{
"id": "uuid",
"userId": "uuid",
"title": "Workout Plan"
}POST /chores
request
{
"projectId": "uuid",
"date": "2026-03-14",
"completed": true
}validation
(projectId, date)must be unique
GET /users/:userId/projects
response
[
{
"id": "uuid",
"title": "Workout Plan"
}
]GET /projects/:projectId/chores
response
[
{
"date": "2026-03-14",
"completed": true
}
]src
common
exceptions
logger
users
user.entity.ts
user.repository.ts
projects
project.controller.ts
project.service.ts
project.entity.ts
project.repository.ts
chores
chore.controller.ts
chore.service.ts
chore.entity.ts
chore.repository.ts
테스트는 Vitest 기반으로 작성한다.
목표
- domain logic 검증
- API behavior 검증
import { describe, it, expect } from "vitest"
import { ProjectService } from "./project.service"
describe("ProjectService", () => {
it("creates project", async () => {
const repo = {
save: async (p: any) => ({ id: "p1", ...p }),
}
const service = new ProjectService(repo as any)
const project = await service.createProject({
userId: "m1",
title: "fitness",
})
expect(project.title).toBe("fitness")
})
})import { describe, it, expect } from "vitest"
import { ChoreService } from "./chore.service"
describe("ChoreService", () => {
it("prevents duplicate chore per day", async () => {
const repo = {
findByProjectAndDate: async () => ({ id: "existing" }),
}
const service = new ChoreService(repo as any)
await expect(
service.createChore({
projectId: "p1",
date: "2026-03-14",
completed: true,
})
).rejects.toThrow()
})
})API 테스트
describe("POST /projects", () => {
it("creates project", async () => {
const res = await request(app)
.post("/projects")
.send({
userId: "m1",
title: "study"
})
expect(res.status).toBe(201)
})
})README에서 **“future improvements”**나 **“engineering concerns”**으로 쓰면 좋다.
NestJS DTO validation
class-validator
class-transformer
예
- title length
- valid date format
NestJS
ExceptionFilter
middleware
method
path
duration
POST /chores
같은 요청이 여러 번 오더라도
duplicate creation 방지
GET /projects
GET /chores
?sort=date
예
ProjectNotFoundError
DuplicateChoreError
UserNotFoundError
DB 구현을 쉽게 교체 가능
in-memory
postgres
chore date 문제
UTC normalization
GET /health