vibes-plug 1.0.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +20 -0
- package/AGENTS.md +66 -0
- package/BLUEPRINT.md +152 -60
- package/CHANGELOG.md +50 -0
- package/README.md +346 -194
- package/package.json +25 -25
- package/plugin.json +1 -1
- package/skills/ai-cost-token-optimizer/SKILL.md +52 -0
- package/skills/ai-llm-integration-expert/SKILL.md +180 -162
- package/skills/api-design-expert/SKILL.md +314 -310
- package/skills/app-analyzer-optimizer/SKILL.md +193 -189
- package/skills/apple-ecosystem-expert/SKILL.md +142 -0
- package/skills/async-queue-temporal-expert/SKILL.md +54 -0
- package/skills/authentication-identity-expert/SKILL.md +251 -20
- package/skills/auto-doc-updater/SKILL.md +214 -204
- package/skills/autonomous-chaos-monkey/SKILL.md +63 -0
- package/skills/autonomous-red-teamer/SKILL.md +59 -0
- package/skills/autonomous-swarm-director/SKILL.md +69 -0
- package/skills/autonomous-tdd-debugger/SKILL.md +65 -0
- package/skills/bootstrap-to-modern/SKILL.md +90 -86
- package/skills/brainstorming/SKILL.md +373 -353
- package/skills/browser-automation-expert/SKILL.md +46 -0
- package/skills/ci-cd-devops-architect/SKILL.md +72 -45
- package/skills/cloud-hosting-expert/SKILL.md +244 -244
- package/skills/coderabbit/SKILL.md +192 -192
- package/skills/cron-scheduler-expert/SKILL.md +298 -0
- package/skills/data-telemetry-expert/SKILL.md +213 -213
- package/skills/database-orm-expert/SKILL.md +294 -294
- package/skills/dependency-upgrade-migrator/SKILL.md +295 -0
- package/skills/design-system-architect/SKILL.md +27 -10
- package/skills/doku-mcp-server/SKILL.md +251 -0
- package/skills/doku-payment-gateway/SKILL.md +227 -0
- package/skills/e2e-testing-expert/SKILL.md +315 -315
- package/skills/edge-serverless-db-expert/SKILL.md +43 -0
- package/skills/email-notification-expert/SKILL.md +362 -0
- package/skills/error-resilience-expert/SKILL.md +480 -0
- package/skills/event-driven-architect/SKILL.md +81 -81
- package/skills/feature-flag-analytics-expert/SKILL.md +46 -0
- package/skills/file-upload-media-expert/SKILL.md +431 -0
- package/skills/form-validation-expert/SKILL.md +401 -0
- package/skills/fullstack-expert/SKILL.md +202 -202
- package/skills/fullstack-expert/references/api_design_guide.md +466 -466
- package/skills/fullstack-expert/references/multi_language_backend.md +528 -528
- package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -253
- package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -326
- package/skills/gemini-agent-booster/SKILL.md +135 -135
- package/skills/global-a11y-i18n-expert/SKILL.md +81 -81
- package/skills/glsl-shader-expert/SKILL.md +101 -0
- package/skills/go-programming-expert/SKILL.md +295 -295
- package/skills/graphql-apollo-expert/SKILL.md +108 -0
- package/skills/hig/SKILL.md +188 -188
- package/skills/hyper-context-synthesizer/SKILL.md +55 -0
- package/skills/js-backend-expert/SKILL.md +34 -9
- package/skills/legacy-code-translator/SKILL.md +65 -0
- package/skills/llm-cost-arbitrage-router/SKILL.md +59 -0
- package/skills/logging-error-tracking-expert/SKILL.md +338 -0
- package/skills/mcp-client-orchestrator/SKILL.md +70 -0
- package/skills/mcp-server-architect/SKILL.md +194 -194
- package/skills/micro-frontend-architect/SKILL.md +106 -0
- package/skills/mobile-expo-expert/SKILL.md +186 -186
- package/skills/mobile-push-notification-expert/SKILL.md +51 -0
- package/skills/monday-design-aesthetic/SKILL.md +67 -67
- package/skills/monorepo-architect/SKILL.md +227 -227
- package/skills/mpa-orchestrator/SKILL.md +101 -101
- package/skills/multi-agent-orchestration/SKILL.md +234 -234
- package/skills/multiple-entry-points/SKILL.md +55 -55
- package/skills/mvc-expert/SKILL.md +231 -231
- package/skills/payment-gateway-expert/SKILL.md +45 -45
- package/skills/performance-web-vitals/SKILL.md +332 -332
- package/skills/post-quantum-crypto-migrator/SKILL.md +57 -0
- package/skills/prd-architect/SKILL.md +201 -191
- package/skills/proactive-background-watcher/SKILL.md +62 -0
- package/skills/production-ready-hardener/PRODUCTION_READINESS_REPORT.md +67 -0
- package/skills/production-ready-hardener/SKILL.md +173 -186
- package/skills/production-ready-hardener/references/production_checklist.md +161 -161
- package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +881 -875
- package/skills/project-context-mapper/SKILL.md +79 -0
- package/skills/python-programming-expert/SKILL.md +263 -132
- package/skills/rate-limit-abuse-prevention/SKILL.md +371 -0
- package/skills/realtime-collaboration-expert/SKILL.md +45 -45
- package/skills/rust-programming-expert/SKILL.md +235 -235
- package/skills/saas-billing/SKILL.md +377 -377
- package/skills/saas-multi-tenant/SKILL.md +251 -237
- package/skills/saas-mvp-launcher/SKILL.md +10 -0
- package/skills/saas-transformer/SKILL.md +187 -144
- package/skills/saas-transformer/references/billing_integration_guide.md +401 -401
- package/skills/saas-transformer/references/feature_gating_patterns.md +137 -137
- package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -121
- package/skills/saas-transformer/scripts/saas_transformation_scanner.py +39 -29
- package/skills/scalability-clean-code/SKILL.md +229 -229
- package/skills/self-evolving-memory-graph/SKILL.md +75 -0
- package/skills/self-healing-cloud-orchestrator/SKILL.md +57 -0
- package/skills/senior-frontend/SKILL.md +161 -161
- package/skills/senior-fullstack/SKILL.md +167 -167
- package/skills/seo/SKILL.md +235 -225
- package/skills/seo-geo/SKILL.md +188 -188
- package/skills/session-context-loader/SKILL.md +77 -0
- package/skills/session-handoff-resume/SKILL.md +158 -158
- package/skills/skill_baru/SKILL.md +172 -147
- package/skills/spa-orchestrator/SKILL.md +288 -288
- package/skills/state-management-expert/SKILL.md +272 -272
- package/skills/supabase-security-expert/SKILL.md +243 -243
- package/skills/tailwind-expert/SKILL.md +188 -188
- package/skills/tanstack-query-expert/SKILL.md +199 -199
- package/skills/token-saver/SKILL.md +119 -111
- package/skills/typescript-expert/SKILL.md +324 -279
- package/skills/ui-components-expert/SKILL.md +263 -46
- package/skills/ui-ux-pro-max/SKILL.md +202 -201
- package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
- package/skills/ui_ux_expert/SKILL.md +17 -6
- package/skills/vector-db-rag-expert/SKILL.md +52 -0
- package/skills/vibe-code-gardener/SKILL.md +181 -173
- package/skills/visual-qa-vision-agent/SKILL.md +65 -0
- package/skills/vue-frontend-expert/SKILL.md +126 -0
- package/skills/web-3d-graphics-expert/SKILL.md +131 -0
- package/skills/web-game-engine-expert/SKILL.md +96 -0
- package/skills/web-scraper/SKILL.md +207 -205
- package/skills/website-design-cloner/SKILL.md +174 -0
- package/skills/webxr-ar-vr-expert/SKILL.md +117 -0
- package/skills/zero-to-prod-orchestrator/SKILL.md +206 -180
- package/skills/zero-trust-secret-vault/SKILL.md +40 -0
- package/vibes-swarm-demo.gif +0 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: error-resilience-expert
|
|
3
|
+
description: "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."
|
|
4
|
+
author: "Roedy Rustam"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Error & Resilience Expert (2026 Edition)
|
|
8
|
+
|
|
9
|
+
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<a name="english"></a>
|
|
14
|
+
## English
|
|
15
|
+
|
|
16
|
+
### Description
|
|
17
|
+
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.
|
|
18
|
+
|
|
19
|
+
### Trigger Conditions
|
|
20
|
+
Activate this skill when:
|
|
21
|
+
- Setting up error handling for React/Next.js applications.
|
|
22
|
+
- Implementing retry logic for unreliable API calls or third-party services.
|
|
23
|
+
- Designing circuit breaker patterns for microservice-to-microservice calls.
|
|
24
|
+
- Building fallback UI for degraded service states.
|
|
25
|
+
- Integrating error tracking tools (Sentry, BugSnag, LogRocket).
|
|
26
|
+
- Handling transaction failures in database operations.
|
|
27
|
+
- Designing dead letter queues for failed async jobs.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### Core Concepts
|
|
32
|
+
|
|
33
|
+
#### Error Handling Philosophy
|
|
34
|
+
|
|
35
|
+
| Principle | Description |
|
|
36
|
+
|---|---|
|
|
37
|
+
| **Fail Fast** | Detect and report errors early; don't let invalid state propagate |
|
|
38
|
+
| **Fail Gracefully** | Show useful fallback UI, not blank screens or raw stack traces |
|
|
39
|
+
| **Retry Intelligently** | Use exponential backoff + jitter; never retry non-idempotent operations blindly |
|
|
40
|
+
| **Isolate Failures** | A failing component shouldn't crash the entire page |
|
|
41
|
+
| **Track Everything** | Every unhandled error must reach your monitoring system |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### 1. React & Next.js Error Handling
|
|
46
|
+
|
|
47
|
+
#### Error Boundaries (React 19)
|
|
48
|
+
```tsx
|
|
49
|
+
// components/error-boundary.tsx
|
|
50
|
+
'use client';
|
|
51
|
+
|
|
52
|
+
import { Component, type ErrorInfo, type ReactNode } from 'react';
|
|
53
|
+
|
|
54
|
+
interface Props {
|
|
55
|
+
children: ReactNode;
|
|
56
|
+
fallback: ReactNode | ((error: Error, reset: () => void) => ReactNode);
|
|
57
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface State {
|
|
61
|
+
hasError: boolean;
|
|
62
|
+
error: Error | null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class ErrorBoundary extends Component<Props, State> {
|
|
66
|
+
state: State = { hasError: false, error: null };
|
|
67
|
+
|
|
68
|
+
static getDerivedStateFromError(error: Error): State {
|
|
69
|
+
return { hasError: true, error };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|
73
|
+
this.props.onError?.(error, errorInfo);
|
|
74
|
+
// Report to Sentry/BugSnag
|
|
75
|
+
if (typeof window !== 'undefined' && window.Sentry) {
|
|
76
|
+
window.Sentry.captureException(error, { extra: errorInfo });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
reset = () => this.setState({ hasError: false, error: null });
|
|
81
|
+
|
|
82
|
+
render() {
|
|
83
|
+
if (this.state.hasError && this.state.error) {
|
|
84
|
+
const { fallback } = this.props;
|
|
85
|
+
return typeof fallback === 'function'
|
|
86
|
+
? fallback(this.state.error, this.reset)
|
|
87
|
+
: fallback;
|
|
88
|
+
}
|
|
89
|
+
return this.props.children;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### Next.js App Router Error Files
|
|
95
|
+
```tsx
|
|
96
|
+
// app/error.tsx — Route-level error handler
|
|
97
|
+
'use client';
|
|
98
|
+
|
|
99
|
+
export default function Error({
|
|
100
|
+
error,
|
|
101
|
+
reset,
|
|
102
|
+
}: {
|
|
103
|
+
error: Error & { digest?: string };
|
|
104
|
+
reset: () => void;
|
|
105
|
+
}) {
|
|
106
|
+
return (
|
|
107
|
+
<div role="alert" className="error-container">
|
|
108
|
+
<h2>Something went wrong</h2>
|
|
109
|
+
<p>{error.message}</p>
|
|
110
|
+
{error.digest && <p className="text-muted">Error ID: {error.digest}</p>}
|
|
111
|
+
<button onClick={reset}>Try again</button>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// app/not-found.tsx — 404 handler
|
|
117
|
+
export default function NotFound() {
|
|
118
|
+
return (
|
|
119
|
+
<div>
|
|
120
|
+
<h2>Page Not Found</h2>
|
|
121
|
+
<p>The page you are looking for does not exist.</p>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// app/global-error.tsx — Root layout error handler (catches layout errors)
|
|
127
|
+
'use client';
|
|
128
|
+
|
|
129
|
+
export default function GlobalError({
|
|
130
|
+
error,
|
|
131
|
+
reset,
|
|
132
|
+
}: {
|
|
133
|
+
error: Error & { digest?: string };
|
|
134
|
+
reset: () => void;
|
|
135
|
+
}) {
|
|
136
|
+
return (
|
|
137
|
+
<html>
|
|
138
|
+
<body>
|
|
139
|
+
<h2>Something went wrong!</h2>
|
|
140
|
+
<button onClick={reset}>Try again</button>
|
|
141
|
+
</body>
|
|
142
|
+
</html>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### 2. API Error Response Standards (RFC 9457)
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// lib/api-error.ts
|
|
153
|
+
export class ApiError extends Error {
|
|
154
|
+
constructor(
|
|
155
|
+
public readonly status: number,
|
|
156
|
+
public readonly code: string,
|
|
157
|
+
message: string,
|
|
158
|
+
public readonly details?: Record<string, unknown>,
|
|
159
|
+
) {
|
|
160
|
+
super(message);
|
|
161
|
+
this.name = 'ApiError';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** RFC 9457 Problem Details JSON response */
|
|
165
|
+
toJSON() {
|
|
166
|
+
return {
|
|
167
|
+
type: `https://api.example.com/errors/${this.code}`,
|
|
168
|
+
title: this.code.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
|
|
169
|
+
status: this.status,
|
|
170
|
+
detail: this.message,
|
|
171
|
+
...(this.details && { extensions: this.details }),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Usage in API route
|
|
177
|
+
export async function POST(request: Request) {
|
|
178
|
+
try {
|
|
179
|
+
const body = await request.json();
|
|
180
|
+
const parsed = createUserSchema.safeParse(body);
|
|
181
|
+
if (!parsed.success) {
|
|
182
|
+
throw new ApiError(422, 'validation_error', 'Invalid request body', {
|
|
183
|
+
errors: parsed.error.flatten().fieldErrors,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
// ...business logic
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (error instanceof ApiError) {
|
|
189
|
+
return Response.json(error.toJSON(), { status: error.status });
|
|
190
|
+
}
|
|
191
|
+
// Unexpected error — log and return generic 500
|
|
192
|
+
console.error('Unhandled error:', error);
|
|
193
|
+
return Response.json(
|
|
194
|
+
{ type: 'about:blank', title: 'Internal Server Error', status: 500 },
|
|
195
|
+
{ status: 500 },
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### 3. Retry Patterns with Exponential Backoff
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// lib/retry.ts
|
|
207
|
+
interface RetryOptions {
|
|
208
|
+
maxRetries?: number;
|
|
209
|
+
baseDelayMs?: number;
|
|
210
|
+
maxDelayMs?: number;
|
|
211
|
+
/** Only retry if this returns true */
|
|
212
|
+
retryIf?: (error: unknown) => boolean;
|
|
213
|
+
onRetry?: (attempt: number, error: unknown) => void;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export async function withRetry<T>(
|
|
217
|
+
fn: () => Promise<T>,
|
|
218
|
+
options: RetryOptions = {},
|
|
219
|
+
): Promise<T> {
|
|
220
|
+
const {
|
|
221
|
+
maxRetries = 3,
|
|
222
|
+
baseDelayMs = 500,
|
|
223
|
+
maxDelayMs = 30_000,
|
|
224
|
+
retryIf = isRetryable,
|
|
225
|
+
onRetry,
|
|
226
|
+
} = options;
|
|
227
|
+
|
|
228
|
+
let lastError: unknown;
|
|
229
|
+
|
|
230
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
231
|
+
try {
|
|
232
|
+
return await fn();
|
|
233
|
+
} catch (error) {
|
|
234
|
+
lastError = error;
|
|
235
|
+
|
|
236
|
+
if (attempt === maxRetries || !retryIf(error)) {
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Exponential backoff with jitter
|
|
241
|
+
const delay = Math.min(
|
|
242
|
+
baseDelayMs * 2 ** attempt + Math.random() * baseDelayMs,
|
|
243
|
+
maxDelayMs,
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
onRetry?.(attempt + 1, error);
|
|
247
|
+
await sleep(delay);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
throw lastError;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function isRetryable(error: unknown): boolean {
|
|
255
|
+
if (error instanceof ApiError) {
|
|
256
|
+
// Retry 429 (rate limit), 502/503/504 (server errors)
|
|
257
|
+
return [429, 502, 503, 504].includes(error.status);
|
|
258
|
+
}
|
|
259
|
+
// Retry network errors
|
|
260
|
+
if (error instanceof TypeError && error.message.includes('fetch')) return true;
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### 4. Circuit Breaker Pattern
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// lib/circuit-breaker.ts
|
|
273
|
+
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
|
|
274
|
+
|
|
275
|
+
interface CircuitBreakerOptions {
|
|
276
|
+
failureThreshold?: number;
|
|
277
|
+
resetTimeoutMs?: number;
|
|
278
|
+
halfOpenMaxAttempts?: number;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export class CircuitBreaker {
|
|
282
|
+
private state: CircuitState = 'CLOSED';
|
|
283
|
+
private failureCount = 0;
|
|
284
|
+
private lastFailureTime = 0;
|
|
285
|
+
private halfOpenAttempts = 0;
|
|
286
|
+
|
|
287
|
+
constructor(
|
|
288
|
+
private readonly name: string,
|
|
289
|
+
private readonly options: CircuitBreakerOptions = {},
|
|
290
|
+
) {}
|
|
291
|
+
|
|
292
|
+
private get failureThreshold() { return this.options.failureThreshold ?? 5; }
|
|
293
|
+
private get resetTimeoutMs() { return this.options.resetTimeoutMs ?? 60_000; }
|
|
294
|
+
|
|
295
|
+
async execute<T>(fn: () => Promise<T>): Promise<T> {
|
|
296
|
+
if (this.state === 'OPEN') {
|
|
297
|
+
if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {
|
|
298
|
+
this.state = 'HALF_OPEN';
|
|
299
|
+
this.halfOpenAttempts = 0;
|
|
300
|
+
} else {
|
|
301
|
+
throw new Error(`Circuit breaker "${this.name}" is OPEN`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const result = await fn();
|
|
307
|
+
this.onSuccess();
|
|
308
|
+
return result;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
this.onFailure();
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private onSuccess() {
|
|
316
|
+
this.failureCount = 0;
|
|
317
|
+
this.state = 'CLOSED';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private onFailure() {
|
|
321
|
+
this.failureCount++;
|
|
322
|
+
this.lastFailureTime = Date.now();
|
|
323
|
+
if (this.failureCount >= this.failureThreshold) {
|
|
324
|
+
this.state = 'OPEN';
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
getState(): CircuitState { return this.state; }
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Usage
|
|
332
|
+
const paymentCircuit = new CircuitBreaker('stripe-api', {
|
|
333
|
+
failureThreshold: 3,
|
|
334
|
+
resetTimeoutMs: 30_000,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const charge = await paymentCircuit.execute(() =>
|
|
338
|
+
stripe.paymentIntents.create({ amount: 1000, currency: 'usd' })
|
|
339
|
+
);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### 5. Graceful Degradation & Fallback UI
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
// components/resilient-data.tsx
|
|
348
|
+
'use client';
|
|
349
|
+
|
|
350
|
+
import { useSuspenseQuery } from '@tanstack/react-query';
|
|
351
|
+
import { Suspense } from 'react';
|
|
352
|
+
import { ErrorBoundary } from './error-boundary';
|
|
353
|
+
|
|
354
|
+
// Pattern: Wrap data-dependent UI with ErrorBoundary + Suspense
|
|
355
|
+
export function ResilientDataSection() {
|
|
356
|
+
return (
|
|
357
|
+
<ErrorBoundary
|
|
358
|
+
fallback={(error, reset) => (
|
|
359
|
+
<div className="degraded-state">
|
|
360
|
+
<p>Unable to load latest data. Showing cached version.</p>
|
|
361
|
+
<button onClick={reset}>Retry</button>
|
|
362
|
+
</div>
|
|
363
|
+
)}
|
|
364
|
+
>
|
|
365
|
+
<Suspense fallback={<DataSkeleton />}>
|
|
366
|
+
<LiveDataSection />
|
|
367
|
+
</Suspense>
|
|
368
|
+
</ErrorBoundary>
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
### 6. Dead Letter Queue for Failed Jobs
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
// queues/dead-letter.ts
|
|
379
|
+
import { Queue, Worker } from 'bullmq';
|
|
380
|
+
|
|
381
|
+
const mainQueue = new Queue('email-send', { connection: redis });
|
|
382
|
+
const deadLetterQueue = new Queue('email-send-dlq', { connection: redis });
|
|
383
|
+
|
|
384
|
+
const worker = new Worker('email-send', async (job) => {
|
|
385
|
+
await sendEmail(job.data);
|
|
386
|
+
}, {
|
|
387
|
+
connection: redis,
|
|
388
|
+
settings: {
|
|
389
|
+
backoffStrategy: (attemptsMade) => {
|
|
390
|
+
// Exponential backoff: 1s, 4s, 16s, 64s
|
|
391
|
+
return Math.min(1000 * 4 ** attemptsMade, 120_000);
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
worker.on('failed', async (job, err) => {
|
|
397
|
+
if (job && job.attemptsMade >= (job.opts.attempts ?? 3)) {
|
|
398
|
+
// Move to dead letter queue for manual investigation
|
|
399
|
+
await deadLetterQueue.add('failed-email', {
|
|
400
|
+
originalJobId: job.id,
|
|
401
|
+
data: job.data,
|
|
402
|
+
error: err.message,
|
|
403
|
+
failedAt: new Date().toISOString(),
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### Common Pitfalls to Avoid
|
|
412
|
+
|
|
413
|
+
| Anti-Pattern | Problem | Correct Approach |
|
|
414
|
+
|---|---|---|
|
|
415
|
+
| Catching errors silently (`catch (e) {}`) | Errors disappear, bugs hide | Always log or re-throw with context |
|
|
416
|
+
| Retrying non-idempotent operations | Duplicate charges, double inserts | Only retry reads and idempotent writes |
|
|
417
|
+
| No timeout on external calls | Thread/connection pool exhaustion | Set `AbortSignal.timeout()` on all fetch calls |
|
|
418
|
+
| Generic "Something went wrong" for all errors | Users can't self-resolve | Show actionable messages (retry, contact support, check input) |
|
|
419
|
+
| Using `try/catch` around every single line | Code becomes unreadable | Use error boundaries and middleware for batch handling |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### Integration with Other Skills
|
|
424
|
+
|
|
425
|
+
- `js-backend-expert` — API middleware error handling and response formatting
|
|
426
|
+
- `senior-frontend` — React Error Boundaries and Suspense patterns
|
|
427
|
+
- `database-orm-expert` — Transaction error handling and rollback patterns
|
|
428
|
+
- `logging-error-tracking-expert` — Sentry/BugSnag integration and structured error logging
|
|
429
|
+
- `async-queue-temporal-expert` — Dead letter queues and retry strategies for background jobs
|
|
430
|
+
- `production-ready-hardener` — Pre-launch error handling audit checklist
|
|
431
|
+
- `api-design-expert` — RFC 9457 error response specification
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
<a name="bahasa-indonesia"></a>
|
|
436
|
+
## Bahasa Indonesia
|
|
437
|
+
|
|
438
|
+
### Deskripsi
|
|
439
|
+
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**.
|
|
440
|
+
|
|
441
|
+
### Kondisi Pemicu
|
|
442
|
+
Aktifkan skill ini ketika:
|
|
443
|
+
- Menyiapkan penanganan error untuk aplikasi React/Next.js.
|
|
444
|
+
- Mengimplementasikan logika retry untuk panggilan API yang tidak stabil atau layanan pihak ketiga.
|
|
445
|
+
- Merancang pola circuit breaker untuk panggilan antar-microservice.
|
|
446
|
+
- Membangun UI fallback untuk kondisi layanan terdegradasi.
|
|
447
|
+
- Mengintegrasikan alat pelacak error (Sentry, BugSnag, LogRocket).
|
|
448
|
+
- Menangani kegagalan transaksi pada operasi database.
|
|
449
|
+
- Merancang dead letter queue untuk job asinkron yang gagal.
|
|
450
|
+
|
|
451
|
+
### Konsep Inti
|
|
452
|
+
|
|
453
|
+
#### Filosofi Penanganan Error
|
|
454
|
+
|
|
455
|
+
| Prinsip | Deskripsi |
|
|
456
|
+
|---|---|
|
|
457
|
+
| **Gagal Cepat** | Deteksi dan laporkan error sedini mungkin; jangan biarkan state invalid menyebar |
|
|
458
|
+
| **Gagal dengan Anggun** | Tampilkan UI fallback yang berguna, bukan layar kosong atau stack trace mentah |
|
|
459
|
+
| **Retry dengan Cerdas** | Gunakan exponential backoff + jitter; jangan retry operasi non-idempoten secara membabi buta |
|
|
460
|
+
| **Isolasi Kegagalan** | Komponen yang gagal tidak boleh menghancurkan seluruh halaman |
|
|
461
|
+
| **Lacak Semuanya** | Setiap error yang tidak tertangani harus sampai ke sistem monitoring |
|
|
462
|
+
|
|
463
|
+
### Kesalahan Umum yang Harus Dihindari
|
|
464
|
+
|
|
465
|
+
| Anti-Pola | Masalah | Pendekatan yang Benar |
|
|
466
|
+
|---|---|---|
|
|
467
|
+
| Menangkap error diam-diam (`catch (e) {}`) | Error menghilang, bug tersembunyi | Selalu log atau lempar ulang dengan konteks |
|
|
468
|
+
| Retry operasi non-idempoten | Charge ganda, insert duplikat | Hanya retry operasi baca dan write idempoten |
|
|
469
|
+
| Tidak ada timeout pada panggilan eksternal | Thread/pool koneksi habis | Pasang `AbortSignal.timeout()` pada semua panggilan fetch |
|
|
470
|
+
| Pesan generik "Terjadi kesalahan" untuk semua error | Pengguna tidak bisa menyelesaikan sendiri | Tampilkan pesan yang actionable (retry, hubungi support, periksa input) |
|
|
471
|
+
|
|
472
|
+
### Integrasi dengan Skill Lain
|
|
473
|
+
|
|
474
|
+
- `js-backend-expert` — Middleware penanganan error API dan pemformatan respons
|
|
475
|
+
- `senior-frontend` — React Error Boundaries dan pola Suspense
|
|
476
|
+
- `database-orm-expert` — Penanganan error transaksi dan pola rollback
|
|
477
|
+
- `logging-error-tracking-expert` — Integrasi Sentry/BugSnag dan logging error terstruktur
|
|
478
|
+
- `async-queue-temporal-expert` — Dead letter queue dan strategi retry untuk background job
|
|
479
|
+
- `production-ready-hardener` — Checklist audit penanganan error sebelum peluncuran
|
|
480
|
+
- `api-design-expert` — Spesifikasi respons error RFC 9457
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: event-driven-architect
|
|
3
|
-
description: "Expert guide for microservices, message queues, Event Sourcing, and high-scale backend architectures / Panduan ahli untuk arsitektur microservices, antrean pesan, dan backend skala tinggi."
|
|
4
|
-
author: "Roedy Rustam"
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Event-Driven Architecture Expert
|
|
8
|
-
|
|
9
|
-
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<a name="english"></a>
|
|
14
|
-
## English
|
|
15
|
-
|
|
16
|
-
### Description
|
|
17
|
-
This skill provides architectural guidance for breaking down large monolithic applications into scalable, decoupled services. It focuses on Event-Driven Architecture (EDA), message brokers, and advanced patterns like Event Sourcing and CQRS (Command Query Responsibility Segregation).
|
|
18
|
-
|
|
19
|
-
### Trigger Conditions
|
|
20
|
-
- Scaling a system that handles extremely high throughput or traffic spikes.
|
|
21
|
-
- Implementing background jobs, asynchronous workers, or heavy data processing.
|
|
22
|
-
- Transitioning from a monolith to microservices.
|
|
23
|
-
- Integrating message brokers like RabbitMQ, Apache Kafka, AWS SQS, or Redis Pub/Sub.
|
|
24
|
-
- Resolving distributed transaction issues (e.g., handling the Saga pattern).
|
|
25
|
-
|
|
26
|
-
### Core Architecture Guidelines
|
|
27
|
-
|
|
28
|
-
#### 1. Decoupling via Events
|
|
29
|
-
Do not use synchronous HTTP calls between microservices for state mutations. It creates tightly coupled systems that fail in cascades.
|
|
30
|
-
- **Publisher/Subscriber**: When Service A does something, it publishes an event (e.g., `UserCreated`). Service B and Service C listen to this event and react asynchronously.
|
|
31
|
-
- Use **RabbitMQ** or **AWS SQS** for standard task queues (where order and exact-once delivery might be managed).
|
|
32
|
-
- Use **Apache Kafka** or **Redpanda** for high-throughput event streaming where logs need to be replayed.
|
|
33
|
-
|
|
34
|
-
#### 2. The Saga Pattern (Distributed Transactions)
|
|
35
|
-
In microservices, you cannot use simple database transactions (ACID) across different databases.
|
|
36
|
-
- Use the **Saga Pattern** to coordinate multiple operations. If Step 3 in a 4-step process fails, the system must publish "compensating events" to undo Steps 1 and 2 in the other services.
|
|
37
|
-
|
|
38
|
-
#### 3. CQRS (Command Query Responsibility Segregation)
|
|
39
|
-
For high-read applications (like social media or analytics dashboards), split the read operations from the write operations.
|
|
40
|
-
- **Commands**: Mutate state (write database).
|
|
41
|
-
- **Queries**: Read state (read replica or materialized views/Elasticsearch).
|
|
42
|
-
- Events synchronize the Write DB with the Read DB.
|
|
43
|
-
|
|
44
|
-
#### 4. Event Sourcing
|
|
45
|
-
Instead of storing just the current state of an entity (e.g., `AccountBalance = $100`), store the *history of events* that led to that state (`Deposited $150`, `Withdrew $50`). The current state is derived by replaying the events. This is mandatory for financial and highly auditable systems.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
<a name="bahasa-indonesia"></a>
|
|
50
|
-
## Bahasa Indonesia
|
|
51
|
-
|
|
52
|
-
### Deskripsi
|
|
53
|
-
Skill ini memberikan panduan arsitektural untuk memecah aplikasi monolit yang besar menjadi layanan yang terdesentralisasi (*decoupled*) dan dapat diskalakan. Fokus utamanya adalah pada *Event-Driven Architecture* (Arsitektur Berbasis Peristiwa), *message brokers* (pialang pesan), serta pola lanjutan seperti *Event Sourcing* dan CQRS (*Command Query Responsibility Segregation*).
|
|
54
|
-
|
|
55
|
-
### Kondisi Pemicu
|
|
56
|
-
- Menskalakan sistem untuk menangani lonjakan *traffic* atau volume data yang sangat tinggi.
|
|
57
|
-
- Mengimplementasikan pekerjaan latar belakang (*background jobs*), *worker asinkron*, atau pemrosesan data berat.
|
|
58
|
-
- Bertransisi dari arsitektur monolit ke layanan mikro (*microservices*).
|
|
59
|
-
- Mengintegrasikan *message brokers* seperti RabbitMQ, Apache Kafka, AWS SQS, atau Redis Pub/Sub.
|
|
60
|
-
- Menyelesaikan masalah transaksi terdistribusi (misalnya menerapkan pola Saga).
|
|
61
|
-
|
|
62
|
-
### Panduan Arsitektur Inti
|
|
63
|
-
|
|
64
|
-
#### 1. Desentralisasi melalui Event
|
|
65
|
-
Jangan gunakan panggilan HTTP yang sinkron antar *microservices* untuk memutasi data. Hal ini menciptakan sistem yang saling bergantung ketat (*tightly coupled*) dan bisa menyebabkan kegagalan beruntun (*cascading failures*).
|
|
66
|
-
- **Publisher/Subscriber**: Saat Layanan A melakukan sesuatu, ia menerbitkan sebuah event (misalnya `UserCreated`). Layanan B dan C akan mendengarkan event ini dan bereaksi secara asinkron.
|
|
67
|
-
- Gunakan **RabbitMQ** atau **AWS SQS** untuk antrean tugas standar.
|
|
68
|
-
- Gunakan **Apache Kafka** atau **Redpanda** untuk *streaming event* throughput tinggi yang memerlukan *replay* log.
|
|
69
|
-
|
|
70
|
-
#### 2. Pola Saga (Transaksi Terdistribusi)
|
|
71
|
-
Dalam arsitektur *microservices*, Anda tidak dapat menggunakan transaksi database ACID standar lintas database yang berbeda.
|
|
72
|
-
- Gunakan **Saga Pattern** untuk mengoordinasikan beberapa operasi. Jika Langkah 3 dalam proses 4-langkah gagal, sistem harus menerbitkan "event kompensasi" (pembatalan) untuk membatalkan Langkah 1 dan 2 pada layanan sebelumnya.
|
|
73
|
-
|
|
74
|
-
#### 3. CQRS (Command Query Responsibility Segregation)
|
|
75
|
-
Untuk aplikasi dengan tingkat pembacaan yang sangat tinggi (seperti dasbor analitik), pisahkan operasi baca dari operasi tulis.
|
|
76
|
-
- **Command**: Memutasi state/data (Database Tulis).
|
|
77
|
-
- **Query**: Membaca state (Read Replica, Materialized Views, atau Elasticsearch).
|
|
78
|
-
- Event bertugas menyinkronkan Database Tulis ke Database Baca di latar belakang.
|
|
79
|
-
|
|
80
|
-
#### 4. Event Sourcing
|
|
81
|
-
Daripada hanya menyimpan kondisi terbaru sebuah data (mis. `SaldoAkun = Rp1.000.000`), simpan *sejarah lengkap peristiwa* yang mengarah ke saldo tersebut (`Setor Rp1.500.000`, `Tarik Rp500.000`). Kondisi saat ini diturunkan (dikalkulasi) dengan memutar ulang (*replaying*) event tersebut. Pola ini wajib untuk sistem finansial dan sistem yang membutuhkan jejak audit tingkat tinggi.
|
|
1
|
+
---
|
|
2
|
+
name: event-driven-architect
|
|
3
|
+
description: "Expert guide for microservices, message queues, Event Sourcing, and high-scale backend architectures / Panduan ahli untuk arsitektur microservices, antrean pesan, dan backend skala tinggi."
|
|
4
|
+
author: "Roedy Rustam"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Event-Driven Architecture Expert
|
|
8
|
+
|
|
9
|
+
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<a name="english"></a>
|
|
14
|
+
## English
|
|
15
|
+
|
|
16
|
+
### Description
|
|
17
|
+
This skill provides architectural guidance for breaking down large monolithic applications into scalable, decoupled services. It focuses on Event-Driven Architecture (EDA), message brokers, and advanced patterns like Event Sourcing and CQRS (Command Query Responsibility Segregation).
|
|
18
|
+
|
|
19
|
+
### Trigger Conditions
|
|
20
|
+
- Scaling a system that handles extremely high throughput or traffic spikes.
|
|
21
|
+
- Implementing background jobs, asynchronous workers, or heavy data processing.
|
|
22
|
+
- Transitioning from a monolith to microservices.
|
|
23
|
+
- Integrating message brokers like RabbitMQ, Apache Kafka, AWS SQS, or Redis Pub/Sub.
|
|
24
|
+
- Resolving distributed transaction issues (e.g., handling the Saga pattern).
|
|
25
|
+
|
|
26
|
+
### Core Architecture Guidelines
|
|
27
|
+
|
|
28
|
+
#### 1. Decoupling via Events
|
|
29
|
+
Do not use synchronous HTTP calls between microservices for state mutations. It creates tightly coupled systems that fail in cascades.
|
|
30
|
+
- **Publisher/Subscriber**: When Service A does something, it publishes an event (e.g., `UserCreated`). Service B and Service C listen to this event and react asynchronously.
|
|
31
|
+
- Use **RabbitMQ** or **AWS SQS** for standard task queues (where order and exact-once delivery might be managed).
|
|
32
|
+
- Use **Apache Kafka** or **Redpanda** for high-throughput event streaming where logs need to be replayed.
|
|
33
|
+
|
|
34
|
+
#### 2. The Saga Pattern (Distributed Transactions)
|
|
35
|
+
In microservices, you cannot use simple database transactions (ACID) across different databases.
|
|
36
|
+
- Use the **Saga Pattern** to coordinate multiple operations. If Step 3 in a 4-step process fails, the system must publish "compensating events" to undo Steps 1 and 2 in the other services.
|
|
37
|
+
|
|
38
|
+
#### 3. CQRS (Command Query Responsibility Segregation)
|
|
39
|
+
For high-read applications (like social media or analytics dashboards), split the read operations from the write operations.
|
|
40
|
+
- **Commands**: Mutate state (write database).
|
|
41
|
+
- **Queries**: Read state (read replica or materialized views/Elasticsearch).
|
|
42
|
+
- Events synchronize the Write DB with the Read DB.
|
|
43
|
+
|
|
44
|
+
#### 4. Event Sourcing
|
|
45
|
+
Instead of storing just the current state of an entity (e.g., `AccountBalance = $100`), store the *history of events* that led to that state (`Deposited $150`, `Withdrew $50`). The current state is derived by replaying the events. This is mandatory for financial and highly auditable systems.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<a name="bahasa-indonesia"></a>
|
|
50
|
+
## Bahasa Indonesia
|
|
51
|
+
|
|
52
|
+
### Deskripsi
|
|
53
|
+
Skill ini memberikan panduan arsitektural untuk memecah aplikasi monolit yang besar menjadi layanan yang terdesentralisasi (*decoupled*) dan dapat diskalakan. Fokus utamanya adalah pada *Event-Driven Architecture* (Arsitektur Berbasis Peristiwa), *message brokers* (pialang pesan), serta pola lanjutan seperti *Event Sourcing* dan CQRS (*Command Query Responsibility Segregation*).
|
|
54
|
+
|
|
55
|
+
### Kondisi Pemicu
|
|
56
|
+
- Menskalakan sistem untuk menangani lonjakan *traffic* atau volume data yang sangat tinggi.
|
|
57
|
+
- Mengimplementasikan pekerjaan latar belakang (*background jobs*), *worker asinkron*, atau pemrosesan data berat.
|
|
58
|
+
- Bertransisi dari arsitektur monolit ke layanan mikro (*microservices*).
|
|
59
|
+
- Mengintegrasikan *message brokers* seperti RabbitMQ, Apache Kafka, AWS SQS, atau Redis Pub/Sub.
|
|
60
|
+
- Menyelesaikan masalah transaksi terdistribusi (misalnya menerapkan pola Saga).
|
|
61
|
+
|
|
62
|
+
### Panduan Arsitektur Inti
|
|
63
|
+
|
|
64
|
+
#### 1. Desentralisasi melalui Event
|
|
65
|
+
Jangan gunakan panggilan HTTP yang sinkron antar *microservices* untuk memutasi data. Hal ini menciptakan sistem yang saling bergantung ketat (*tightly coupled*) dan bisa menyebabkan kegagalan beruntun (*cascading failures*).
|
|
66
|
+
- **Publisher/Subscriber**: Saat Layanan A melakukan sesuatu, ia menerbitkan sebuah event (misalnya `UserCreated`). Layanan B dan C akan mendengarkan event ini dan bereaksi secara asinkron.
|
|
67
|
+
- Gunakan **RabbitMQ** atau **AWS SQS** untuk antrean tugas standar.
|
|
68
|
+
- Gunakan **Apache Kafka** atau **Redpanda** untuk *streaming event* throughput tinggi yang memerlukan *replay* log.
|
|
69
|
+
|
|
70
|
+
#### 2. Pola Saga (Transaksi Terdistribusi)
|
|
71
|
+
Dalam arsitektur *microservices*, Anda tidak dapat menggunakan transaksi database ACID standar lintas database yang berbeda.
|
|
72
|
+
- Gunakan **Saga Pattern** untuk mengoordinasikan beberapa operasi. Jika Langkah 3 dalam proses 4-langkah gagal, sistem harus menerbitkan "event kompensasi" (pembatalan) untuk membatalkan Langkah 1 dan 2 pada layanan sebelumnya.
|
|
73
|
+
|
|
74
|
+
#### 3. CQRS (Command Query Responsibility Segregation)
|
|
75
|
+
Untuk aplikasi dengan tingkat pembacaan yang sangat tinggi (seperti dasbor analitik), pisahkan operasi baca dari operasi tulis.
|
|
76
|
+
- **Command**: Memutasi state/data (Database Tulis).
|
|
77
|
+
- **Query**: Membaca state (Read Replica, Materialized Views, atau Elasticsearch).
|
|
78
|
+
- Event bertugas menyinkronkan Database Tulis ke Database Baca di latar belakang.
|
|
79
|
+
|
|
80
|
+
#### 4. Event Sourcing
|
|
81
|
+
Daripada hanya menyimpan kondisi terbaru sebuah data (mis. `SaldoAkun = Rp1.000.000`), simpan *sejarah lengkap peristiwa* yang mengarah ke saldo tersebut (`Setor Rp1.500.000`, `Tarik Rp500.000`). Kondisi saat ini diturunkan (dikalkulasi) dengan memutar ulang (*replaying*) event tersebut. Pola ini wajib untuk sistem finansial dan sistem yang membutuhkan jejak audit tingkat tinggi.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feature-flag-analytics-expert
|
|
3
|
+
description: "Expert guide for Feature Flags & Progressive Rollout (PostHog, LaunchDarkly, GrowthBook), A/B testing orchestration, and canary releases / Panduan ahli Feature Flags, A/B testing, dan rilis bertahap."
|
|
4
|
+
author: "Roedy Rustam"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Feature Flag & Progressive Rollout Expert
|
|
8
|
+
|
|
9
|
+
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<a name="english"></a>
|
|
14
|
+
## English
|
|
15
|
+
|
|
16
|
+
### Purpose & Overview
|
|
17
|
+
Production-grade guidelines for feature flag management, progressive feature rollouts, canary deployments, A/B testing experiment analysis, and dynamic server-side/client-side feature evaluation using PostHog, LaunchDarkly, and GrowthBook.
|
|
18
|
+
|
|
19
|
+
### Key Capabilities
|
|
20
|
+
- **Feature Gating**: Decoupling code deployment from feature release with instant kill-switches.
|
|
21
|
+
- **Canary & Percentage Rollout**: Incrementally releasing new features to 5%, 25%, 50%, and 100% of user segments.
|
|
22
|
+
- **Experimentation Engine**: Statistical A/B testing with conversion metrics and variant analytics.
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { PostHog } from 'posthog-node';
|
|
26
|
+
|
|
27
|
+
const posthog = new PostHog(process.env.POSTHOG_API_KEY!);
|
|
28
|
+
|
|
29
|
+
export async function isNewCheckoutEnabled(userId: string) {
|
|
30
|
+
const isEnabled = await posthog.isFeatureEnabled('new-checkout-flow', userId);
|
|
31
|
+
return isEnabled;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
<a name="bahasa-indonesia"></a>
|
|
38
|
+
## Bahasa Indonesia
|
|
39
|
+
|
|
40
|
+
### Deskripsi
|
|
41
|
+
Panduan tingkat produksi untuk manajemen feature flags, rilis fitur bertahap (progressive rollout), canary deployment, pengujian A/B testing, dan evaluasi fitur dinamis menggunakan PostHog, LaunchDarkly, dan GrowthBook.
|
|
42
|
+
|
|
43
|
+
### Fitur Utama
|
|
44
|
+
- **Feature Gating**: Memisahkan deployment kode dari rilis fitur dengan tombol *kill-switch* instan.
|
|
45
|
+
- **Rilis Bertahap (Canary)**: Meluncurkan fitur baru secara bertahap ke 5%, 25%, 50%, hingga 100% segmen pengguna.
|
|
46
|
+
- **Mesin Eksperimen**: Pengujian A/B statistik dengan metrik konversi dan analitik varian.
|