Skip to content

RLidea/weaver2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

440 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Weaver2

NestJS + Next.js 기반의 커뮤니티 플랫폼 보일러플레이트입니다. 인증, 게시판, 알림, 검색, 신고/제재, 관리자 기능을 포함한 프로덕션 수준의 모노레포 구조로 설계되었습니다.

🚀 주요 기능

인증 & 사용자

  • 이메일/비밀번호 로그인·회원가입 — JWT HttpOnly 쿠키 기반, 이메일 인증
  • OAuth 소셜 로그인 — Google, Kakao, Naver (native fetch, passport 미사용)
  • 2단계 인증(2FA) — TOTP(Google Authenticator 등) + 이메일 OTP 선택 지원
  • 계정 잠금 — 로그인 5회 실패 시 15분 잠금
  • 세션 관리 — 기기별 RefreshToken 조회·삭제, 비밀번호 변경 시 전체 세션 무효화
  • 이메일 변경 — 새 이메일로 인증 코드 발송 후 적용
  • OAuth 연결 관리 — 연동된 소셜 계정 목록 조회·해제

게시판

  • 게시판·게시글·댓글 CRUD — Keyset 기반 무한스크롤 페이지네이션
  • 대댓글 — 4단계 중첩, 소프트 삭제
  • 파일 첨부 — 게시글 생성·수정 시 파일 업로드/삭제
  • 고정 게시글 — 쿼리 분리 패턴으로 상단 고정
  • 카테고리 필터링 — 게시판별 카테고리 탭/칩 UI
  • 리액션 시스템 — 이모지 기반 게시글 반응

알림

  • SSE 실시간 알림 — 로그인 상태에서 댓글·답글·리액션 즉시 수신
  • 웹 푸시 알림 — Service Worker + VAPID 기반, 브라우저 닫힌 상태에서도 수신
  • 알림 목록 — 미읽음 카운트, 전체/개별 읽음 처리

검색

  • 통합 검색 — 게시글·댓글 전문 검색, 키워드 하이라이팅
  • 필터링 — 작성자, 날짜 범위, 게시판별 필터
  • URL 상태 관리 — 검색 조건이 URL에 유지되어 공유 가능

신고/모더레이션

  • 다형 신고 — 게시글·댓글·사용자·미디어 신고
  • 콘텐츠 제재 — 숨김·삭제, 동일 대상 신고 자동 처리
  • 사용자 제재 — 경고·정지(기간 지정), 로그인 시 정지 계정 차단
  • 권한 분리 — Moderator(숨김·경고) / Operator(삭제·정지) / Admin(전체)

관리자

  • 대시보드 — 사용자·게시글·댓글 통계
  • 사용자 관리 — 목록 조회, 정지·복구
  • 콘텐츠 관리 — 게시글·댓글 관리
  • 권한 그룹 — 그룹별 세분화된 퍼미션 관리
  • 신고 처리 — 신고 목록 조회·처리·기각
  • 이메일 템플릿 — 발송 템플릿 내용·활성화 관리
  • 시스템 설정 — KV 스토어 기반 런타임 설정 변경
  • 약관 관리 — 버전 관리·동의 이력

인프라

  • 파일 업로드 — Local 또는 S3(MinIO 호환) 드라이버 전환 가능
  • 썸네일 생성 — sharp 기반 자동 리사이징
  • 이메일 — SMTP, DB 템플릿 관리, 발송 로그·재발송
  • Rate Limiting — 전역 + 민감 엔드포인트별 강화 적용

🛠️ 기술 스택

영역 기술
Backend NestJS, TypeScript, Prisma ORM
Frontend Next.js 16 (App Router), TypeScript, Tailwind CSS
Database PostgreSQL
Auth JWT (HttpOnly Cookie), Passport 없이 native OAuth
Realtime SSE (Server-Sent Events), Web Push (VAPID)
Storage Local / AWS S3 (환경변수로 전환)
Email Nodemailer (SMTP)
Docs Swagger / OpenAPI
CI ESLint, Prettier, Husky pre-commit

📂 프로젝트 구조

weaver2/
├── apps/
│   ├── core-backend/          # NestJS API 서버 (port 4000)
│   │   ├── prisma/schema/     # 도메인별 분리된 Prisma 스키마
│   │   └── src/
│   │       ├── core/          # 프레임워크 기능 (auth, user, notification, permission, terms)
│   │       ├── features/      # 비즈니스 기능 (board, report, search)
│   │       ├── infrastructure/# 인프라 (email, upload, config)
│   │       └── system/        # 관리자 API
│   └── core-frontend/         # Next.js 웹 앱 (port 3000)
│       └── src/
│           ├── app/           # 라우팅 (App Router)
│           ├── features/      # 도메인별 슬라이스
│           ├── shared/        # 공통 UI 컴포넌트
│           └── infrastructure/# ApiClient, Providers
├── libs/
│   ├── common/                # 전역 데코레이터, 인터셉터, 필터
│   ├── email/                 # Nodemailer 래퍼
│   ├── pagination/            # Keyset 페이지네이션 라이브러리
│   ├── prisma/                # PrismaService 모듈
│   ├── shared/                # PERMISSIONS 상수, hasPermission() (백·프론트 공용)
│   └── upload/                # StorageProvider 인터페이스, Local/S3 구현
└── scripts/                   # 유틸리티 스크립트

🚀 시작하기

1. 환경 변수 설정

cp apps/core-backend/.env.example apps/core-backend/.env
cp apps/core-frontend/.env.example apps/core-frontend/.env.local

apps/core-backend/.env 필수 항목:

DATABASE_URL=postgresql://<user>:<password>@localhost:5432/<db>
JWT_SECRET=<secret>
SMTP_HOST=smtp.gmail.com
SMTP_USER=<email>
SMTP_PASS=<app-password>

# Web Push (VAPID) — node -e "const wp=require('web-push'); console.log(wp.generateVAPIDKeys())"
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
VAPID_SUBJECT=mailto:admin@example.com

# 파일 저장 방식: local(기본) | s3
STORAGE_DRIVER=local

2. 의존성 설치

pnpm install

3. 데이터베이스 설정

# 마이그레이션 실행
DATABASE_URL=<your-url> npx prisma migrate deploy --schema apps/core-backend/prisma/schema

# 시드 데이터 생성 (권한 그룹, 기본 관리자 계정, 이메일 템플릿 등)
pnpm db:seed

4. 개발 서버 실행

# 백엔드 (port 4000)
pnpm dev

# 프론트엔드 (port 3000) — 별도 터미널
cd apps/core-frontend && pnpm dev

5. 확인

서비스 URL
프론트엔드 http://localhost:3000
API 서버 http://localhost:4000
Swagger http://localhost:4000/docs

기본 관리자 계정은 시드 실행 후 apps/core-backend/prisma/seed 참조.


🔌 주요 API 엔드포인트

모든 경로는 /v1 프리픽스를 포함합니다.

인증

POST /v1/auth/sign-in                    # 로그인
POST /v1/auth/sign-up/email              # 이메일 회원가입
POST /v1/auth/refresh                    # 토큰 갱신
POST /v1/auth/sign-out                   # 로그아웃
POST /v1/auth/password/request-reset     # 비밀번호 재설정 요청
POST /v1/auth/password/reset             # 비밀번호 재설정
GET  /v1/auth/oauth/:provider            # OAuth 시작 (google|kakao|naver)
POST /v1/auth/2fa/authenticate           # 2FA 최종 인증
POST /v1/auth/2fa/email/send             # 이메일 OTP 발송
GET  /v1/auth/sessions                   # 세션 목록
DELETE /v1/auth/sessions/:id             # 세션 삭제
GET  /v1/auth/oauth/connections          # OAuth 연결 목록
DELETE /v1/auth/oauth/connections/:provider # OAuth 연결 해제

사용자

GET    /v1/users/me                      # 본인 정보 조회
PATCH  /v1/users/me                      # 프로필 수정
PATCH  /v1/users/me/password             # 비밀번호 변경
DELETE /v1/users/me                      # 계정 탈퇴
POST   /v1/users/me/email                # 이메일 변경 요청
POST   /v1/users/me/email/confirm        # 이메일 변경 확인

게시판

GET    /v1/boards                        # 게시판 목록
GET    /v1/boards/:id/posts              # 게시글 목록 (categoryId 필터 지원)
POST   /v1/boards/:id/posts              # 게시글 생성 (파일 첨부 가능)
GET    /v1/boards/:id/posts/:postId      # 게시글 조회
PATCH  /v1/boards/:id/posts/:postId      # 게시글 수정
DELETE /v1/boards/:id/posts/:postId      # 게시글 삭제
POST   /v1/boards/:id/posts/:postId/reactions/:emojiId # 리액션 추가

알림

GET  /v1/notifications                   # 알림 목록
GET  /v1/notifications/unread-count      # 미읽음 수
GET  /v1/notifications/stream            # SSE 실시간 스트림
PATCH /v1/notifications/:id/read         # 개별 읽음 처리
PATCH /v1/notifications/read-all         # 전체 읽음 처리
GET  /v1/notifications/push-subscription/public-key # VAPID 공개키
POST /v1/notifications/push-subscription # 웹 푸시 구독 저장
DELETE /v1/notifications/push-subscription # 웹 푸시 구독 해제

검색

GET /v1/search?q=키워드&type=post|comment&boardId=...&authorId=...

신고

POST   /v1/reports                       # 신고 생성
GET    /v1/reports                       # 신고 목록 (관리자)
PATCH  /v1/reports/:id/action            # 신고 처리 (숨김·삭제·경고·정지)
PATCH  /v1/reports/:id/reject            # 신고 기각

업로드

POST /v1/upload                          # 파일 업로드
GET  /v1/upload/:id/file                 # 파일 서빙 (302 redirect)
GET  /v1/upload/:id/thumbnail            # 썸네일 서빙 (302 redirect)

🏗️ 아키텍처

Repository 패턴

Controller → Service → Repository (*.query.ts | *.command.ts) → Prisma

읽기(Query)와 쓰기(Command)를 파일 레벨에서 분리합니다.

알림 아키텍처

EventEmitter2 (notification.created)
  → NotificationListener
    → DB 저장 (notifications 테이블)
    → InMemoryNotificationEmitter → SSE 발송
    → PushSubscriptionService → 웹 푸시 발송

NOTIFICATION_EMITTER 심볼 토큰으로 추상화되어 있어, Redis 기반 Emitter로 교체 시 NotificationModule provider만 변경하면 됩니다.

파일 업로드 아키텍처

STORAGE_DRIVER=local  → LocalStorageProvider  (uploads/ 디렉토리)
STORAGE_DRIVER=s3     → S3StorageProvider     (AWS S3 / MinIO)

환경변수 하나로 드라이버를 전환할 수 있습니다.

권한 시스템

역할(Role) 대신 권한 그룹(PermissionGroup) 기반으로 동작합니다.

  • 사용자는 여러 권한 그룹에 속할 수 있습니다.
  • PERMISSIONS 상수와 hasPermission() 함수가 @weaver2/shared에 정의되어 백엔드·프론트엔드가 공유합니다.
  • 와일드카드 지원: board:*board:read, board:write 등을 모두 포함합니다.

🔐 보안

  • JWT: HttpOnly 쿠키 기반, Access Token 15분 / Refresh Token 최대 30일
  • CSRF: 뮤테이션 요청마다 x-csrf-token 헤더 검증
  • Rate Limiting: 전역 60초/100회, 로그인 60초/10회, 2FA 60초/3~5회
  • 계정 잠금: 로그인 5회 실패 → 15분 잠금
  • 보안 헤더: Helmet, HSTS(프로덕션), X-Frame-Options 등

🛠️ 주요 명령어

# 개발 서버
pnpm dev              # 백엔드 개발 모드
pnpm build            # 백엔드 프로덕션 빌드

# 데이터베이스
pnpm db:migrate       # 마이그레이션 실행
pnpm db:seed          # 시드 데이터 생성
pnpm db:reset         # DB 초기화 + 시드

# 코드 품질
pnpm lint             # ESLint 검사
pnpm format           # Prettier 포맷팅
pnpm test             # 유닛 테스트
pnpm test:integration # 통합 테스트 (Postgres 필요)

# E2E (Playwright) — 풀 스택 시나리오, 자세한 안내는 apps/core-frontend/e2e/README.md
pnpm --filter core-frontend e2e:install    # 1회: chromium 브라우저 설치
pnpm --filter core-frontend e2e            # e2e 실행 (자동으로 frontend·backend 기동)
pnpm --filter core-frontend e2e:ui         # Playwright UI 모드 (시나리오 작성/디버깅)

🐳 Docker

# 개발 환경 (PostgreSQL + 앱)
docker-compose up -d

# 프로덕션
docker-compose -f docker-compose.prod.yml up -d

🤖 CI / GitHub Actions

.github/workflows/에 4개의 워크플로우가 포함되어 있습니다.

워크플로우 트리거 역할
ci.yml PR / main push / 수동 install → secret-files / lint / unit / integration / backend build / web build / prisma check → CI success 단일 게이트
security.yml 매주 월 09:00 KST / 수동 / 의존성 PR pnpm audit --audit-level=high, 발견 시 자동 Issue 생성 + PR fail
pr-checks.yml PR 이벤트 Conventional Commits 제목 검사, 경로별 자동 라벨, 500줄 이상 PR 경고
codeql.yml PR / main push / 매주 월 14:00 KST / 수동 GitHub CodeQL 정적 분석 (security-extended 쿼리)

설계 포인트:

  • ci-success 단일 aggregator job — Branch protection에서 이 하나만 require하면 충분.
  • HUSKY=0 + --ignore-scripts + 명시적 prisma generate — pnpm v11의 approve-builds 프롬프트와 husky postinstall 노이즈 회피.
  • Postgres 16 service container + healthcheck로 integration test 격리.
  • concurrency.cancel-in-progress — 동일 PR 새 push 시 진행 중 run 자동 취소.

Branch ruleset 권장 설정

저장소 Settings → Rules → Rulesets → New branch ruleset:

  • Target: default branch
  • Restrict deletions
  • Block force pushes
  • Require a pull request before merging
    • Required approvals: 1
    • Dismiss stale approvals: ✅
    • Require conversation resolution: ✅
  • Require status checks to pass
    • CI success 단일 등록 (워크플로우가 한 번 실행된 후에 검색 가능)
    • Analyze (javascript-typescript) 추가 (CodeQL — public 또는 Team/Enterprise plan)

외주/private 저장소로 복제 시

이 보일러플레이트를 private repo로 복제하셨다면 plan에 따라 ruleset 일부 항목을 빼야 합니다:

기능 Public Free Private Free Private Team/Enterprise
Code Scanning (CodeQL) ❌ → ruleset에서 제거
Restrict file paths (Push ruleset) ❌ → 본 보일러플레이트의 3-layer guard 사용
Dependabot
Branch ruleset

Private + Free 환경에서 CodeQL 워크플로우 자체는 두어도 무방하지만 결과를 Security 탭에서 볼 수 없으며, ruleset의 Require code scanning results는 영원히 만족되지 않으므로 반드시 제거해야 합니다.

Secret/key 파일 차단 — 3-layer guard

이 보일러플레이트는 GitHub plan 의존 없이 secret 유출을 방어합니다:

  1. .gitignore.env* (단, .env.example 제외), *.pem/.key/.p12/.pfx/.crt/.cer, id_rsa*, id_ed25519*
  2. .husky/pre-commit — staged 파일 검사 후 차단 (커밋 자체가 실패)
  3. ci.ymlsecret-files job — 트리 전체 검사 (push에서 차단)

세 단계가 동일 패턴을 공유하므로 어느 하나가 뚫려도 다음에서 잡힙니다.


📚 문서 구조

문서 역할
README.md 프로젝트 소개, 기술 스택, API, CI 가이드 (이 문서)
CHARTER.md 보일러플레이트 헌장 — 미션, IN/OUT 범위, 설계 원칙, 확장 포인트, 분기 체크리스트
CONTRIBUTING.md 일상 개발 워크플로우, 브랜치/커밋/PR/리뷰/마이그레이션/테스트/FAQ
SECURITY.md 보안 취약점 보고·대응 정책, 빌트인 보안 레이어 정리
ROADMAP.md 향후 권장 작업 (Dependabot, e2e, 운영 등)
CLAUDE.md 코딩 철학·EDGE 방법론·금지 사항 (AI 협업 규칙 포함)
apps/core-frontend/CLAUDE.md 프론트엔드 디렉토리 구조·스킨 시스템·import 규칙
docs/audits/ 종합 감사 보고서 archive

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors