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.
Files changed (123) hide show
  1. package/.github/workflows/publish.yml +20 -0
  2. package/AGENTS.md +66 -0
  3. package/BLUEPRINT.md +152 -60
  4. package/CHANGELOG.md +50 -0
  5. package/README.md +346 -194
  6. package/package.json +25 -25
  7. package/plugin.json +1 -1
  8. package/skills/ai-cost-token-optimizer/SKILL.md +52 -0
  9. package/skills/ai-llm-integration-expert/SKILL.md +180 -162
  10. package/skills/api-design-expert/SKILL.md +314 -310
  11. package/skills/app-analyzer-optimizer/SKILL.md +193 -189
  12. package/skills/apple-ecosystem-expert/SKILL.md +142 -0
  13. package/skills/async-queue-temporal-expert/SKILL.md +54 -0
  14. package/skills/authentication-identity-expert/SKILL.md +251 -20
  15. package/skills/auto-doc-updater/SKILL.md +214 -204
  16. package/skills/autonomous-chaos-monkey/SKILL.md +63 -0
  17. package/skills/autonomous-red-teamer/SKILL.md +59 -0
  18. package/skills/autonomous-swarm-director/SKILL.md +69 -0
  19. package/skills/autonomous-tdd-debugger/SKILL.md +65 -0
  20. package/skills/bootstrap-to-modern/SKILL.md +90 -86
  21. package/skills/brainstorming/SKILL.md +373 -353
  22. package/skills/browser-automation-expert/SKILL.md +46 -0
  23. package/skills/ci-cd-devops-architect/SKILL.md +72 -45
  24. package/skills/cloud-hosting-expert/SKILL.md +244 -244
  25. package/skills/coderabbit/SKILL.md +192 -192
  26. package/skills/cron-scheduler-expert/SKILL.md +298 -0
  27. package/skills/data-telemetry-expert/SKILL.md +213 -213
  28. package/skills/database-orm-expert/SKILL.md +294 -294
  29. package/skills/dependency-upgrade-migrator/SKILL.md +295 -0
  30. package/skills/design-system-architect/SKILL.md +27 -10
  31. package/skills/doku-mcp-server/SKILL.md +251 -0
  32. package/skills/doku-payment-gateway/SKILL.md +227 -0
  33. package/skills/e2e-testing-expert/SKILL.md +315 -315
  34. package/skills/edge-serverless-db-expert/SKILL.md +43 -0
  35. package/skills/email-notification-expert/SKILL.md +362 -0
  36. package/skills/error-resilience-expert/SKILL.md +480 -0
  37. package/skills/event-driven-architect/SKILL.md +81 -81
  38. package/skills/feature-flag-analytics-expert/SKILL.md +46 -0
  39. package/skills/file-upload-media-expert/SKILL.md +431 -0
  40. package/skills/form-validation-expert/SKILL.md +401 -0
  41. package/skills/fullstack-expert/SKILL.md +202 -202
  42. package/skills/fullstack-expert/references/api_design_guide.md +466 -466
  43. package/skills/fullstack-expert/references/multi_language_backend.md +528 -528
  44. package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -253
  45. package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -326
  46. package/skills/gemini-agent-booster/SKILL.md +135 -135
  47. package/skills/global-a11y-i18n-expert/SKILL.md +81 -81
  48. package/skills/glsl-shader-expert/SKILL.md +101 -0
  49. package/skills/go-programming-expert/SKILL.md +295 -295
  50. package/skills/graphql-apollo-expert/SKILL.md +108 -0
  51. package/skills/hig/SKILL.md +188 -188
  52. package/skills/hyper-context-synthesizer/SKILL.md +55 -0
  53. package/skills/js-backend-expert/SKILL.md +34 -9
  54. package/skills/legacy-code-translator/SKILL.md +65 -0
  55. package/skills/llm-cost-arbitrage-router/SKILL.md +59 -0
  56. package/skills/logging-error-tracking-expert/SKILL.md +338 -0
  57. package/skills/mcp-client-orchestrator/SKILL.md +70 -0
  58. package/skills/mcp-server-architect/SKILL.md +194 -194
  59. package/skills/micro-frontend-architect/SKILL.md +106 -0
  60. package/skills/mobile-expo-expert/SKILL.md +186 -186
  61. package/skills/mobile-push-notification-expert/SKILL.md +51 -0
  62. package/skills/monday-design-aesthetic/SKILL.md +67 -67
  63. package/skills/monorepo-architect/SKILL.md +227 -227
  64. package/skills/mpa-orchestrator/SKILL.md +101 -101
  65. package/skills/multi-agent-orchestration/SKILL.md +234 -234
  66. package/skills/multiple-entry-points/SKILL.md +55 -55
  67. package/skills/mvc-expert/SKILL.md +231 -231
  68. package/skills/payment-gateway-expert/SKILL.md +45 -45
  69. package/skills/performance-web-vitals/SKILL.md +332 -332
  70. package/skills/post-quantum-crypto-migrator/SKILL.md +57 -0
  71. package/skills/prd-architect/SKILL.md +201 -191
  72. package/skills/proactive-background-watcher/SKILL.md +62 -0
  73. package/skills/production-ready-hardener/PRODUCTION_READINESS_REPORT.md +67 -0
  74. package/skills/production-ready-hardener/SKILL.md +173 -186
  75. package/skills/production-ready-hardener/references/production_checklist.md +161 -161
  76. package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +881 -875
  77. package/skills/project-context-mapper/SKILL.md +79 -0
  78. package/skills/python-programming-expert/SKILL.md +263 -132
  79. package/skills/rate-limit-abuse-prevention/SKILL.md +371 -0
  80. package/skills/realtime-collaboration-expert/SKILL.md +45 -45
  81. package/skills/rust-programming-expert/SKILL.md +235 -235
  82. package/skills/saas-billing/SKILL.md +377 -377
  83. package/skills/saas-multi-tenant/SKILL.md +251 -237
  84. package/skills/saas-mvp-launcher/SKILL.md +10 -0
  85. package/skills/saas-transformer/SKILL.md +187 -144
  86. package/skills/saas-transformer/references/billing_integration_guide.md +401 -401
  87. package/skills/saas-transformer/references/feature_gating_patterns.md +137 -137
  88. package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -121
  89. package/skills/saas-transformer/scripts/saas_transformation_scanner.py +39 -29
  90. package/skills/scalability-clean-code/SKILL.md +229 -229
  91. package/skills/self-evolving-memory-graph/SKILL.md +75 -0
  92. package/skills/self-healing-cloud-orchestrator/SKILL.md +57 -0
  93. package/skills/senior-frontend/SKILL.md +161 -161
  94. package/skills/senior-fullstack/SKILL.md +167 -167
  95. package/skills/seo/SKILL.md +235 -225
  96. package/skills/seo-geo/SKILL.md +188 -188
  97. package/skills/session-context-loader/SKILL.md +77 -0
  98. package/skills/session-handoff-resume/SKILL.md +158 -158
  99. package/skills/skill_baru/SKILL.md +172 -147
  100. package/skills/spa-orchestrator/SKILL.md +288 -288
  101. package/skills/state-management-expert/SKILL.md +272 -272
  102. package/skills/supabase-security-expert/SKILL.md +243 -243
  103. package/skills/tailwind-expert/SKILL.md +188 -188
  104. package/skills/tanstack-query-expert/SKILL.md +199 -199
  105. package/skills/token-saver/SKILL.md +119 -111
  106. package/skills/typescript-expert/SKILL.md +324 -279
  107. package/skills/ui-components-expert/SKILL.md +263 -46
  108. package/skills/ui-ux-pro-max/SKILL.md +202 -201
  109. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
  110. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
  111. package/skills/ui_ux_expert/SKILL.md +17 -6
  112. package/skills/vector-db-rag-expert/SKILL.md +52 -0
  113. package/skills/vibe-code-gardener/SKILL.md +181 -173
  114. package/skills/visual-qa-vision-agent/SKILL.md +65 -0
  115. package/skills/vue-frontend-expert/SKILL.md +126 -0
  116. package/skills/web-3d-graphics-expert/SKILL.md +131 -0
  117. package/skills/web-game-engine-expert/SKILL.md +96 -0
  118. package/skills/web-scraper/SKILL.md +207 -205
  119. package/skills/website-design-cloner/SKILL.md +174 -0
  120. package/skills/webxr-ar-vr-expert/SKILL.md +117 -0
  121. package/skills/zero-to-prod-orchestrator/SKILL.md +206 -180
  122. package/skills/zero-trust-secret-vault/SKILL.md +40 -0
  123. package/vibes-swarm-demo.gif +0 -0
@@ -1,272 +1,272 @@
1
- ---
2
- name: state-management-expert
3
- description: "Expert guide for modern client-side state management: Zustand, Jotai, Valtio, TanStack Store, Redux Toolkit, and server state patterns with TanStack Query / Panduan ahli untuk manajemen state client-side modern: Zustand, Jotai, Valtio, TanStack Store, Redux Toolkit, dan pola server state dengan TanStack Query."
4
- author: "Roedy Rustam"
5
- ---
6
-
7
- # State Management Expert (Modern React Edition)
8
-
9
- [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
10
-
11
- ---
12
-
13
- <a name="english"></a>
14
- ## English
15
-
16
- ### Description
17
- Expert guide for selecting and implementing the right state management solution for React and Next.js applications. Covers **Zustand 5**, **Jotai 2**, **Valtio**, **TanStack Store**, and **Redux Toolkit 2**, with clear guidance on when to use each, proper separation of server state (TanStack Query) from client state, and advanced patterns like slices, persistence, and devtools integration.
18
-
19
- ### Trigger Conditions
20
- - Choosing a state management library for a new React/Next.js project.
21
- - Refactoring prop drilling or complex Context API usage.
22
- - Implementing global UI state (modals, drawers, theme, auth session).
23
- - Managing complex form state across multiple steps.
24
- - Implementing undo/redo, optimistic updates, or derived state.
25
- - Migrating from Redux to a lighter alternative.
26
-
27
- ---
28
-
29
- ### State Category Separation (Critical First Step)
30
-
31
- Before choosing a library, categorize your state:
32
-
33
- | Category | Description | Solution |
34
- |---|---|---|
35
- | **Server State** | Data from APIs, databases | TanStack Query / SWR |
36
- | **URL State** | Route params, search filters | `useSearchParams`, nuqs |
37
- | **Form State** | Input values, validation errors | React Hook Form + Zod |
38
- | **UI/Local State** | Modals, drawers, toggles | `useState` / `useReducer` |
39
- | **Global Client State** | Theme, auth, shopping cart | Zustand / Jotai |
40
- | **Cross-tab State** | Sync across browser tabs | Zustand + BroadcastChannel |
41
-
42
- **Rule**: Do NOT store server data in client state. Let TanStack Query own all async data.
43
-
44
- ---
45
-
46
- ### Library Selection Guide
47
-
48
- | Criteria | Zustand 5 | Jotai 2 | Valtio | Redux Toolkit |
49
- |---|---|---|---|---|
50
- | **Mental Model** | Single store, actions | Atomic, bottom-up | Proxy-based, mutable | Flux, reducers |
51
- | **Bundle Size** | ~1KB | ~3KB | ~3KB | ~15KB+ |
52
- | **DevTools** | Redux DevTools | Jotai DevTools | Redux DevTools | Built-in |
53
- | **Async** | Manual or middleware | `atomWithQuery` | `snapshot` | `createAsyncThunk` |
54
- | **Best For** | General global state | Atomic derived state | Simple mutable state | Large teams, strict patterns |
55
-
56
- **Recommendation**: Use **Zustand** as the default. Use **Jotai** for fine-grained reactive atoms. Use **Redux Toolkit** only for large enterprise teams with strict conventions.
57
-
58
- ---
59
-
60
- ### Zustand 5 — Best Practices
61
-
62
- #### Basic Store with TypeScript
63
- ```typescript
64
- // stores/ui.store.ts
65
- import { create } from 'zustand';
66
- import { devtools, persist, subscribeWithSelector } from 'zustand/middleware';
67
- import { immer } from 'zustand/middleware/immer';
68
-
69
- interface UiState {
70
- theme: 'light' | 'dark' | 'system';
71
- sidebarOpen: boolean;
72
- activeModal: string | null;
73
- setTheme: (theme: UiState['theme']) => void;
74
- toggleSidebar: () => void;
75
- openModal: (modalId: string) => void;
76
- closeModal: () => void;
77
- }
78
-
79
- export const useUiStore = create<UiState>()(
80
- devtools(
81
- persist(
82
- subscribeWithSelector(
83
- immer((set) => ({
84
- theme: 'system',
85
- sidebarOpen: true,
86
- activeModal: null,
87
- setTheme: (theme) => set((state) => { state.theme = theme; }),
88
- toggleSidebar: () => set((state) => { state.sidebarOpen = !state.sidebarOpen; }),
89
- openModal: (modalId) => set((state) => { state.activeModal = modalId; }),
90
- closeModal: () => set((state) => { state.activeModal = null; }),
91
- }))
92
- ),
93
- { name: 'ui-store', partialize: (s) => ({ theme: s.theme }) }
94
- ),
95
- { name: 'UiStore' }
96
- )
97
- );
98
- ```
99
-
100
- #### Slice Pattern for Large Stores
101
- ```typescript
102
- // Pattern: separate slices, combine into one store
103
- import { StateCreator } from 'zustand';
104
-
105
- interface AuthSlice {
106
- user: User | null;
107
- isAuthenticated: boolean;
108
- login: (user: User) => void;
109
- logout: () => void;
110
- }
111
-
112
- interface CartSlice {
113
- items: CartItem[];
114
- addItem: (item: CartItem) => void;
115
- removeItem: (id: string) => void;
116
- total: () => number;
117
- }
118
-
119
- type AppStore = AuthSlice & CartSlice;
120
-
121
- const createAuthSlice: StateCreator<AppStore, [], [], AuthSlice> = (set) => ({
122
- user: null,
123
- isAuthenticated: false,
124
- login: (user) => set({ user, isAuthenticated: true }),
125
- logout: () => set({ user: null, isAuthenticated: false }),
126
- });
127
-
128
- const createCartSlice: StateCreator<AppStore, [], [], CartSlice> = (set, get) => ({
129
- items: [],
130
- addItem: (item) => set((s) => ({ items: [...s.items, item] })),
131
- removeItem: (id) => set((s) => ({ items: s.items.filter((i) => i.id !== id) })),
132
- total: () => get().items.reduce((sum, item) => sum + item.price * item.qty, 0),
133
- });
134
-
135
- export const useAppStore = create<AppStore>()(
136
- devtools((...args) => ({
137
- ...createAuthSlice(...args),
138
- ...createCartSlice(...args),
139
- }))
140
- );
141
- ```
142
-
143
- #### Selective Subscriptions (Prevent Unnecessary Rerenders)
144
- ```typescript
145
- // Only re-render when `theme` changes, not the entire store
146
- const theme = useUiStore((s) => s.theme);
147
- const isModalOpen = useUiStore((s) => s.activeModal === 'confirm-delete');
148
-
149
- // Subscribe outside React (side effects, non-component code)
150
- useUiStore.subscribe(
151
- (s) => s.theme,
152
- (theme) => document.documentElement.dataset.theme = theme,
153
- { fireImmediately: true }
154
- );
155
- ```
156
-
157
- ---
158
-
159
- ### Jotai 2 — Atomic State Patterns
160
-
161
- ```typescript
162
- // atoms/user.atoms.ts
163
- import { atom, loadable } from 'jotai';
164
- import { atomWithStorage, atomWithReset } from 'jotai/utils';
165
-
166
- // Primitive atom
167
- export const themeAtom = atomWithStorage<'light' | 'dark'>('theme', 'light');
168
-
169
- // Derived (read-only) atom
170
- export const isDarkAtom = atom((get) => get(themeAtom) === 'dark');
171
-
172
- // Async atom with loadable for Suspense-free usage
173
- export const userAtom = atom(async () => {
174
- const res = await fetch('/api/me');
175
- if (!res.ok) throw new Error('Failed to fetch user');
176
- return res.json() as Promise<User>;
177
- });
178
-
179
- export const loadableUserAtom = loadable(userAtom);
180
-
181
- // In component:
182
- function UserWidget() {
183
- const loadableUser = useAtomValue(loadableUserAtom);
184
- if (loadableUser.state === 'loading') return <Spinner />;
185
- if (loadableUser.state === 'hasError') return <Error />;
186
- return <div>{loadableUser.data.name}</div>;
187
- }
188
- ```
189
-
190
- ---
191
-
192
- ### Redux Toolkit 2 — Modern Patterns
193
-
194
- ```typescript
195
- // features/cart/cartSlice.ts
196
- import { createSlice, PayloadAction, createSelector } from '@reduxjs/toolkit';
197
-
198
- interface CartState {
199
- items: CartItem[];
200
- status: 'idle' | 'loading' | 'failed';
201
- }
202
-
203
- const cartSlice = createSlice({
204
- name: 'cart',
205
- initialState: { items: [], status: 'idle' } as CartState,
206
- reducers: {
207
- addItem(state, action: PayloadAction<CartItem>) {
208
- state.items.push(action.payload); // Immer handles immutability
209
- },
210
- removeItem(state, action: PayloadAction<string>) {
211
- state.items = state.items.filter((i) => i.id !== action.payload);
212
- },
213
- },
214
- });
215
-
216
- // Memoized selector
217
- export const selectCartTotal = createSelector(
218
- (state: RootState) => state.cart.items,
219
- (items) => items.reduce((sum, i) => sum + i.price * i.qty, 0)
220
- );
221
-
222
- export const { addItem, removeItem } = cartSlice.actions;
223
- export default cartSlice.reducer;
224
- ```
225
-
226
- ---
227
-
228
- ### Integration with Next.js App Router
229
-
230
- - **Server Components**: No client state. Fetch directly.
231
- - **Client Components**: Use Zustand/Jotai wrapped in providers.
232
- - **Hydration**: Initialize Zustand store from server-fetched data using `useHydrateAtoms` (Jotai) or a `HydrationBoundary` pattern.
233
-
234
- ```typescript
235
- // providers/store-provider.tsx (App Router pattern)
236
- 'use client';
237
- import { createStore, Provider } from 'jotai';
238
- import { useRef } from 'react';
239
-
240
- type Props = { children: React.ReactNode; initialUser?: User };
241
-
242
- export function StoreProvider({ children, initialUser }: Props) {
243
- const store = useRef(createStore());
244
- if (initialUser) store.current.set(userAtom, initialUser);
245
- return <Provider store={store.current}>{children}</Provider>;
246
- }
247
- ```
248
-
249
- ---
250
-
251
- <a name="bahasa-indonesia"></a>
252
- ## Bahasa Indonesia
253
-
254
- ### Deskripsi
255
- Panduan ahli untuk memilih dan mengimplementasikan solusi manajemen state yang tepat untuk aplikasi React dan Next.js. Mencakup **Zustand 5**, **Jotai 2**, **Valtio**, dan **Redux Toolkit 2**, dengan panduan pemilihan yang jelas, pemisahan server state (TanStack Query) dari client state, dan pola lanjutan seperti slices, persistensi, dan integrasi devtools.
256
-
257
- ### Kondisi Pemicu
258
- - Memilih library state management untuk proyek React/Next.js baru.
259
- - Refaktor prop drilling atau penggunaan Context API yang rumit.
260
- - Mengimplementasikan global UI state (modal, drawer, tema, sesi auth).
261
- - Mengelola state form kompleks di beberapa langkah.
262
- - Mengimplementasikan undo/redo, optimistic update, atau derived state.
263
- - Migrasi dari Redux ke alternatif yang lebih ringan.
264
-
265
- ### Prinsip Utama
266
-
267
- - **Pisahkan server state dari client state**: Server state (data dari API) dikelola TanStack Query. Client state (UI, preferensi) dikelola Zustand/Jotai.
268
- - **Gunakan Zustand sebagai default** untuk state global umum.
269
- - **Gunakan Jotai** untuk state atomik yang sangat granular dan reaktif.
270
- - **Hindari menyimpan data server di client state** — ini adalah sumber bug terbesar di aplikasi React.
271
- - **Selective subscription**: Selalu gunakan selector untuk menghindari re-render yang tidak perlu.
272
- - **DevTools**: Selalu integrasikan devtools di development untuk debugging yang efektif.
1
+ ---
2
+ name: state-management-expert
3
+ description: "Expert guide for modern client-side state management: Zustand, Jotai, Valtio, TanStack Store, Redux Toolkit, and server state patterns with TanStack Query / Panduan ahli untuk manajemen state client-side modern: Zustand, Jotai, Valtio, TanStack Store, Redux Toolkit, dan pola server state dengan TanStack Query."
4
+ author: "Roedy Rustam"
5
+ ---
6
+
7
+ # State Management Expert (Modern React Edition)
8
+
9
+ [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
10
+
11
+ ---
12
+
13
+ <a name="english"></a>
14
+ ## English
15
+
16
+ ### Description
17
+ Expert guide for selecting and implementing the right state management solution for React and Next.js applications. Covers **Zustand 5**, **Jotai 2**, **Valtio**, **TanStack Store**, and **Redux Toolkit 2**, with clear guidance on when to use each, proper separation of server state (TanStack Query) from client state, and advanced patterns like slices, persistence, and devtools integration.
18
+
19
+ ### Trigger Conditions
20
+ - Choosing a state management library for a new React/Next.js project.
21
+ - Refactoring prop drilling or complex Context API usage.
22
+ - Implementing global UI state (modals, drawers, theme, auth session).
23
+ - Managing complex form state across multiple steps.
24
+ - Implementing undo/redo, optimistic updates, or derived state.
25
+ - Migrating from Redux to a lighter alternative.
26
+
27
+ ---
28
+
29
+ ### State Category Separation (Critical First Step)
30
+
31
+ Before choosing a library, categorize your state:
32
+
33
+ | Category | Description | Solution |
34
+ |---|---|---|
35
+ | **Server State** | Data from APIs, databases | TanStack Query / SWR |
36
+ | **URL State** | Route params, search filters | `useSearchParams`, nuqs |
37
+ | **Form State** | Input values, validation errors | React Hook Form + Zod |
38
+ | **UI/Local State** | Modals, drawers, toggles | `useState` / `useReducer` |
39
+ | **Global Client State** | Theme, auth, shopping cart | Zustand / Jotai |
40
+ | **Cross-tab State** | Sync across browser tabs | Zustand + BroadcastChannel |
41
+
42
+ **Rule**: Do NOT store server data in client state. Let TanStack Query own all async data.
43
+
44
+ ---
45
+
46
+ ### Library Selection Guide
47
+
48
+ | Criteria | Zustand 5 | Jotai 2 | Valtio | Redux Toolkit |
49
+ |---|---|---|---|---|
50
+ | **Mental Model** | Single store, actions | Atomic, bottom-up | Proxy-based, mutable | Flux, reducers |
51
+ | **Bundle Size** | ~1KB | ~3KB | ~3KB | ~15KB+ |
52
+ | **DevTools** | Redux DevTools | Jotai DevTools | Redux DevTools | Built-in |
53
+ | **Async** | Manual or middleware | `atomWithQuery` | `snapshot` | `createAsyncThunk` |
54
+ | **Best For** | General global state | Atomic derived state | Simple mutable state | Large teams, strict patterns |
55
+
56
+ **Recommendation**: Use **Zustand** as the default. Use **Jotai** for fine-grained reactive atoms. Use **Redux Toolkit** only for large enterprise teams with strict conventions.
57
+
58
+ ---
59
+
60
+ ### Zustand 5 — Best Practices
61
+
62
+ #### Basic Store with TypeScript
63
+ ```typescript
64
+ // stores/ui.store.ts
65
+ import { create } from 'zustand';
66
+ import { devtools, persist, subscribeWithSelector } from 'zustand/middleware';
67
+ import { immer } from 'zustand/middleware/immer';
68
+
69
+ interface UiState {
70
+ theme: 'light' | 'dark' | 'system';
71
+ sidebarOpen: boolean;
72
+ activeModal: string | null;
73
+ setTheme: (theme: UiState['theme']) => void;
74
+ toggleSidebar: () => void;
75
+ openModal: (modalId: string) => void;
76
+ closeModal: () => void;
77
+ }
78
+
79
+ export const useUiStore = create<UiState>()(
80
+ devtools(
81
+ persist(
82
+ subscribeWithSelector(
83
+ immer((set) => ({
84
+ theme: 'system',
85
+ sidebarOpen: true,
86
+ activeModal: null,
87
+ setTheme: (theme) => set((state) => { state.theme = theme; }),
88
+ toggleSidebar: () => set((state) => { state.sidebarOpen = !state.sidebarOpen; }),
89
+ openModal: (modalId) => set((state) => { state.activeModal = modalId; }),
90
+ closeModal: () => set((state) => { state.activeModal = null; }),
91
+ }))
92
+ ),
93
+ { name: 'ui-store', partialize: (s) => ({ theme: s.theme }) }
94
+ ),
95
+ { name: 'UiStore' }
96
+ )
97
+ );
98
+ ```
99
+
100
+ #### Slice Pattern for Large Stores
101
+ ```typescript
102
+ // Pattern: separate slices, combine into one store
103
+ import { StateCreator } from 'zustand';
104
+
105
+ interface AuthSlice {
106
+ user: User | null;
107
+ isAuthenticated: boolean;
108
+ login: (user: User) => void;
109
+ logout: () => void;
110
+ }
111
+
112
+ interface CartSlice {
113
+ items: CartItem[];
114
+ addItem: (item: CartItem) => void;
115
+ removeItem: (id: string) => void;
116
+ total: () => number;
117
+ }
118
+
119
+ type AppStore = AuthSlice & CartSlice;
120
+
121
+ const createAuthSlice: StateCreator<AppStore, [], [], AuthSlice> = (set) => ({
122
+ user: null,
123
+ isAuthenticated: false,
124
+ login: (user) => set({ user, isAuthenticated: true }),
125
+ logout: () => set({ user: null, isAuthenticated: false }),
126
+ });
127
+
128
+ const createCartSlice: StateCreator<AppStore, [], [], CartSlice> = (set, get) => ({
129
+ items: [],
130
+ addItem: (item) => set((s) => ({ items: [...s.items, item] })),
131
+ removeItem: (id) => set((s) => ({ items: s.items.filter((i) => i.id !== id) })),
132
+ total: () => get().items.reduce((sum, item) => sum + item.price * item.qty, 0),
133
+ });
134
+
135
+ export const useAppStore = create<AppStore>()(
136
+ devtools((...args) => ({
137
+ ...createAuthSlice(...args),
138
+ ...createCartSlice(...args),
139
+ }))
140
+ );
141
+ ```
142
+
143
+ #### Selective Subscriptions (Prevent Unnecessary Rerenders)
144
+ ```typescript
145
+ // Only re-render when `theme` changes, not the entire store
146
+ const theme = useUiStore((s) => s.theme);
147
+ const isModalOpen = useUiStore((s) => s.activeModal === 'confirm-delete');
148
+
149
+ // Subscribe outside React (side effects, non-component code)
150
+ useUiStore.subscribe(
151
+ (s) => s.theme,
152
+ (theme) => document.documentElement.dataset.theme = theme,
153
+ { fireImmediately: true }
154
+ );
155
+ ```
156
+
157
+ ---
158
+
159
+ ### Jotai 2 — Atomic State Patterns
160
+
161
+ ```typescript
162
+ // atoms/user.atoms.ts
163
+ import { atom, loadable } from 'jotai';
164
+ import { atomWithStorage, atomWithReset } from 'jotai/utils';
165
+
166
+ // Primitive atom
167
+ export const themeAtom = atomWithStorage<'light' | 'dark'>('theme', 'light');
168
+
169
+ // Derived (read-only) atom
170
+ export const isDarkAtom = atom((get) => get(themeAtom) === 'dark');
171
+
172
+ // Async atom with loadable for Suspense-free usage
173
+ export const userAtom = atom(async () => {
174
+ const res = await fetch('/api/me');
175
+ if (!res.ok) throw new Error('Failed to fetch user');
176
+ return res.json() as Promise<User>;
177
+ });
178
+
179
+ export const loadableUserAtom = loadable(userAtom);
180
+
181
+ // In component:
182
+ function UserWidget() {
183
+ const loadableUser = useAtomValue(loadableUserAtom);
184
+ if (loadableUser.state === 'loading') return <Spinner />;
185
+ if (loadableUser.state === 'hasError') return <Error />;
186
+ return <div>{loadableUser.data.name}</div>;
187
+ }
188
+ ```
189
+
190
+ ---
191
+
192
+ ### Redux Toolkit 2 — Modern Patterns
193
+
194
+ ```typescript
195
+ // features/cart/cartSlice.ts
196
+ import { createSlice, PayloadAction, createSelector } from '@reduxjs/toolkit';
197
+
198
+ interface CartState {
199
+ items: CartItem[];
200
+ status: 'idle' | 'loading' | 'failed';
201
+ }
202
+
203
+ const cartSlice = createSlice({
204
+ name: 'cart',
205
+ initialState: { items: [], status: 'idle' } as CartState,
206
+ reducers: {
207
+ addItem(state, action: PayloadAction<CartItem>) {
208
+ state.items.push(action.payload); // Immer handles immutability
209
+ },
210
+ removeItem(state, action: PayloadAction<string>) {
211
+ state.items = state.items.filter((i) => i.id !== action.payload);
212
+ },
213
+ },
214
+ });
215
+
216
+ // Memoized selector
217
+ export const selectCartTotal = createSelector(
218
+ (state: RootState) => state.cart.items,
219
+ (items) => items.reduce((sum, i) => sum + i.price * i.qty, 0)
220
+ );
221
+
222
+ export const { addItem, removeItem } = cartSlice.actions;
223
+ export default cartSlice.reducer;
224
+ ```
225
+
226
+ ---
227
+
228
+ ### Integration with Next.js App Router
229
+
230
+ - **Server Components**: No client state. Fetch directly.
231
+ - **Client Components**: Use Zustand/Jotai wrapped in providers.
232
+ - **Hydration**: Initialize Zustand store from server-fetched data using `useHydrateAtoms` (Jotai) or a `HydrationBoundary` pattern.
233
+
234
+ ```typescript
235
+ // providers/store-provider.tsx (App Router pattern)
236
+ 'use client';
237
+ import { createStore, Provider } from 'jotai';
238
+ import { useRef } from 'react';
239
+
240
+ type Props = { children: React.ReactNode; initialUser?: User };
241
+
242
+ export function StoreProvider({ children, initialUser }: Props) {
243
+ const store = useRef(createStore());
244
+ if (initialUser) store.current.set(userAtom, initialUser);
245
+ return <Provider store={store.current}>{children}</Provider>;
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ <a name="bahasa-indonesia"></a>
252
+ ## Bahasa Indonesia
253
+
254
+ ### Deskripsi
255
+ Panduan ahli untuk memilih dan mengimplementasikan solusi manajemen state yang tepat untuk aplikasi React dan Next.js. Mencakup **Zustand 5**, **Jotai 2**, **Valtio**, dan **Redux Toolkit 2**, dengan panduan pemilihan yang jelas, pemisahan server state (TanStack Query) dari client state, dan pola lanjutan seperti slices, persistensi, dan integrasi devtools.
256
+
257
+ ### Kondisi Pemicu
258
+ - Memilih library state management untuk proyek React/Next.js baru.
259
+ - Refaktor prop drilling atau penggunaan Context API yang rumit.
260
+ - Mengimplementasikan global UI state (modal, drawer, tema, sesi auth).
261
+ - Mengelola state form kompleks di beberapa langkah.
262
+ - Mengimplementasikan undo/redo, optimistic update, atau derived state.
263
+ - Migrasi dari Redux ke alternatif yang lebih ringan.
264
+
265
+ ### Prinsip Utama
266
+
267
+ - **Pisahkan server state dari client state**: Server state (data dari API) dikelola TanStack Query. Client state (UI, preferensi) dikelola Zustand/Jotai.
268
+ - **Gunakan Zustand sebagai default** untuk state global umum.
269
+ - **Gunakan Jotai** untuk state atomik yang sangat granular dan reaktif.
270
+ - **Hindari menyimpan data server di client state** — ini adalah sumber bug terbesar di aplikasi React.
271
+ - **Selective subscription**: Selalu gunakan selector untuk menghindari re-render yang tidak perlu.
272
+ - **DevTools**: Selalu integrasikan devtools di development untuk debugging yang efektif.