Expert guide for automated and manual Web Accessibility (a11y) testing — axe-core, Pa11y, Playwright a11y, screen reader testing, and WCAG 2.2 Level AA/AAA compliance / Panduan ahli pengujian aksesibilitas web.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Expert guide for error handling patterns, resilience engineering, retry strategies, circuit breakers, and graceful degradation across React, Next.js, and Node.js / Panduan ahli pola penanganan error, rekayasa ketahanan, strategi retry, circuit breaker, dan degradasi anggun di React, Next.js, dan Node.js.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
<a name="english"></a>
Connects and orchestrates with relevant domain skills like brainstorming, zero-to-prod-orchestrator, and session-memory-manager to ensure cohesive execution.
Production-grade guide for building resilient applications that fail gracefully, recover automatically, and provide actionable error feedback to users and developers. Covers React Error Boundaries, Next.js error handling (error.tsx, global-error.tsx, not-found.tsx), API error response standards (RFC 9457 Problem Details), retry patterns with exponential backoff, circuit breaker patterns, dead letter queues, and Sentry/BugSnag integration.
Activate this skill when:
| Principle | Description |
|---|---|
| Fail Fast | Detect and report errors early; don't let invalid state propagate |
| Fail Gracefully | Show useful fallback UI, not blank screens or raw stack traces |
| Retry Intelligently | Use exponential backoff + jitter; never retry non-idempotent operations blindly |
| Isolate Failures | A failing component shouldn't crash the entire page |
| Track Everything | Every unhandled error must reach your monitoring system |
// components/error-boundary.tsx
'use client';
import { Component, type ErrorInfo, type ReactNode } from 'react';
interface Props {
children: ReactNode;
fallback: ReactNode | ((error: Error, reset: () => void) => ReactNode);
onError?: (error: Error, errorInfo: ErrorInfo) => void;
}
interface State {
hasError: boolean;
error: Error | null;
}
export class ErrorBoundary extends Component<Props, State> {
state: State = { hasError: false, error: null };
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.props.onError?.(error, errorInfo);
// Report to Sentry/BugSnag
if (typeof window !== 'undefined' && window.Sentry) {
window.Sentry.captureException(error, { extra: errorInfo });
}
}
reset = () => this.setState({ hasError: false, error: null });
render() {
if (this.state.hasError && this.state.error) {
const { fallback } = this.props;
return typeof fallback === 'function'
? fallback(this.state.error, this.reset)
: fallback;
}
return this.props.children;
}
}
// app/error.tsx — Route-level error handler
'use client';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div role="alert" className="error-container">
<h2>Something went wrong</h2>
<p>{error.message}</p>
{error.digest && <p className="text-muted">Error ID: {error.digest}</p>}
<button onClick={reset}>Try again</button>
</div>
);
}
// app/not-found.tsx — 404 handler
export default function NotFound() {
return (
<div>
<h2>Page Not Found</h2>
<p>The page you are looking for does not exist.</p>
</div>
);
}
// app/global-error.tsx — Root layout error handler (catches layout errors)
'use client';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html>
<body>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</body>
</html>
);
}
// lib/api-error.ts
export class ApiError extends Error {
constructor(
public readonly status: number,
public readonly code: string,
message: string,
public readonly details?: Record<string, unknown>,
) {
super(message);
this.name = 'ApiError';
}
/** RFC 9457 Problem Details JSON response */
toJSON() {
return {
type: `https://api.example.com/errors/${this.code}`,
title: this.code.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
status: this.status,
detail: this.message,
...(this.details && { extensions: this.details }),
};
}
}
// Usage in API route
export async function POST(request: Request) {
try {
const body = await request.json();
const parsed = createUserSchema.safeParse(body);
if (!parsed.success) {
throw new ApiError(422, 'validation_error', 'Invalid request body', {
errors: parsed.error.flatten().fieldErrors,
});
}
const user = { id: 'usr_101', ...parsed.data };
return Response.json(user, { status: 201 });
} catch (error) {
if (error instanceof ApiError) {
return Response.json(error.toJSON(), { status: error.status });
}
// Unexpected error — log and return generic 500
console.error('Unhandled error:', error);
return Response.json(
{ type: 'about:blank', title: 'Internal Server Error', status: 500 },
{ status: 500 },
);
}
}
// lib/retry.ts
interface RetryOptions {
maxRetries?: number;
baseDelayMs?: number;
maxDelayMs?: number;
/** Only retry if this returns true */
retryIf?: (error: unknown) => boolean;
onRetry?: (attempt: number, error: unknown) => void;
}
export async function withRetry<T>(
fn: () => Promise<T>,
options: RetryOptions = {},
): Promise<T> {
const {
maxRetries = 3,
baseDelayMs = 500,
maxDelayMs = 30_000,
retryIf = isRetryable,
onRetry,
} = options;
let lastError: unknown;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (attempt === maxRetries || !retryIf(error)) {
throw error;
}
// Exponential backoff with jitter
const delay = Math.min(
baseDelayMs * 2 ** attempt + Math.random() * baseDelayMs,
maxDelayMs,
);
onRetry?.(attempt + 1, error);
await sleep(delay);
}
}
throw lastError;
}
function isRetryable(error: unknown): boolean {
if (error instanceof ApiError) {
// Retry 429 (rate limit), 502/503/504 (server errors)
return [429, 502, 503, 504].includes(error.status);
}
// Retry network errors
if (error instanceof TypeError && error.message.includes('fetch')) return true;
return false;
}
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
// lib/circuit-breaker.ts
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
interface CircuitBreakerOptions {
failureThreshold?: number;
resetTimeoutMs?: number;
halfOpenMaxAttempts?: number;
}
export class CircuitBreaker {
private state: CircuitState = 'CLOSED';
private failureCount = 0;
private lastFailureTime = 0;
private halfOpenAttempts = 0;
constructor(
private readonly name: string,
private readonly options: CircuitBreakerOptions = {},
) {}
private get failureThreshold() { return this.options.failureThreshold ?? 5; }
private get resetTimeoutMs() { return this.options.resetTimeoutMs ?? 60_000; }
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {
this.state = 'HALF_OPEN';
this.halfOpenAttempts = 0;
} else {
throw new Error(`Circuit breaker "${this.name}" is OPEN`);
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
private onFailure() {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.failureThreshold) {
this.state = 'OPEN';
}
}
getState(): CircuitState { return this.state; }
}
// Usage
const paymentCircuit = new CircuitBreaker('stripe-api', {
failureThreshold: 3,
resetTimeoutMs: 30_000,
});
const charge = await paymentCircuit.execute(() =>
stripe.paymentIntents.create({ amount: 1000, currency: 'usd' })
);
// components/resilient-data.tsx
'use client';
import { useSuspenseQuery } from '@tanstack/react-query';
import { Suspense } from 'react';
import { ErrorBoundary } from './error-boundary';
// Pattern: Wrap data-dependent UI with ErrorBoundary + Suspense
export function ResilientDataSection() {
return (
<ErrorBoundary
fallback={(error, reset) => (
<div className="degraded-state">
<p>Unable to load latest data. Showing cached version.</p>
<button onClick={reset}>Retry</button>
</div>
)}
>
<Suspense fallback={<DataSkeleton />}>
<LiveDataSection />
</Suspense>
</ErrorBoundary>
);
}
// queues/dead-letter.ts
import { Queue, Worker } from 'bullmq';
const mainQueue = new Queue('email-send', { connection: redis });
const deadLetterQueue = new Queue('email-send-dlq', { connection: redis });
const worker = new Worker('email-send', async (job) => {
await sendEmail(job.data);
}, {
connection: redis,
settings: {
backoffStrategy: (attemptsMade) => {
// Exponential backoff: 1s, 4s, 16s, 64s
return Math.min(1000 * 4 ** attemptsMade, 120_000);
},
},
});
worker.on('failed', async (job, err) => {
if (job && job.attemptsMade >= (job.opts.attempts ?? 3)) {
// Move to dead letter queue for manual investigation
await deadLetterQueue.add('failed-email', {
originalJobId: job.id,
data: job.data,
error: err.message,
failedAt: new Date().toISOString(),
});
}
});
| Anti-Pattern | Problem | Correct Approach |
|---|---|---|
Catching errors silently (catch (e) {}) | Errors disappear, bugs hide | Always log or re-throw with context |
| Retrying non-idempotent operations | Duplicate charges, double inserts | Only retry reads and idempotent writes |
| No timeout on external calls | Thread/connection pool exhaustion | Set AbortSignal.timeout() on all fetch calls |
| Generic "Something went wrong" for all errors | Users can't self-resolve | Show actionable messages (retry, contact support, check input) |
Using try/catch around every single line | Code becomes unreadable | Use error boundaries and middleware for batch handling |
js-backend-expert — API middleware error handling and response formattingsenior-frontend — React Error Boundaries and Suspense patternsdatabase-orm-expert — Transaction error handling and rollback patternslogging-error-tracking-expert — Sentry/BugSnag integration and structured error loggingasync-queue-temporal-expert — Dead letter queues and retry strategies for background jobsproduction-ready-hardener — Pre-launch error handling audit checklistapi-design-expert — RFC 9457 error response specification<a name="bahasa-indonesia"></a>
Terhubung dan mengorkestrasi skill domain yang relevan seperti brainstorming, zero-to-prod-orchestrator, dan session-memory-manager untuk memastikan eksekusi yang kohesif.
Panduan tingkat produksi untuk membangun aplikasi yang tahan banting — gagal secara anggun, pulih otomatis, dan memberikan umpan balik error yang dapat ditindaklanjuti kepada pengguna maupun developer. Mencakup React Error Boundaries, penanganan error Next.js (error.tsx, global-error.tsx, not-found.tsx), standar respons error API (RFC 9457 Problem Details), pola retry dengan exponential backoff, pola circuit breaker, dead letter queues, dan integrasi Sentry/BugSnag.
Aktifkan skill ini ketika:
| Prinsip | Deskripsi |
|---|---|
| Gagal Cepat | Deteksi dan laporkan error sedini mungkin; jangan biarkan state invalid menyebar |
| Gagal dengan Anggun | Tampilkan UI fallback yang berguna, bukan layar kosong atau stack trace mentah |
| Retry dengan Cerdas | Gunakan exponential backoff + jitter; jangan retry operasi non-idempoten secara membabi buta |
| Isolasi Kegagalan | Komponen yang gagal tidak boleh menghancurkan seluruh halaman |
| Lacak Semuanya | Setiap error yang tidak tertangani harus sampai ke sistem monitoring |
| Anti-Pola | Masalah | Pendekatan yang Benar |
|---|---|---|
Menangkap error diam-diam (catch (e) {}) | Error menghilang, bug tersembunyi | Selalu log atau lempar ulang dengan konteks |
| Retry operasi non-idempoten | Charge ganda, insert duplikat | Hanya retry operasi baca dan write idempoten |
| Tidak ada timeout pada panggilan eksternal | Thread/pool koneksi habis | Pasang AbortSignal.timeout() pada semua panggilan fetch |
| Pesan generik "Terjadi kesalahan" untuk semua error | Pengguna tidak bisa menyelesaikan sendiri | Tampilkan pesan yang actionable (retry, hubungi support, periksa input) |
js-backend-expert — Middleware penanganan error API dan pemformatan responssenior-frontend — React Error Boundaries dan pola Suspensedatabase-orm-expert — Penanganan error transaksi dan pola rollbacklogging-error-tracking-expert — Integrasi Sentry/BugSnag dan logging error terstrukturasync-queue-temporal-expert — Dead letter queue dan strategi retry untuk background jobproduction-ready-hardener — Checklist audit penanganan error sebelum peluncuranapi-design-expert — Spesifikasi respons error RFC 9457아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Expert guide for automated and manual Web Accessibility (a11y) testing — axe-core, Pa11y, Playwright a11y, screen reader testing, and WCAG 2.2 Level AA/AAA compliance / Panduan ahli pengujian aksesibilitas web.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Expert guide for intelligent model cascading and routing — complexity-scored task routing from Flash/Haiku to Sonnet/Opus/Astra, dynamic escalation with quality gates, 40-60% token cost reduction while maintaining output quality / Panduan ahli untuk kaskade dan routing model cerdas — routing tugas berbasis skor kompleksitas dari Flash/Haiku ke Sonnet/Opus/Astra, eskalasi dinamis dengan gerbang kualitas, pengurangan biaya token 40-60% dengan kualitas output terjaga.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Expert guide for Affective Computing, emotional AI, and real-time sentiment analysis through native multimodal tokens (voice intonation and facial micro-expressions) / Panduan ahli komputasi afektif, AI emosional, dan analisis sentimen real-time melalui token multimodal native.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Expert guide for AI-assisted coding workflows — agentic code generation, multi-agent code swarms, self-healing CI/CD, automated PR review, spec-to-code pipelines, codebase knowledge graphs, and human-in-the-loop approval gates / Panduan ahli untuk workflow pengkodean berbasis AI — generasi kode agentic, code swarm multi-agen, CI/CD self-healing, review PR otomatis, pipeline spec-to-code, knowledge graph codebase, dan gate persetujuan human-in-the-loop.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Expert guide for autonomous Machine-to-Machine (M2M) agent settlement, dual-rail fiat & stablecoin micro-clearing, dynamic budget envelopes, and cryptographic agent invoicing / Panduan ahli settlement otonom antar-agen (M2M), kliring mikro dual-rail fiat & stablecoin, pagu anggaran dinamis, dan penagihan agen kriptografis.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Expert guide for long-term episodic memory integration (Mem0 v2, Letta/MemGPT, Zep v2), memory tier architecture, pgvector HNSW storage, and unified context management for autonomous AI agents / Panduan ahli untuk integrasi memori episodik jangka panjang (Mem0 v2, Letta/MemGPT, Zep v2), arsitektur tier memori, penyimpanan pgvector HNSW, dan manajemen konteks terpadu untuk agen AI otonom.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.