소스 정보
- 저장소
- diegosouzapw/awesome-omni-skill
- 최근 소스 활동
- 2026년 2월 28일 04:03
- 감지된 SKILL.md 언어
- 영어
- 스타
- 50
- 포크
- 19
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/diegosouzapw/awesome-omni-skill --skill backend-expert-advisor명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Token-efficient tracking for AI orchestration. CLI-first for status updates (~50 tokens), agent fallback for complex ops (~1KB). Use when: updating task status, querying blockers, creating progress files, validating phases.
AshAi extension guidelines for integrating AI capabilities with Ash Framework. Use when implementing vectorization/embeddings, exposing Ash actions as LLM tools, creating prompt-backed actions, or setting up MCP servers. Covers semantic search, LangChain integration, and structured outputs.
This skill should be used when solving hard questions, complex architectural problems, or debugging issues that benefit from GPT-5 Pro or GPT-5.1 thinking models with large file context. Use when standard Claude analysis needs deeper reasoning or extended context windows.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | backend-expert-advisor |
| description | Backend expert guidance for API/DB/Security/Architecture |
Version: 1.0.0
Last Updated: 2025-01-24
Specialization: Professional Backend Development (API/DB/Security/Architecture)
Target Audience: Intermediate to Advanced Backend Developers
Language Support: Korean + English
Backend Expert Advisor is a comprehensive skill that provides expert-level guidance for backend development challenges. Built on 45+ research papers in prompt engineering and curated from authoritative sources including RFC standards, OWASP guidelines, and enterprise engineering blogs (Netflix, Uber, Kakao, Naver), this skill delivers production-ready solutions with security and performance best practices.
Use Backend Expert Advisor when you need to:
Basic Query Format
"I need help with [specific problem].
Context:
- Tech stack: [e.g., Node.js + PostgreSQL + Redis]
- Current issue: [describe the problem]
- Constraints: [performance requirements, regulations, etc.]"
Example
"I need help optimizing a slow API endpoint.
Context:
- Tech stack: Express.js + PostgreSQL + Redis
- Current issue: /users endpoint takes 3-5 seconds
- The query joins 4 tables and returns 10,000+ rows
- Need to reduce to under 500ms"
"Review my microservices architecture:
Services:
1. User Service (Node.js + MongoDB)
2. Product Service (Java + PostgreSQL)
3. Order Service (Python + PostgreSQL)
4. Payment Service (Go + MySQL)
Communication: REST APIs
Message Queue: RabbitMQ for async events
Issues:
- Frequent timeouts between services
- Difficulty maintaining data consistency
- Deployment takes 30+ minutes
Suggest improvements with Korean cloud deployment in mind."
"Audit my authentication system for security issues:
[PASTE YOUR CODE OR ARCHITECTURE DIAGRAM]
Requirements:
- OAuth 2.1 compliance
- JWT with refresh tokens
- OWASP Top 10 compliance
- 개인정보보호법 준수 (for Korean users)"
"Optimize this query:
```sql
SELECT u.*, p.*, o.*
FROM users u
LEFT JOIN profiles p ON u.id = p.user_id
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
ORDER BY u.created_at DESC
LIMIT 100;
Current performance:
Target: <500ms"
#### Pattern 4: API Design
"Design a REST API for a blog system with:
Entities:
Requirements:
Generate OpenAPI 3.1 spec."
---
## 🛠️ Framework & Tool Specific Guides
### Node.js + Express.js
```javascript
// ✅ Best Practice: Async Error Handling
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) throw new NotFoundError('User not found');
res.json(user);
}));
// ✅ Best Practice: Structured Logging
const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [new winston.transports.Console()]
});
app.use((req, res, next) => {
logger.info('Request', {
method: req.method,
path: req.path,
ip: req.ip,
userId: req.user?.id
});
next();
});
// ✅ Best Practice: Connection Pooling
const pool = new Pool({
host: process.env.DB_HOST,
database: process.env.DB_NAME,
max: 20, // max connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
# ✅ Best Practice: Dependency Injection
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users/{user_id}")
async def get_user(
user_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
# ✅ Best Practice: Pydantic Validation
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(..., min_length=8)
name: str = Field(..., max_length=100)
class Config:
json_schema_extra = {
"example": {
"email": "user@example.com",
"password": "SecurePass123!",
"name":
}
}
// ✅ Best Practice: Service Layer Pattern
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public UserService(UserRepository userRepository,
PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public UserDTO createUser(UserCreateRequest request) {
// Validation
if (userRepository.existsByEmail(request.getEmail())) {
throw new DuplicateEmailException("Email already exists");
}
// Business logic
User user = User.builder()
.email(request.getEmail())
.password(passwordEncoder.encode(request.getPassword()))
.name(request.getName())
.build();
User savedUser = userRepository.save(user);
return UserDTO.from(savedUser);
}
}
// ✅ Best Practice: Global Exception Handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound {
ErrorResponse.builder()
.status(HttpStatus.NOT_FOUND.value())
.message(ex.getMessage())
.timestamp(LocalDateTime.now())
.build();
<>(error, HttpStatus.NOT_FOUND);
}
}
Scenario: Prevent API abuse with Redis-based rate limiting
Problem:
Solution (Node.js + Express + Redis):
const Redis = require('ioredis');
const redis = new Redis(process.env.REDIS_URL);
// Sliding window rate limiter
async function rateLimiter(req, res, next) {
const userId = req.user?.id || req.ip;
const key = `rate_limit:${userId}`;
const limit = 100;
const window = 60; // seconds
try {
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, window);
}
if (current > limit) {
const ttl = await redis.ttl(key);
res.set('Retry-After', ttl);
return res.status(429).json({
error: 'Too Many Requests',
message: `Rate limit exceeded. Try again in ${ttl} seconds.`,
: ttl
});
}
res.(, limit);
res.(, limit - current);
();
} (error) {
.(, error);
();
}
}
app.(, rateLimiter);
Result:
Scenario: Optimize blog post listing with author and comment counts
Problem (Bad Code):
# ❌ N+1 Query Problem
@app.get("/posts")
async def list_posts(db: Session = Depends(get_db)):
posts = db.query(Post).limit(20).all()
result = []
for post in posts:
# N additional queries!
author = db.query(User).filter(User.id == post.author_id).first()
comment_count = db.query(Comment).filter(
Comment.post_id == post.id
).count()
result.append({
"id": post.id,
"title": post.title,
"author": author.name,
"comment_count": comment_count
})
return result
# Query count: 1 (posts) + 20 (authors) + 20 (counts) = 41 queries!
Solution (Optimized):
# ✅ Optimized with Eager Loading
from sqlalchemy.orm import joinedload, selectinload
from sqlalchemy import func
@app.get("/posts")
async def list_posts(db: Session = Depends(get_db)):
# Single query with joins
posts = db.query(
Post.id,
Post.title,
Post.created_at,
User.name.label('author_name'),
func.count(Comment.id).label('comment_count')
).join(
User, Post.author_id == User.id
).outerjoin(
Comment, Post.id == Comment.post_id
).group_by(
Post.id, User.name
).limit(20).all()
return [
{
"id": post.id,
"title": post.title,
"author": post.author_name,
"comment_count": post.comment_count
}
for post in posts
]
# Query count: 1 query total!
# Performance: 41 queries (2.3s) → 1 query (45ms)
Key Techniques:
JOIN instead of separate queriesCOUNT) in single queryScenario: Implement secure authentication with refresh token rotation
Requirements:
Implementation (Node.js + Express):
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
// Token generation
function generateTokens(userId) {
const accessToken = jwt.sign(
{ userId, type: 'access' },
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ userId, type: 'refresh', jti: crypto.randomUUID() },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '7d' }
);
return { accessToken, refreshToken };
}
// Login endpoint
app.post('/auth/login', async (req, res) => {
const { email, password } = req.body;
// 1. Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
isValid = bcrypt.(password, user.);
(!isValid) {
res.().({ : });
}
{ accessToken, refreshToken } = (user.);
.({
: user.,
: refreshToken,
: (.() + * * * * )
});
res.(, refreshToken, {
: ,
: ,
: ,
: * * * *
});
res.({
accessToken,
: ,
:
});
});
app.(, (req, res) => {
{ refreshToken } = req.;
(!refreshToken) {
res.().({ : });
}
{
payload = jwt.(
refreshToken,
process..
);
storedToken = .({
: payload.,
: refreshToken
});
(!storedToken) {
.({ : payload. });
res.().({ : });
}
.({ : storedToken. });
tokens = (payload.);
.({
: payload.,
: tokens.,
: (.() + * * * * )
});
res.(, tokens., {
: ,
: ,
: ,
: * * * *
});
res.({
: tokens.,
:
});
} (error) {
res.().({ : });
}
});
() {
authHeader = req..;
(!authHeader?.()) {
res.().({ : });
}
token = authHeader.();
{
payload = jwt.(token, process..);
req. = { : payload. };
();
} (error) {
res.().({ : });
}
}
app.(, authenticate, (req, res) => {
user = .(req..);
res.(user);
});
Security Features:
Korean Compliance:
Scenario: Prevent cascading failures between microservices
Problem:
Solution (Node.js with opossum library):
const CircuitBreaker = require('opossum');
const axios = require('axios');
// Payment service client with circuit breaker
function createPaymentClient() {
// Base function to call payment service
async function processPayment(orderId, amount) {
const response = await axios.post(
'http://payment-service/api/payments',
{ orderId, amount },
{ timeout: 3000 } // 3 second timeout
);
return response.data;
}
// Circuit breaker options
const options = {
timeout: 3000, // If function takes > 3s, trigger failure
errorThresholdPercentage: 50, // Open circuit at 50% failure rate
resetTimeout: 30000, // Try again after 30 seconds
rollingCountTimeout: 10000, // 10 second window for stats
rollingCountBuckets: 10, // 10 buckets (1 second each)
// Fallback function
fallback: (orderId, amount) => {
console.log();
messageQueue.(, { orderId, amount });
}
};
breaker = (processPayment, options);
breaker.(, {
.();
metrics.();
});
breaker.(, {
.();
metrics.();
});
breaker.(, {
.();
metrics.();
});
breaker.(, {
.();
metrics.();
});
breaker;
}
paymentClient = ();
app.(, (req, res) => {
{
order = .({
: req..,
: req..,
: req..
});
payment = paymentClient.(order., order.);
(payment. === ) {
res.().({
: ,
: order.,
:
});
}
order.({ : , : payment. });
res.().({
: ,
: order.,
:
});
} (error) {
.(, error);
res.().({ : });
}
});
Circuit Breaker States:
CLOSED (Normal)
↓ (50% errors in 10s window)
OPEN (Reject all requests)
↓ (After 30 seconds)
HALF-OPEN (Allow 1 request to test)
↓ (If successful)
CLOSED (Resume normal)
Benefits:
Monitoring Dashboard (Grafana):
Circuit Breaker Status:
- State: CLOSED ✅ / OPEN ❌ / HALF-OPEN ⚠️
- Success Rate: 95.2%
- Average Response Time: 245ms
- Fallback Triggered: 12 times (last hour)
Scenario: Optimize database connections for high-concurrency API
Problem:
Solution (Node.js + pg library):
const { Pool } = require('pg');
// ✅ Proper connection pool configuration
const pool = new Pool({
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
// Pool configuration
max: 20, // Maximum number of connections
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 2000, // Timeout when acquiring connection
// Connection validation
query_timeout: 10000, // Timeout individual queries after 10s
statement_timeout: 10000,
// SSL for production
ssl: process.env.NODE_ENV === 'production' ? {
rejectUnauthorized: false
} : false
});
// Health check
pool.on('connect', () => {
.();
});
pool.(, {
.(, err);
});
() {
start = .();
{
result = pool.(text, params);
duration = .() - start;
(duration > ) {
.(, {
duration,
: text,
params
});
}
result;
} (error) {
.(, {
: text,
params,
: error.
});
error;
}
}
() {
client = pool.();
{
client.();
result = (client);
client.();
result;
} (error) {
client.();
error;
} {
client.();
}
}
app.(, (req, res) => {
result = (
,
[req..]
);
(result.. === ) {
res.().({ : });
}
res.(result.[]);
});
app.(, (req, res) => {
{
order = ( (client) => {
orderResult = client.(
,
[req.., req..]
);
( item req..) {
client.(
,
[orderResult.[]., item., item.]
);
}
( item req..) {
client.(
,
[item., item.]
);
}
orderResult.[];
});
res.().(order);
} (error) {
.(, error);
res.().({ : });
}
});
process.(, () => {
.();
pool.();
process.();
});
Performance Comparison:
Without Connection Pool:
- Concurrent requests: 100
- Connection creation time: ~50ms each
- Total overhead: 5 seconds
- Errors: "Too many connections"
With Connection Pool (max: 20):
- Concurrent requests: 100
- Connection reuse: Instant
- Total overhead: Negligible
- Errors: None
- Response time: 50ms → 5ms (90% improvement)
Monitoring Metrics (Prometheus):
const metrics = {
poolSize: new Gauge({ name: 'db_pool_size', help: 'Current pool size' }),
poolIdle: new Gauge({ name: 'db_pool_idle', help: 'Idle connections' }),
poolWaiting: new Gauge({ name: 'db_pool_waiting', help: 'Waiting clients' })
};
setInterval(() => {
metrics.poolSize.set(pool.totalCount);
metrics.poolIdle.set(pool.idleCount);
metrics.poolWaiting.set(pool.waitingCount);
}, 5000);
Scenario: Integrate Toss Payments with proper error handling and compliance
Requirements:
Implementation:
const axios = require('axios');
const crypto = require('crypto');
// Toss Payments client
class TossPaymentsClient {
constructor() {
this.secretKey = process.env.TOSS_SECRET_KEY;
this.clientKey = process.env.TOSS_CLIENT_KEY;
this.baseURL = process.env.NODE_ENV === 'production'
? 'https://api.tosspayments.com'
: 'https://api-sandbox.tosspayments.com';
}
// Create payment
async createPayment(orderId, amount, orderName, customerEmail) {
// Generate idempotency key
const idempotencyKey = crypto.createHash('sha256')
.update(`${orderId}-${Date.now()}`)
.digest('hex');
try {
const response = await axios.post(
`${this.baseURL}/v1/payments`,
{
orderId,
amount,
orderName,
customerEmail,
: ,
:
},
{
: {
: ,
: ,
: idempotencyKey
}
}
);
response.;
} (error) {
.(, error.?.);
();
}
}
() {
{
response = axios.(
,
{
paymentKey,
orderId,
amount
},
{
: {
: ,
:
}
}
);
response.;
} (error) {
.(, error.?.);
error;
}
}
() {
{
response = axios.(
,
{ cancelReason },
{
: {
: ,
:
}
}
);
response.;
} (error) {
.(, error.?.);
error;
}
}
() {
computedSignature = crypto
.(, .)
.(.(body))
.();
signature === computedSignature;
}
}
toss = ();
app.(, (req, res) => {
{
{ orderId, amount, orderName } = req.;
order = .(orderId);
(!order) {
res.().({ : });
}
(order. !== ) {
res.().({ : });
}
payment = toss.(
orderId,
amount,
orderName,
req..
);
.({
orderId,
: payment.,
amount,
: ,
: payment.
});
res.({
: payment.,
: payment.
});
} (error) {
.(, error);
res.().({ : error. });
}
});
app.(, (req, res) => {
{ paymentKey, orderId, amount } = req.;
{
result = toss.(paymentKey, orderId, amount);
.(
{ paymentKey },
{
: ,
: (result.),
: result.
}
);
.(
{ : orderId },
{ : }
);
.({
orderId,
paymentKey,
: ,
amount,
: (),
: req.,
: req.()
});
res.();
} (error) {
.(, error);
res.();
}
});
app.(, (req, res) => {
signature = req.[];
(!toss.(signature, req.)) {
.();
res.().({ : });
}
{ eventType, data } = req.;
{
(eventType) {
:
(data);
;
:
(data);
;
:
(data);
;
}
res.({ : });
} (error) {
.(, error);
res.().({ : error. });
}
});
() {
.(
{ : data. },
{ : , : }
);
emailService.({
: data.,
: ,
: ,
: {
: data.,
: data.,
: data.
}
});
}
() {
.(
{ : data. },
{ : , : data. }
);
.(
{ : data. },
{ : }
);
}
() {
.(
{ : data. },
{ : , : data. }
);
}
Compliance Checklist:
// ❌ Bad: No authorization check
app.get('/api/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user); // Anyone can access any user!
});
// ✅ Good: Proper authorization
app.get('/api/users/:id', authenticate, async (req, res) => {
if (req.user.id !== req.params.id && !req.user.isAdmin) {
return res.status(403).json({ error: 'Access denied' });
}
const user = await User.findById(req.params.id);
res.json(user);
});
// ❌ Bad: String concatenation
const query = `SELECT * FROM users WHERE email = '${req.body.email}'`;
// Vulnerable to: ' OR '1'='1
// ✅ Good: Parameterized queries
const query = 'SELECT * FROM users WHERE email = $1';
const result = await pool.query(query, [req.body.email]);
// ✅ Content Security Policy
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
);
next();
});
// ✅ Sanitize user input
const sanitizeHtml = require('sanitize-html');
app.post('/posts', async (req, res) => {
const cleanContent = sanitizeHtml(req.body.content, {
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
allowedAttributes: { 'a': ['href'] }
});
await Post.create({ content: cleanContent });
});
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
// All state-changing operations
app.post('/api/orders', csrfProtection, async (req, res) => {
// CSRF token automatically validated
// ...
});
// Provide token to frontend
app.get('/api/csrf-token', csrfProtection, (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});
const bcrypt = require('bcrypt');
// ✅ KISA 권장: bcrypt with salt rounds 12+
async function hashPassword(password) {
// Validation
if (password.length < 10) {
throw new Error('Password must be at least 10 characters');
}
// Check complexity (영문+숫자+특수문자)
const hasLetter = /[a-zA-Z]/.test(password);
const hasNumber = /[0-9]/.test(password);
const hasSpecial = /[!@#$%^&*]/.test(password);
if (!(hasLetter && hasNumber && hasSpecial)) {
throw new Error('Password must contain letters, numbers, and special characters');
}
// Hash with bcrypt
const saltRounds = 12; // KISA 권장
return await bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// Additional: Password change tracking (for compliance)
async function () {
user = .(userId);
isValid = (oldPassword, user.);
(!isValid) {
();
}
recentPasswords = .({ userId })
.({ : - })
.();
( record recentPasswords) {
( bcrypt.(newPassword, record.)) {
();
}
}
newHash = (newPassword);
.({ : userId }, { : newHash });
.({
userId,
: newHash,
: ()
});
.({
userId,
: ,
: req.,
: ()
});
}
Target Response Times:
- Simple queries (1 table): < 50ms
- Complex queries (3+ tables): < 200ms
- API Gateway: < 10ms overhead
- 95th percentile: < 500ms
- 99th percentile: < 1s
-- ✅ Index for common queries
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_posts_author_created ON posts(author_id, created_at DESC);
-- ✅ Partial index for filtered queries
CREATE INDEX idx_active_users ON users(email) WHERE status = 'active';
-- ✅ Covering index (includes all query columns)
CREATE INDEX idx_posts_list ON posts(author_id, created_at DESC)
INCLUDE (title, excerpt);
-- ❌ Avoid over-indexing
-- Too many indexes slow down writes
-- Rule of thumb: 3-5 indexes per table maximum
const redis = require('redis');
const client = redis.createClient();
// Multi-level caching
async function getUser(userId) {
// L1: In-memory cache (fastest)
if (memoryCache.has(userId)) {
return memoryCache.get(userId);
}
// L2: Redis cache (fast)
const cached = await client.get(`user:${userId}`);
if (cached) {
const user = JSON.parse(cached);
memoryCache.set(userId, user); // Populate L1
return user;
}
// L3: Database (slowest)
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
// Cache results
await client.setex(`user:${userId}`, 300, JSON.stringify(user)); // 5 min TTL
memoryCache.set(userId, user);
return user;
}
// Cache invalidation
async function updateUser() {
db.(, [userId]);
memoryCache.(userId);
client.();
}
-- ❌ Bad: SELECT *
SELECT * FROM posts WHERE author_id = 123;
-- ✅ Good: Select only needed columns
SELECT id, title, excerpt, created_at FROM posts WHERE author_id = 123;
-- ❌ Bad: N+1 queries
SELECT * FROM posts;
-- Then for each post:
SELECT * FROM users WHERE id = post.author_id;
-- ✅ Good: Single query with JOIN
SELECT
p.id, p.title, p.excerpt,
u.name as author_name, u.avatar as author_avatar
FROM posts p
INNER JOIN users u ON p.author_id = u.id
WHERE p.status = 'published'
ORDER BY p.created_at DESC
LIMIT 20;
// ❌ Bad: Synchronous email sending (blocks response)
app.post('/register', async (req, res) => {
const user = await User.create(req.body);
await emailService.sendWelcomeEmail(user.email); // Blocks for 2-3 seconds!
res.json(user);
});
// ✅ Good: Queue for background processing
const Bull = require('bull');
const emailQueue = new Bull('email', process.env.REDIS_URL);
app.post('/register', async (req, res) => {
const user = await User.create(req.body);
// Queue email (returns immediately)
await emailQueue.add('welcome', {
email: user.email,
name: user.name
});
res.json(user); // Fast response!
});
// Worker process (separate process)
emailQueue.process('welcome', async (job) => {
await emailService.(job.., job..);
});
Symptoms: Pool is exhausted errors under load
Diagnosis:
// Check pool status
console.log('Total:', pool.totalCount);
console.log('Idle:', pool.idleCount);
console.log('Waiting:', pool.waitingCount);
Solutions:
max: 20 → max: 50idleTimeoutMillis: 30000 → idleTimeoutMillis: 10000// Wrap queries with timeout
const withTimeout = (promise, ms) => {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Query timeout')), ms)
)
]);
};
Diagnosis:
// Add request timing middleware
app.use((req, res, next) => {
req.startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - req.startTime;
if (duration > 1000) {
console.warn('Slow request:', {
method: req.method,
path: req.path,
duration,
query: req.query
});
}
});
next();
});
Solutions:
EXPLAIN ANALYZEDiagnosis:
// Monitor memory usage
setInterval(() => {
const usage = process.memoryUsage();
console.log('Memory:', {
rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`
});
}, 60000); // Every minute
Common Causes:
Solutions:
// ✅ Remove event listeners
const controller = new AbortController();
eventEmitter.on('data', handler, { signal: controller.signal });
// Later:
controller.abort(); // Removes all listeners
// ✅ Use WeakMap for caches
const cache = new WeakMap(); // Automatically garbage collected
// ✅ Implement LRU cache
const LRU = require('lru-cache');
const cache = new LRU({ max: 500, maxAge: 1000 * 60 * 5 });
Project Structure:
src/
├── domain/ # Business logic (pure)
│ ├── entities/
│ ├── use-cases/
│ └── interfaces/ # Ports
├── infrastructure/ # External adapters
│ ├── database/
│ ├── messaging/
│ └── external-apis/
├── application/ # Application services
│ ├── dto/
│ └── services/
└── presentation/ # API layer
├── http/
└── graphql/
Benefits:
Services:
- User Service (authentication, profiles)
- Product Service (catalog, inventory)
- Order Service (order management)
- Payment Service (payment processing)
- Notification Service (emails, SMS)
Communication:
- Synchronous: REST/gRPC for queries
- Asynchronous: Kafka/RabbitMQ for events
Events:
- UserRegistered
- OrderCreated
- PaymentCompleted
- OrderShipped
Saga Pattern Example:
// Order Service publishes event
await events.publish('OrderCreated', {
orderId: order.id,
userId: order.userId,
total: order.total
});
// Payment Service listens
events.on('OrderCreated', async (data) => {
try {
const payment = await processPayment(data);
await events.publish('PaymentCompleted', payment);
} catch (error) {
await events.publish('PaymentFailed', { orderId: data.orderId });
}
});
// Order Service compensates on failure
events.on('PaymentFailed', async (data) => {
await Order.updateOne(
{ id: data.orderId },
{ status: 'cancelled' }
);
});
const DataLoader = require('dataloader');
// Create DataLoader for batch loading
const userLoader = new DataLoader(async (userIds) => {
const users = await db.query(
'SELECT * FROM users WHERE id = ANY($1)',
[userIds]
);
// Return in same order as input
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id));
});
// GraphQL resolver
const resolvers = {
Post: {
author: (post) => userLoader.load(post.authorId)
},
Query: {
posts: () => db.query('SELECT * FROM posts LIMIT 20')
}
};
// Result: 20 posts → 1 query for posts + 1 batched query for authors
// Without DataLoader: 20 posts → 1 query + 20 queries for authors!
// user.proto
syntax = "proto3";
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc CreateUser (CreateUserRequest) returns (User);
rpc StreamUsers (StreamUsersRequest) returns (stream User);
}
message User {
string id = 1;
string email = 2;
string name = 3;
int64 created_at = 4;
}
message GetUserRequest {
string id = 1;
}
// server.js
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync('user.proto');
const userProto = grpc.loadPackageDefinition(packageDefinition);
// Implement service
const server = new grpc.Server();
server.addService(userProto.UserService.service, {
GetUser: async (call, callback) => {
try {
const user = await db.query(
'SELECT * FROM users WHERE id = $1',
[call.request.id]
);
callback(null, user);
} catch (error) {
callback({
code: grpc.status.NOT_FOUND,
details: 'User not found'
});
}
},
StreamUsers: async (call) => {
const stream = db.stream('SELECT * FROM users');
stream.on('data', (user) => {
call.write(user);
});
stream.(, {
call.();
});
}
});
server.(
,
grpc..(),
{
.();
server.();
}
);
const promClient = require('prom-client');
// Create metrics
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.5, 1, 2, 5]
});
const httpRequestTotal = new promClient.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status_code']
});
const dbQueryDuration = new promClient.Histogram({
name: 'db_query_duration_seconds',
help: 'Duration of database queries',
labelNames: ['query_type'],
buckets: [0.01, 0.05, 0.1, 0.5, 1]
});
// Middleware
app.use((req, res, next) => {
const start = .();
res.(, {
duration = (.() - start) / ;
httpRequestDuration.(
{
: req.,
: req.?. || req.,
: res.
},
duration
);
httpRequestTotal.({
: req.,
: req.?. || req.,
: res.
});
});
();
});
app.(, (req, res) => {
res.(, promClient..);
res.( promClient..());
});
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: {
service: 'user-service',
environment: process.env.NODE_ENV
},
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// Usage
logger.info('User login successful', {
userId: user.id,
ip: req.ip,
userAgent: req.get('user-agent')
});
logger.(, {
: error.,
: error.,
: sql,
: params
});
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');
// Initialize tracer
const provider = new NodeTracerProvider();
provider.register();
registerInstrumentations({
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation()
]
});
// Manual tracing
const tracer = provider.getTracer('user-service');
app.get('/api/users/:id', async (req, res) => {
const span = tracer.startSpan('get_user');
try {
span.setAttribute('user.id', req.params.id);
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
span.({ : });
res.(user);
} (error) {
span.({ : , : error. });
res.().({ : error. });
} {
span.();
}
});
Required Implementations:
// 1. Consent Management
const ConsentSchema = new Schema({
userId: ObjectId,
type: {
type: String,
enum: ['marketing', 'third_party', 'profiling']
},
granted: Boolean,
grantedAt: Date,
expiresAt: Date,
ipAddress: String
});
// 2. Data Access Request (개인정보 열람 요구)
app.get('/api/users/me/data-export', authenticate, async (req, res) => {
const userData = {
personal: await User.findById(req.user.id).select('-password'),
orders: await Order.find({ userId: req.user.id }),
consents: await Consent.find({ userId: req.user.id }),
loginHistory: await LoginLog.({ : req.. }).()
};
res.(userData);
});
app.(, authenticate, (req, res) => {
userId = req..;
.(
{ : userId },
{
: ,
: (),
: ,
: ,
:
}
);
.(
{ userId },
{ : }
);
res.({ : });
});
() {
( user affectedUsers) {
emailService.({
: user.,
: ,
: ,
: {
: user.,
: (),
: [, ],
:
}
});
}
({
: (),
: affectedUsers.,
: [, ]
});
}
Transaction Logging Requirements:
// 모든 금융 거래는 5년간 보관
const TransactionLogSchema = new Schema({
transactionId: String,
userId: ObjectId,
type: {
type: String,
enum: ['payment', 'refund', 'withdrawal']
},
amount: Number,
status: String,
timestamp: { type: Date, default: Date.now },
ipAddress: String,
userAgent: String,
deviceId: String,
// 거래 당사자 정보
merchant: {
name: String,
businessNumber: String
}
});
// Index for efficient querying (5 years of data)
TransactionLogSchema.index({ userId: 1, timestamp: -1 });
TransactionLogSchema.index({ transactionId: 1 }, { unique: true });
// Automatic retention policy
.(
{ : },
{ : * * * * }
);
openapi: 3.1.0
info:
title: User Service API
version: 1.0.0
description: User management and authentication
contact:
email: dev@example.com
servers:
- url: https://api.example.com/v1
description: Production
- url: https://api-staging.example.com/v1
description: Staging
security:
- bearerAuth: []
paths:
/users:
get:
summary: List users
description: Returns a paginated list of users
tags:
- Users
parameters:
- name: page
in: query
schema:
type:
[, , ]
Good Question Format:
Problem: [Clear description of the issue]
Context:
- Tech stack: [e.g., Node.js 18, PostgreSQL 15, Redis 7]
- Environment: [Development/Staging/Production]
- Traffic: [e.g., 1000 req/min]
Current Implementation:
[Code snippet or architecture description]
What I've Tried:
1. [Attempt 1]
2. [Attempt 2]
Expected Behavior: [What should happen]
Actual Behavior: [What's happening]
Error Messages: [If any]
You'll receive:
This skill covers: ✅ Backend architecture and design ✅ API development (REST/GraphQL/gRPC) ✅ Database optimization ✅ Security best practices ✅ Performance tuning ✅ Korean regulations compliance
This skill does NOT cover: ❌ Frontend development (React, Vue, etc.) ❌ Mobile development (iOS, Android) ❌ Infrastructure as Code (Terraform, CloudFormation) ❌ Machine Learning / AI models ❌ Blockchain / Web3
For out-of-scope topics, I'll recommend appropriate resources.
Initial Release
Knowledge Base:
Usage Rights: Free to use for personal and commercial projects
Disclaimer:
Sources:
For First-Time Users:
Example Query:
"I need to optimize this API endpoint that's taking 3 seconds to respond.
Tech stack: Express.js + PostgreSQL
Current query: [SQL code]
Traffic: 500 requests/minute
Need: Under 500ms response time"
You'll get:
Ready to build better backends? Ask your first question! 🚀