| marp | true |
|---|---|
| theme | default |
| paginate | true |
| size | 58140 |
| title | Deck Onboarding |
| description | Deck 신규 개발자 온보딩 슬라이드 |
신규 개발자 빠른 적응 가이드
- Monorepo: Frontend + Backend + Infra
- Service split:
app/meetpie/deskpie - Local-first 개발 흐름
멀티서비스 운영 플랫폼입니다.
app: 공통 백오피스(control-plane)- 인증/권한, 사용자/메뉴, 알림, 감사/에러 로그, 워크스페이스
meetpie: 비즈니스 도메인(data-plane)- 일정 연동, 예약(Booking), 명함(Contacts), 관계 인텔리전스, 공휴일 구독
deskpie: 확장 도메인(data-plane)- 라이선스 관리, CRM (개발 중)
서비스 무관 공통 기능은 반드시 app에 배치. meetpie/deskpie에는 해당 도메인 코드만.
deck/
├── frontend/ # app, meetpie, deskpie (Vite + React)
├── backend/ # modular monolith (Kotlin + Spring Boot)
├── docs/ # reference / rules / plans
├── scripts/ # standards, github, 운영 스크립트
├── deploy/ # 배포 설정 / SBOM 산출물
└── monitoring/ # Grafana / Prometheus / Loki 설정
핵심 문서
- 아키텍처:
docs/reference/architecture.md - FE 규칙:
docs/reference/frontend.md - BE 규칙:
docs/reference/backend.md - Meetpie:
docs/reference/meetpie.md
- React 19 + TypeScript + Vite (SPA)
- Tailwind CSS v4 + shadcn/ui (Radix)
- React Hook Form + zod
- Vitest + Playwright
- Kotlin 2.3 + Spring Boot 4 + Java 25
- PostgreSQL + Flyway
- DDD 레이어 + Spring Modulith 검증 테스트
- JWT ES256 + HttpOnly Cookie
brew install mise humanlog
mise install
pnpm --dir frontend install
docker compose up -d핵심 포트
- Frontend:
4011 - Backend:
8011 - PostgreSQL:
5011
기본 로그인: admin@deck.io / Deck@dm1n!
(최초 로그인 시 비밀번호 변경 필요)
- FE:
pnpm --dir frontend/app dev - BE:
./backend/gradlew -p backend :dist:app:bootRun 2>&1 | humanlog
- FE:
pnpm --dir frontend/meetpie dev - BE:
./backend/gradlew -p backend :dist:meetpie:bootRun 2>&1 | humanlog
- FE:
pnpm --dir frontend/deskpie dev - BE:
./backend/gradlew -p backend :dist:deskpie:bootRun 2>&1 | humanlog
레이어 의존 방향: pages → features → entities → shared
| 레이어 | 역할 | 경로 |
|---|---|---|
pages |
화면 조합 + 흐름 제어 | src/pages/ |
features |
비즈니스 상태 + 액션 | src/features/ |
entities |
API 계약 (api.ts + types.ts) | src/entities/ |
shared |
공통 UI + 인프라 | src/shared/ |
MUST NOT: features에서 pages/layouts/widgets import 금지
RHF (React Hook Form)
- 폼 source of truth는 RHF 하나만
- 제출은
handleSubmit경유, DOM 우회 금지 - 편집 초기값 로딩은
reset()사용
DOM 제어 원칙
- React가 렌더링한 요소 → React(props/hooks)로만 제어
- 조건부 렌더링 게이트 안의 요소에
useEffect에서querySelector접근 금지
에러 메시지 (FE-ERR-001)
// ✅ 올바른 패턴
} catch (e) {
toastError(e instanceof ApiError ? e.message : 'Unexpected error');
}레이어: Controller → Service → Domain/Repository
| 레이어 | 책임 |
|---|---|
Controller |
얇게 유지, Service 호출만, @PreAuthorize 필수 |
Service |
유스케이스 조합, Domain Event 발행 |
Domain/Entity |
상태 변경 캡슐화 (메서드로만) |
Repository |
컬렉션 수준 쿼리 |
부수효과는 이벤트로 분리
// Service에서 이벤트 발행 → @TransactionalEventListener(AFTER_COMMIT)backend/
├── app/ # composition root (config, filter, listener, scheduler)
├── iam/ # User, Auth, Menu, OAuth2
├── crypto/ # KEK/DEK Envelope Encryption, JWT JWK
├── notification/ # Email, Slack, Webhook (채널/룰/템플릿)
├── audit/ # 감사 로그
├── meetpie/ # 명함, 일정, 예약, 관계 인텔리전스
├── deskpie/ # 라이선스 관리
├── common/ # SoftDeleteEntity, HardDeleteEntity, 공통 유틸/예외/이벤트
├── mcp/ # MCP Server (확장 예정)
└── dist/ # 서비스별 패키징 (app / meetpie / deskpie)
- JWT ES256 + HttpOnly 쿠키 (Stateless, 1시간 만료)
- INTERNAL + OAuth2 (Google, Auth0, Okta, Microsoft, AIP 등)
- TOTP 2FA + 백업 코드 10개
- Role은 권한 관리에 사용하지 않는다 — 사용자 분류용, 동적 생성 가능
- 권한은 Menu.permissions 기반 — 관리자가 메뉴별로 할당
User.roleIds → Role별 Menu → Menu.permissions → GrantedAuthority
// 1. PermissionRegistrar — 권한 코드 정의
CALENDAR_INTEGRATION_READ, CALENDAR_INTEGRATION_WRITE
// 2. ProgramRegistrar — 경로 + 허용 권한 매핑
ProgramDefinition("CALENDAR", "/meetpie/calendar", listOf(CALENDAR_INTEGRATION_READ))
// 3. Controller — @PreAuthorize 적용
@PreAuthorize("hasAuthority(@P.CALENDAR_INTEGRATION_READ)")이중 검증 (FE + BE)
// FE
{auth.hasPermission(auth.P.CALENDAR_INTEGRATION_READ) && <CalendarPage />}PostgreSQL + Flyway
| 스키마 | 위치 |
|---|---|
| app 공통 | backend/app/src/main/resources/db/migration/app |
| meetpie | backend/meetpie/src/main/resources/db/migration/meetpie |
네이밍 규칙
- DB 컬럼/테이블:
snake_case - 인덱스:
idx_{table}_{columns}/udx_{table}_{columns} - API URL:
kebab-case - Kotlin:
PascalCase(클래스),camelCase(변수/함수) - UUID: v7 사용
Standards-First: 공식 문서 기반, 추측성 코드 금지
SSOT (Single Source of Truth)
- 정책/규칙은
docs/reference/문서 기준 - 중복 정의 금지, CI 룰은 문서를 구현한 결과
KISS: 요구사항을 충족하는 가장 단순한 설계 선택
- 단, 아키텍처 계약과 충돌 시 아키텍처 우선
Clean Code
- 함수/클래스 단일 책임, 의도 드러내는 네이밍
- 죽은 코드, 미사용 의존성 제거
- Kotlin
!!사용 금지
# FE
cd frontend/app && pnpm check
# BE
cd backend && ./gradlew test- lefthook: pre-commit lint / typecheck / pattern check
- CI: lint + build + test + SBOM + CVE scan
- Rule Gate: 아키텍처 룰 정적 검증 (merge 차단)
- Rule Report: 이슈 자동 생성 + autofix PR
feature/* ──PR──▶ develop ──auto promote──▶ release
│ │
CI (lint+build+test) CI + Rule Gate
+ Rule Report
+ SBOM/CVE scan
브랜치 규칙
- 기본 개발:
develop - 배포(프로덕션):
release— 직접 push 금지, 자동 동기화 - feature:
feature/{detail}— develop 기준 분기
- 로컬에서
app+meetpie각각 1회 실행 -
frontend/app/src/pages와backend/iam코드 읽기 - 로그인/권한 흐름 API 추적 (
/api/v1/auth/*) - 권한 모델 이해 — Role vs Menu.permissions
- 예약 공개 페이지 흐름 확인 (
/book/{handle}/{slug}) - 테스트 1개 고치고 CI 통과까지 경험
-
docs/reference/주요 문서 훑어보기
FE UI 텍스트는 모두 번역 키를 사용한다. BE 에러 메시지는 서버가 번역해서 내려주므로 FE는 다시 번역하지 않는다.
// React 컴포넌트
const { t } = useTranslation('account');
<label>{t('email.label')}</label>
// non-React (toast, dialog)
showToast(i18n.t('common:button.saved'), 'success');번역 키 추가 — en → ko → ja 3개 파일 세트로 추가
- app 공통:
frontend/app/src/shared/i18n/locales/{lang}/{ns}.json - 서비스 전용:
frontend/{service}/src/shared/i18n/locales/{lang}/{ns}.json
상세: docs/reference/frontend/i18n.md
| 문서 | 내용 |
|---|---|
docs/reference/architecture.md |
아키텍처 원칙, 목표 구조 |
docs/reference/frontend.md |
FE 베스트 프랙티스 |
docs/reference/backend.md |
BE 베스트 프랙티스 |
docs/reference/meetpie.md |
meetpie 도메인 규칙 (UI 메시지 영문 정책 포함) |
docs/reference/common-rules.md |
공통 엔지니어링 기준 |
docs/reference/backend/auth.md |
인증/권한 상세 |
docs/reference/backend/notification.md |
알림 시스템 (Email/Slack/Webhook) |
docs/reference/backend/encryption-architecture.md |
암호화 (KEK/DEK/JWK) |
docs/reference/frontend/fsd.md |
FSD 레이어 상세 |
docs/reference/frontend/i18n.md |
다국어 (i18n) 가이드 |
docs/rules/rule-catalog-v0.md |
룰 인덱스 |
필요한 내용이 빠졌다면
온보딩 슬라이드(onboarding.md)를 바로 업데이트하세요.
"문서는 코드와 같이 유지한다"가 팀 기본 원칙입니다.