
본 서비스는 일정, 할 일, 출퇴근, 파일 공유, 멤버 관리를 하나로 묶어 동아리를 운영하는 서비스입니다.

기존에도 출퇴근을 기록하기 위해 페이지가 운영되고 있었습니다.
바닐라JS로 만들어져 출퇴근 기록 자체는 잘 동작했지만, 추가 기능을 넣기에는 기존 코드가 읽기 어려워 유지보수와 확장성에 한계가 있었습니다.

추가적으로 불편함은 단순히 유지보수하기 어려운 코드에서만 오는 것이 아니였습니다.
매달 지각비를 정산하기 위해서는 두 가지 작업을 수동으로 따로 해야 했습니다.
- 출퇴근 기록 페이지에서 각 멤버의 출근 시간 확인
- 노션에 별도로 근무표에 기재된 멤버의 출근 요일과 시간 확인
이 두 데이터를 직접 총무가 대조하며 얼마나 지각했는지 확인하며, 금액까지 수작업을 정산해야 했습니다. 그러다 보니 멤버 수가 늘어날수록 이 작업은 총무에게 가장 힘든 파트였습니다.

그래서 본 사이트를 통해 현재 문제를 한 번에 해결하는 서비스를 만들기로 했습니다.
- 출퇴근 자동 기록 - 본인이 직접 출근·퇴근 버튼을 눌러 기록
- 개인 근무 스케줄 설정 - 노션 근무표 없이 서비스 내에서 본인 출근 요일·시간 직접 설정
- 관리자 열람 기능 - 팀장·리더가 전체 멤버의 출퇴근 기록을 한번에 조회
- 기간별 CSV 내보내기 - 지각비 정산 시 엑셀로 바로 활용 가능
출퇴근 외에도 일정 관리, 파일 공유, 업무 채팅까지 동아리 운영에 필요한 기능을 하나의 서비스로 묶어 노션, 카카오톡, 별도 출퇴근 페이지를 오가는 불편함을 없애는 것이 최종 목표였습니다.
| 분류 | 기술 |
|---|---|
| UI | React 19 + TypeScript 5 |
| 번들러 | Vite |
| 상태 관리 | React Context API |
| 아키텍처 | FSD (Feature-Sliced Design) |
| 라우팅 | React Router v7 |
| 캘린더 | FullCalendar v6 |
| 애니메이션 | framer-motion |
| 테스트 | Vitest + React Testing Library + MSW |
| 배포 | Vercel |
| 분류 | 기술 |
|---|---|
| Language | Java 21 |
| Framework | Spring Boot 3.5 |
| ORM | Spring Data JPA + QueryDSL 5 |
| DB | PostgreSQL 15 |
| Migration | Flyway 11 |
| Auth | Spring Security 6 + JWT |
| Storage | MinIO |
| Docs | SpringDoc OpenAPI (Swagger UI) |
| Test | JUnit5 + AssertJ + Testcontainers |
| Infra | Docker + Nginx + 온프레미스 서버 (systemd) |
| CI/CD | GitHub Actions |
기술 스택은 단순히 익숙한 도구를 나열하기보다, 유지보수성과 확장성, 그리고 실제 운영 경험까지 고려해 선택했습니다.
복잡한 조회가 필요한 출퇴근 기능에는 QueryDSL을 적용했고, 테스트 환경은 Testcontainers 기반으로 구성해 운영 DB와 최대한 유사한 환경에서 검증할 수 있도록 했습니다.
기술 선정 이유와 아키텍처 설계 배경은 별도 글에서 더 자세히 정리했습니다. 👉 [링크 추가 예정]
이 프로젝트의 프론트엔드는 AI 도구와 함께 개발했습니다.
단순히 코드 생성을 맡기는 방식이 아니라 개발 흐름에 맞는 지침을 각각 지정하여 FSD 구조 규칙, TDD 순서, 커밋 컨벤션, MSW 사용 원칙 등을 문서화해두고 그 기준 안에서 작업이 이뤄지도록 했습니다.
백엔드 개발자 2명이 프론트엔드까지 함께 병행해야 하는 상황이었기 때문에 반복적인 구현은 AI의 도움을 받고 설계 판단과 리뷰에는 사람이 집중하는 방식으로 생산성을 높였습니다.
이 과정을 통해 느낀 점은 AI를 잘 활용하려면 오히려 구조와 기준을 더 명확하게 설계해야 하며 맥락과 제약이 분명할수록 결과물의 품질이 상승했고 그 기준을 문서화하는 과정 자체가 프로젝트 설계를 정리하는 작업이 되었습니다.
가장 큰 기술적 과제는 관리자용 출퇴근 조회 기능이었습니다.
이 기능은 단순히 출퇴근 기록만 보여주는 것이 아니라 멤버 정보와 개인별 근무 스케줄, 날짜 범위 조건을 함께 조합해 지각 여부까지 확인할 수 있어야 했습니다. 처음에는 JPA 기본 방식으로 접근했지만, 조건이 늘어날수록 조회 로직이 복잡해지고 유지보수도 어려워졌습니다.
이 문제를 해결하기 위해 단순 CRUD와 복잡 조회를 분리하고, 관리자 조회 기능은 QueryDSL 기반의 동적 쿼리로 재구성했습니다.
그 결과 팀, 기간, 멤버 조건이 조합되는 조회를 타입 안전하게 처리할 수 있었고 이후 필터가 추가되더라도 문자열 기반 쿼리를 수정하는 부담 없이 확장할 수 있었습니다.
이 경험을 통해 조회 기능은 “엔티티를 가져오는 것”보다 “어떤 화면과 운영 요구사항을 만족시켜야 하는가”를 기준으로 설계해야 한다는 점을 배웠습니다.
매달 총무가 수작업으로 처리하던 지각비 정산이 CSV 내보내기로 대체됐고, 현재 동아리 멤버 전원이 실사용 중입니다. 노션·카카오톡·별도 출퇴근 페이지로 분산되어 있던 운영 흐름이 하나의 서비스로 통합됐습니다.
현재 프로젝트를 진행하며 단순히 기능을 구현한다는 방면으로 끝내지 않았습니다.
실제로 내가 겪고 있는 문제점과 불편했던 문제를 정의하며 그 문제를 서비스 구조로 어떻게 풀어내는 경험을 겼었습니다.
출퇴근 기록과 근무표를 하나의 시스템 안에서 관리하도록 하여 단순하게 기능을 만들어 내는 것 보다는 운영 흐름을 설계하는 점을 크게 배울 수 있었습니다.
그리고 지금 뜨거운 감자인 바이브 코딩을 통해 어떻게 AI를 활용해야 할 지에 대해서 분명히 알게 될 수 있었고 프론트엔드, 백엔드, 테스트, 배포까지 전반을 직접 다루면서 하나의 서비스를 끝까지 운영 가능한 형태로 만드는 중요한 경험을 쌓을 수 있었습니다.
현재로서는 출퇴근, 근무표, 드라이브, 팀 관리 기능만 구현되어 있지만 드라이브의 문서로로 RAG기반 LLM 채팅 서비스를 구현하여 팀 프로젝트가 무엇을 하고 있는지 yANUs란 동아리가 무엇인지에 대해서 알려주는 기능을 구현하는 것과 채팅 기능을 구현하는 것을 목표에 두고 있습니다.
긴 글을 읽어주셔서 감사합니다 !! ☺️
실제 서비스 링크 : yANUs-groupware
프론트엔드 레포지토리 : https://github.com/Yanus306/yanus-groupware
백엔드 레포지토리 : https://github.com/Yanus306/yanus-groupware-BE
자바 형님 화이팅