1. 프로젝트 개요
Memory Calendar는 사용자가 작성한 메모에서 AI가 일정 정보를 추출하고, 사용자가 확인한 일정만 캘린더에 저장하는 개인 기록·일정 관리 프로젝트다.
초기 목표는 개인적으로 실제 사용할 수 있는 MVP를 만드는 것이고, 이후에는 다중 사용자 구조와 기록 검색 기능까지 확장할 계획이다.
1일차에는 기능 구현보다 프로젝트 개발 기반을 만드는 것에 집중했다.
구성은 다음과 같이 잡았다.
memory-calendar/
├── frontend/
├── backend/
├── .env.example
├── .gitignore
└── README.md
2. Git Repository 구조와 Frontend / Backend 디렉터리 설계
Frontend와 Backend를 별도 Repository로 분리하지 않고 하나의 Repository에서 관리하기로 했다.
memory-calendar/
├── frontend/
└── backend/
현재 프로젝트는 개인 프로젝트이고 Frontend와 Backend가 하나의 서비스 단위로 같이 변경될 가능성이 높다.
예를 들어 메모 작성 기능을 구현하면 보통 아래 작업이 동시에 발생한다.
frontend ── 메모 작성 화면 / API 요청
backend ── 메모 생성 API / 비즈니스 로직
Repository를 분리하면 하나의 기능을 구현하더라도 두 Repository에서 브랜치와 커밋을 따로 관리해야 한다
현재 규모에서는 그럴 필요가 없다고 판단해 하나의 Repository 안에서 관리하는 구조로 시작했다.
3. Frontend 구성
이번 프로젝트에서 나는 Frontend보다 Backend에 익숙한 편이기 때문에,
Frontend 기술을 선택할 때도 새로운 기술을 많이 조합하기보다는
자료가 많고 기본 기능이 잘 갖춰져 있어 최대한 단순하게 개발할 수 있는 구성을 우선했다.
React만 사용해서 직접 프로젝트 구조나 라우팅 등을 하나씩 구성하는 것보다
Next.js를 사용하면 프로젝트 생성 단계에서 필요한 기본 환경을 대부분 준비할 수 있다.
또한 페이지 라우팅, Layout 등의 구조가 프레임워크 차원에서 정해져 있기 때문에
Frontend 경험이 많지 않은 입장에서도 프로젝트 구조를 잡기가 비교적 쉽다고 판단했다.
pnpm create next-app@latest frontend
생성 시 주요 설정은 다음과 같다
TypeScript → Yes
ESLint → Yes
React Compiler → No
Tailwind CSS → Yes
src/ directory → Yes
App Router → Yes
Import Alias → @/*
AGENTS.md → Yes
pnpm
패키지 매니저는 npm 대신 pnpm을 사용했다.
pnpm은 npm과 같은 Node.js 패키지 매니저지만,
설치한 패키지를 공용 저장소에 보관한 뒤 프로젝트에서 재사용하는 방식을 사용한다.
따라서 여러 프로젝트에서 동일한 패키지를 사용할 때 불필요한 중복을 줄일 수 있다.
이번 프로젝트에서 pnpm이 반드시 필요한 것은 아니지만,
설치와 명령 체계가 npm과 크게 다르지 않으면서 패키지 관리가 효율적이기 때문에 사용하기로 했다.
Frontend 개발 과정에서 사용하는 명령도 pnpm으로 통일한다.
pnpm install
pnpm dev
pnpm lint
pnpm build
TypeScript
JavaScript 대신 TypeScript를 사용하도록 설정했다.
Frontend에 익숙하지 않은 상태에서는 오히려 자유도가 높은 JavaScript보다 타입을 명시할 수 있는 TypeScript가 개발하기 편하다고 판단했다.
앞으로 Backend API에서 다음과 같은 데이터를 받아 사용하게 된다.
User
Note
Event
예를 들어 일정 데이터를 TypeScript 타입으로 정의하면 어떤 값이 들어있는지 IDE에서 바로 확인할 수 있다.
type Event = {
id: number;
title: string;
startAt: string;
endAt: string;
};
잘못된 타입의 값을 사용하면 실행하기 전에 IDE나 컴파일 과정에서 확인할 수도 있고, 자동완성도 활용할 수 있다.
ESLint
ESLint도 활성화했다.
Frontend에 익숙하지 않으면 작성한 코드가 단순히 문법적으로 실행되는 것과, React/Next.js에서 적절하게 작성된 코드를 구분하기 어려울 수 있다.
ESLint를 사용하면 문제가 될 수 있는 코드나 기본적인 작성 실수를 개발 중에 확인할 수 있기 때문에 사용하기로 했다.
기본 실행 검증
프로젝트 생성 후 바로 기능 구현을 시작하지 않고 기본 상태가 정상인지 먼저 확인했다.
pnpm dev
localhost:3000에서 Next.js 기본 화면이 정상적으로 실행되는 것을 확인했다.
이후 다음 명령도 실행했다.
pnpm lint
pnpm build
두 명령 모두 정상적으로 통과했다.
Frontend에 익숙하지 않은 만큼 문제가 생겼을 때 원인을 기능 코드에서 찾아야 하는지 프로젝트 설정에서 찾아야 하는지 혼동하지 않도록, 아무 기능도 추가하지 않은 초기 상태에서 실행·lint·build가 모두 성공하는 것을 먼저 확인했다.
결과적으로 Frontend는 새로운 기술을 많이 적용하기보다는 Next.js가 제공하는 기본 설정을 최대한 활용하고, 개발자가 직접 관리해야 하는 부분을 줄이는 방향으로 구성했다.
4. Backend 구성
Backend는 Spring Boot + Java 21 + Gradle로 구성했다.
Spring Initializr에서 다음과 같이 생성했다.
Project → Gradle
Language → Java
Spring Boot → 4.1.0
Java → 21
Packaging → Jar
Group → com.memorycalendar
Artifact → backend
Package → com.memorycalendar
초기 Dependency는 필요한 것만 추가했다.
Spring Web
Validation
Spring Boot DevTools
1일차에는 프로젝트 실행 환경을 만드는 것이 목적이기 때문에 JPA, PostgreSQL, Security 등은 미리 추가하지 않았다.
Spring Data JPA
PostgreSQL Driver
Flyway
Spring Security
필요한 시점에 하나씩 추가해서 설정과 역할이 불필요하게 섞이지 않도록 진행할 예정이다.
패키지 구조
최상위 패키지는 기능 단위로 구분했다.
com.memorycalendar
├── global
├── auth
├── user
├── note
├── event
└── ai
controller, service, repository, dto처럼 계층을 최상위에 두는 대신 note, event, auth 등 도메인별로 먼저 구분하는 구조로 잡았다.
예를 들어 메모 기능을 구현할 때는 다음처럼 확장할 예정이다.
note/
├── controller/
├── service/
├── repository/
├── domain/
└── dto/
아직 사용하지 않는 하위 패키지는 미리 만들지 않고 기능 구현 시점에 추가한다.
Health API
Spring Boot 프로젝트가 HTTP 요청까지 정상적으로 처리하는지 확인하기 위해 간단한 Health API를 추가했다.
GET /api/health
@RestController
@RequestMapping("/api")
public class HealthController {
@GetMapping("/health")
public ResponseEntity<Map<String, String>> health() {
return ResponseEntity.ok(Map.of("status", "ok"));
}
}
요청 결과:
{
"status": "ok"
}
마지막으로 테스트와 빌드까지 확인했다.
./gradlew test
./gradlew build
둘 다 BUILD SUCCESSFUL로 완료되어 Backend 초기 구성을 마무리했다.