Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# System Architecture

## Communication Topology

### Data Flow Between Services

```
client (React/Vite)
โ†’ nginx (reverse proxy, static files)
โ†’ server (NestJS)
โ”œโ”€โ”€ MySQL 8.0 (TypeORM, Full-Text Search)
โ”œโ”€โ”€ Redis 6 (cache, session, trends)
โ”‚
โ”œโ”€โ”€[Redis rpush]โ”€โ”€โ†’ feed-crawler (standalone Node.js, cron scheduler)
โ”‚ queue: feed:full-crawl:queue (triggered on RSS approval, full crawl)
โ”‚ queue: feed:ai:queue (AI tag/summary for crawled feeds)
โ”‚ consumer pattern: Redis rpop polling (RabbitMQ migration planned)
โ”‚ feed-crawler โ†’ MySQL (feed persistence), Redis (recent feed cache)
โ”‚
โ””โ”€โ”€[RabbitMQ AMQP]โ”€โ”€โ†’ email-worker (standalone Node.js)
exchange: EmailExchange, routing: email.send
DLQ: DeadLetterExchange (3 retries with exponential backoff, then dead letter)
triggers: signup verification, RSS accept/reject, password reset, account deletion, RSS removal

client โ†โ”€โ”€[SSE]โ”€โ”€ server (real-time trending updates)
```

## Queue Specifications

### Redis Queues (server โ†’ feed-crawler)

- feed:full-crawl:queue: RSS feed crawling requests
- Trigger: Admin RSS approval
- Purpose: Full crawl of newly approved RSS sources
- feed:ai:queue: AI tagging and summarization jobs
- Trigger: New posts detected during crawl
- Purpose: Generate summaries and tags via Anthropic Claude
- Consumer Pattern: Redis rpop polling (blocking read with timeout)
- Migration Plan: RabbitMQ migration planned for improved reliability

### RabbitMQ (server โ†’ email-worker)

- Exchange: EmailExchange (topic exchange)
- Routing Key: email.send
- Retry Policy: 3 attempts with exponential backoff
- DLQ: DeadLetterExchange for failed deliveries after retry exhaustion
- Triggers:
- Signup verification email
- RSS accept/reject notification
- Password reset email
- Account deletion confirmation
- RSS removal notification

## Service Communication Patterns

### Server โ†’ Feed Crawler (Redis)

- Pattern: Fire-and-forget queue push
- Reliability: At-least-once delivery (manual retry on consumer)
- Ordering: FIFO within each queue
- Backpressure: Queue length monitoring via Redis metrics

### Server โ†’ Email Worker (RabbitMQ)

- Pattern: Reliable async messaging with DLQ
- Reliability: At-least-once delivery (automatic retry with exponential backoff)
- Ordering: Not guaranteed (parallel consumers)
- Failure Handling: 3 retries โ†’ DLQ โ†’ manual intervention

### Server โ†’ Client (SSE)

- Pattern: Server-push for real-time updates
- Use Case: Trending posts updates
- Reconnection: Client-side automatic retry with exponential backoff
- Heartbeat: Periodic keep-alive to detect stale connections
164 changes: 69 additions & 95 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,121 +1,95 @@
# CLAUDE.md
# Project Overview

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Denamu (๋ฐ๋‚˜๋ฌด) is an RSS-based tech blog curation platform. It aggregates developer blog content from multiple platforms (Tistory, Velog, Medium) into a single service with real-time trending, search, and developer chat features.

## Project Overview
- Production URL: https://denamu.dev
- Architecture: Monorepo with microservices (Docker Compose orchestration)

**Denamu (๋ฐ๋‚˜๋ฌด)** is an RSS-based tech blog curation platform. It aggregates developer blog content from multiple platforms (Tistory, Velog, Medium) into a single service with real-time trending, search, and developer chat features.
# Identity

- **Production URL**: https://denamu.dev
- **Architecture**: Monorepo with microservices (Docker Compose orchestration)
You are a Principal Engineer responsible for the 5-year viability of the platform.

## Repository Structure
Core Goal: Ensure architectural health, data safety, and operational simplicity.
Philosophy: Long-term survivability > Short-term speed.
Language: Always respond in Korean. (Technical terms remain in English).

# Repository Structure

```
server/ # NestJS backend API (port 8080)
client/ # React + Vite frontend (port 5173)
server/ # NestJS backend API (Dev port 8080)
client/ # React + Vite frontend (Dev port 5173)
feed-crawler/ # RSS feed crawler with AI tagging
email-worker/ # Email processing via RabbitMQ
docker-compose/ # Infrastructure configs (local, dev, prod)
nginx/ # Reverse proxy configuration
nginx/ # Local & Dev Infra Reverse proxy configuration
```

## Common Commands
# Absolute Decision Hierarchy

### Root Level
```bash
npm run start:local # Start all services locally (no watch)
npm run start:dev # Start dev environment with hot reload
npm run start:was-dev # Start backend services only
npm run commit # Commitizen for structured commits
```
Reject any tradeoff that violates upper tiers:
Correctness & Data Integrity
Failure Containment & Recoverability
Architectural Longevity & Cognitive Simplicity
Scalability & Performance

### Server (NestJS)
```bash
cd server
npm run start:dev # Development with watch mode
npm run build # Production build
npm run lint # ESLint
npm run test:unit # Unit tests
npm run test:e2e # E2E tests (uses Testcontainers)
npm run test:dto # DTO validation tests
npm run migration:create # Create DB migrations
```
# Operational Protocol

### Client (React)
```bash
cd client
npm run dev # Development server
npm run build # Production build
npm run lint # ESLint
npm run test # Vitest unit tests
npm run test:coverage # Coverage report
```
Challenge Fragility: Do NOT comply with risky requests. Explain the failure mode and provide a robust alternative.
Risk Escalation: Mark clearly: ๐Ÿ”ฅ (Critical), โš ๏ธ (Structural), ๐ŸŸก (Tradeoff), โœ… (Safe).
Executive Response Structure:
Verdict: Clear Go/No-Go (1-2 sentences).
Rationale: Dense engineering reasoning.
Design/Implementation: High-signal code or architecture.
Failure Modes: How will this break, and how do we mitigate?

### Feed Crawler
```bash
cd feed-crawler
npm run start:dev # Development mode
npm run test:unit # Unit tests
npm run test:e2e # Integration tests
```
# Engineering Laws

## Tech Stack
Never Guess: If context is missing, ask one precise question. Do not hallucinate infra.
Boring Systems Scale: Favor predictable patterns over "clever" or "complex" solutions.
Data Gravity: Code is ephemeral; data is forever. Protect the schema aggressively.
Concurrency First: Always evaluate locking, idempotency, and race conditions.

- **Backend**: NestJS, TypeORM, MySQL 8.0, Redis 7.2, RabbitMQ 3.13
- **Frontend**: React 18, TypeScript, Vite, TanStack Query, Zustand, Tailwind CSS, Radix UI
- **Real-time**: Socket.IO (WebSocket chat)
- **AI**: Anthropic Claude SDK (automatic content tagging in feed-crawler)
- **Monitoring**: Prometheus, Grafana, Winston logging
- **Auth**: JWT + OAuth (Google, GitHub) via Passport.js
# Forbidden Behaviors

## Architecture Notes
No beginner-level hand-holding.
No passive compliance with poor design.
No verbosity; maximize signal-to-noise ratio.

### Backend (Server)
- Module-based NestJS architecture: each feature has Module, Controller, Service
- TypeORM with MySQL for data persistence
- Redis for caching and session management
- Global exception filters and interceptors for consistent error handling
- Swagger API documentation available
# Commands

### Frontend (Client)
- TanStack Query for server state, Zustand for client state
- Custom hooks pattern for logic reuse
- Socket.IO client for real-time chat
npm run \*
start:local # Start all services locally (no watch)
start:dev # Start dev environment with hot reload
start:dev:was # Start backend services only
start:dev:feed # Start feed crawler services only
start:dev:email # Start email worker services only
commit # Commitizen for structured commits

### Feed Crawler
- tsyringe for dependency injection (not NestJS)
- Scheduled jobs via node-schedule for RSS polling
- Claude AI integration for automatic tag generation
- RabbitMQ for event publishing
# Commit Message

### Email Worker
- RabbitMQ consumer for async email processing
- Nodemailer for email delivery
Reference `.cz-config.js`

## Code Review Convention
# Code Review Convention

Uses Pn-level system (Korean language reviews):
- **P1**: Critical - security issues, business logic errors (must fix before deploy)
- **P2**: Important - code quality/functionality issues (must fix)
- **P3**: Medium - potential bug risks, improvements (strongly consider)
- **P4**: Light - readability suggestions (optional)
- **P5**: Questions - optional suggestions

## Environment Variables

Key environment variable groups (see `.env.example` files):
- Database: `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASSWORD`, `DB_NAME`
- Redis: `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`
- RabbitMQ: `RABBITMQ_HOST`, `RABBITMQ_PORT`, `RABBITMQ_USER`, `RABBITMQ_PASSWORD`
- JWT: `JWT_ACCESS_SECRET`, `JWT_REFRESH_SECRET`
- OAuth: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`

## CI/CD

GitHub Actions workflows deploy to self-hosted runner via GHCR:
- `deploy_server.yml` - NestJS backend
- `deploy_client.yml` - React frontend
- `deploy_feed-crawler.yml` - Crawler service
- `deploy_email-worker.yml` - Email worker
- Test workflows run on PR: `test_server_dto.yml`, `test_server_e2e.yml`, `test_feed-crawler.yml`

- P1: Critical - security issues, business logic errors (must fix before deploy)
- P2: Important - code quality/functionality issues (must fix)
- P3: Medium - potential bug risks, improvements (strongly consider)
- P4: Light - readability suggestions (optional)
- P5: Questions - optional suggestions

# CI/CD

GitHub Actions workflows deploy to self-hosted runner via GHCR
Deploy Application: `deploy_*.yml`
Test workflows run on PR: `test_*.yml`

# Docker Compose

All Docker Compose files are located in the `docker-compose/` directory.
Use the appropriate compose file based on the target environment (local, dev, prod).

- `local`: docker-compose.local.yml + docker-compose.infra.yml
- `dev`: docker-compose.dev.yml + docker-compose.infra.yml
- `prod`: docker-compose.prod.yml + docker-compose.prod.infra.yml
68 changes: 68 additions & 0 deletions client/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# System Purpose

The client is the user-facing React SPA for Denamu. It consumes the server API and renders RSS-aggregated blog content with features including trending feeds, search, developer chat, and user authentication.

# Stack

[Core]

- React 18
- Vite(SWC)
- Zustand v5 (global UI state)
- TanStack React Query v5 (server state + caching)
- Axios with credentials
- Socket.io-client (chat, trending)
- Tailwind CSS
- shadcn/ui (Radix UI)
- Framer Motion

[Test]

- Vitest

# Directory Structure

| Directory | Role |
| ------------------ | ---------------------------------------------------------- |
| src/pages/ | Page-level components, one per route |
| src/routes/ | React Router route definitions |
| src/components/ | Feature components (auth, admin, chat, common, ui) |
| src/store/ | Zustand stores (auth, search, sidebar, chat, filter, etc.) |
| src/hooks/ | Custom hooks: auth/, queries/, common/ |
| src/api/services/ | Axios service layer per domain |
| src/api/mocks/ | MSW handlers for development |
| src/constants/ | API endpoint constants |
| src/types/ | TypeScript type definitions |
| src/providers/ | React context providers (TanStack Query) |
| src/components/ui/ | shadcn/ui base components |

# Routing

Background Location pattern is used: PostDetailPage renders as a modal overlay on the feed list, or as a full page on direct navigation.

Pages are lazy-loaded via React.lazy() for code splitting.

# State Management

| Store | Purpose |
| --------------------- | --------------------------------------------- |
| useAuthStore | User role (guest / user / admin), token state |
| useSearchStore | Search params, filter type, pagination |
| useSidebarStore | Sidebar visibility |
| useChatStore | WebSocket chat state |
| useRegisterModalStore | RSS registration modal |
| React Query | Server data fetching, caching, refetch |

# Build Configuration

Vite manual chunks split vendor libraries to optimize bundle size: radix-ui, charts (recharts), vendor (react core), animation (framer-motion), query, socket, utils.

Dev server uses `usePolling: true` for file system compatibility in Docker/WSL.

# Commands

npm run dev - Development server (port 5173)
npm run build - Production build (tsc + vite build)
npm run lint - ESLint
npm run test - Vitest
npm run test:coverage - Vitest with coverage report
Loading