@adlas/create-app 1.0.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 (79) hide show
  1. package/README.md +476 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +39 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/figma.d.ts +16 -0
  7. package/dist/commands/figma.d.ts.map +1 -0
  8. package/dist/commands/figma.js +172 -0
  9. package/dist/commands/figma.js.map +1 -0
  10. package/dist/commands/index.d.ts +5 -0
  11. package/dist/commands/index.d.ts.map +1 -0
  12. package/dist/commands/index.js +5 -0
  13. package/dist/commands/index.js.map +1 -0
  14. package/dist/commands/init.d.ts +8 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +1471 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/swagger.d.ts +16 -0
  19. package/dist/commands/swagger.d.ts.map +1 -0
  20. package/dist/commands/swagger.js +404 -0
  21. package/dist/commands/swagger.js.map +1 -0
  22. package/dist/commands/update.d.ts +15 -0
  23. package/dist/commands/update.d.ts.map +1 -0
  24. package/dist/commands/update.js +93 -0
  25. package/dist/commands/update.js.map +1 -0
  26. package/package.json +63 -0
  27. package/templates/.vscode/extensions.json +9 -0
  28. package/templates/.vscode/launch.json +26 -0
  29. package/templates/.vscode/settings.json +67 -0
  30. package/templates/.vscode/tasks.json +21 -0
  31. package/templates/boilerplate/config/fonts.ts +10 -0
  32. package/templates/boilerplate/config/navigationUrls.ts +47 -0
  33. package/templates/boilerplate/config/site.ts +96 -0
  34. package/templates/boilerplate/libs/I18n.ts +15 -0
  35. package/templates/boilerplate/libs/I18nNavigation.ts +5 -0
  36. package/templates/boilerplate/libs/I18nRouting.ts +9 -0
  37. package/templates/boilerplate/libs/env.ts +21 -0
  38. package/templates/boilerplate/libs/react-query/ReactQueryProvider.tsx +21 -0
  39. package/templates/boilerplate/libs/react-query/index.ts +2 -0
  40. package/templates/boilerplate/libs/react-query/queryClient.ts +62 -0
  41. package/templates/boilerplate/libs/react-query/queryKeys.ts +5 -0
  42. package/templates/boilerplate/public/images/index.ts +1 -0
  43. package/templates/boilerplate/reset.d.ts +2 -0
  44. package/templates/boilerplate/styles/globals.css +308 -0
  45. package/templates/boilerplate/types/i18n.ts +10 -0
  46. package/templates/boilerplate/types/locale.ts +8 -0
  47. package/templates/boilerplate/utils/file/fileConfig.ts +123 -0
  48. package/templates/boilerplate/utils/file/fileValidation.ts +78 -0
  49. package/templates/boilerplate/utils/file/imageCompression.ts +182 -0
  50. package/templates/boilerplate/utils/file/index.ts +3 -0
  51. package/templates/boilerplate/utils/helpers.ts +55 -0
  52. package/templates/boilerplate/validations/auth.validation.ts +92 -0
  53. package/templates/boilerplate/validations/commonValidations.ts +258 -0
  54. package/templates/boilerplate/validations/zodErrorMap.ts +101 -0
  55. package/templates/configs/.env.example +8 -0
  56. package/templates/configs/.prettierignore +23 -0
  57. package/templates/configs/.prettierrc.cjs +26 -0
  58. package/templates/configs/.prettierrc.icons.cjs +11 -0
  59. package/templates/configs/Dockerfile +6 -0
  60. package/templates/configs/commitlint.config.ts +8 -0
  61. package/templates/configs/eslint.config.mjs +119 -0
  62. package/templates/configs/knip.config.ts +32 -0
  63. package/templates/configs/lefthook.yml +42 -0
  64. package/templates/configs/lint-staged.config.js +8 -0
  65. package/templates/configs/next.config.template.ts +77 -0
  66. package/templates/configs/next.config.ts +43 -0
  67. package/templates/configs/package.json +75 -0
  68. package/templates/configs/postcss.config.mjs +15 -0
  69. package/templates/configs/svgr.config.mjs +129 -0
  70. package/templates/configs/tsconfig.json +75 -0
  71. package/templates/docs/AI_QUICK_REFERENCE.md +379 -0
  72. package/templates/docs/ARCHITECTURE_PATTERNS.md +927 -0
  73. package/templates/docs/DOCUMENTATION_INDEX.md +411 -0
  74. package/templates/docs/FIGMA_TO_CODE_GUIDE.md +768 -0
  75. package/templates/docs/IMPLEMENTATION_GUIDE.md +892 -0
  76. package/templates/docs/PROJECT_OVERVIEW.md +302 -0
  77. package/templates/docs/REFACTOR_PROGRESS.md +1113 -0
  78. package/templates/docs/SHADCN_TO_HEROUI_MIGRATION.md +1375 -0
  79. package/templates/docs/UI_COMPONENTS_GUIDE.md +893 -0
@@ -0,0 +1,927 @@
1
+ # Architecture Patterns
2
+
3
+ Comprehensive guide to architectural patterns used in the Berndorf e-commerce project. Follow these patterns for consistency and maintainability.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Service Module Pattern](#service-module-pattern)
8
+ 2. [State Management with Zustand](#state-management-with-zustand)
9
+ 3. [Data Fetching with React Query](#data-fetching-with-react-query)
10
+ 4. [Form Patterns](#form-patterns)
11
+ 5. [Validation Patterns](#validation-patterns)
12
+ 6. [Internationalization (i18n)](#internationalization-i18n)
13
+ 7. [Authentication Patterns](#authentication-patterns)
14
+ 8. [API Communication](#api-communication)
15
+
16
+ ---
17
+
18
+ ## Service Module Pattern
19
+
20
+ All features follow a consistent service module structure for organization and maintainability.
21
+
22
+ ### Directory Structure
23
+
24
+ ```
25
+ src/services/[feature]/
26
+ ├── index.ts # Public exports
27
+ ├── api/ # API client functions
28
+ │ └── [feature].api.ts
29
+ ├── queries/ # React Query hooks
30
+ │ └── [feature].queries.ts
31
+ ├── hooks/ # Custom hooks
32
+ │ └── use[Feature].ts
33
+ ├── types/ # TypeScript types
34
+ │ └── [feature].types.ts
35
+ ├── actions/ # Server actions
36
+ │ └── [feature].actions.ts
37
+ ├── store/ # Zustand stores
38
+ │ └── [feature].store.ts
39
+ ├── constants/ # Constants
40
+ │ └── [feature].constants.ts
41
+ └── helpers/ # Helper functions
42
+ └── [feature].helpers.ts
43
+ ```
44
+
45
+ ### Complete Example: Product Service Module
46
+
47
+ #### 1. Index File (Public API)
48
+
49
+ **File:** `src/services/product/index.ts`
50
+
51
+ ```typescript
52
+ // Export all public APIs
53
+ export * from './api/product.api';
54
+ export * from './queries/product.queries';
55
+ export * from './hooks/useProducts';
56
+ export * from './types/product.types';
57
+ export * from './actions/product.actions';
58
+ export * from './store/product.store';
59
+ export * from './constants/product.constants';
60
+ export * from './helpers/product.helpers';
61
+ ```
62
+
63
+ #### 2. Types Definition
64
+
65
+ **File:** `src/services/product/types/product.types.ts`
66
+
67
+ ```typescript
68
+ // API Response types
69
+ export interface ProductApiResponse {
70
+ id: string;
71
+ name: string;
72
+ description: string;
73
+ price: number;
74
+ images: string[];
75
+ category: string;
76
+ stock: number;
77
+ createdAt: string;
78
+ }
79
+
80
+ // Frontend model types
81
+ export interface Product {
82
+ id: string;
83
+ name: string;
84
+ description: string;
85
+ price: number;
86
+ formattedPrice: string;
87
+ images: string[];
88
+ primaryImage: string;
89
+ category: string;
90
+ inStock: boolean;
91
+ createdAt: Date;
92
+ }
93
+
94
+ // Request types
95
+ export interface CreateProductRequest {
96
+ name: string;
97
+ description: string;
98
+ price: number;
99
+ categoryId: string;
100
+ }
101
+
102
+ // Filter types
103
+ export interface ProductFilters {
104
+ category?: string;
105
+ minPrice?: number;
106
+ maxPrice?: number;
107
+ inStock?: boolean;
108
+ }
109
+ ```
110
+
111
+ #### 3. API Client
112
+
113
+ **File:** `src/services/product/api/product.api.ts`
114
+
115
+ ```typescript
116
+ import { apiRequest } from '@/lib/apiRequest';
117
+ import type { Product, ProductApiResponse, CreateProductRequest, ProductFilters } from '../types/product.types';
118
+ import { transformProductResponse } from '../helpers/product.helpers';
119
+
120
+ /**
121
+ * Fetch all products with optional filters
122
+ */
123
+ export async function getProducts(filters?: ProductFilters): Promise<Product[]> {
124
+ const queryParams = new URLSearchParams();
125
+
126
+ if (filters?.category) queryParams.append('category', filters.category);
127
+ if (filters?.minPrice) queryParams.append('minPrice', String(filters.minPrice));
128
+ if (filters?.maxPrice) queryParams.append('maxPrice', String(filters.maxPrice));
129
+ if (filters?.inStock !== undefined) queryParams.append('inStock', String(filters.inStock));
130
+
131
+ const url = `/api/products${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
132
+
133
+ const response = await apiRequest<ProductApiResponse[]>({
134
+ url,
135
+ method: 'GET',
136
+ });
137
+
138
+ return response.map(transformProductResponse);
139
+ }
140
+
141
+ /**
142
+ * Fetch a single product by ID
143
+ */
144
+ export async function getProduct(id: string): Promise<Product> {
145
+ const response = await apiRequest<ProductApiResponse>({
146
+ url: `/api/products/${id}`,
147
+ method: 'GET',
148
+ });
149
+
150
+ return transformProductResponse(response);
151
+ }
152
+
153
+ /**
154
+ * Create a new product
155
+ */
156
+ export async function createProduct(data: CreateProductRequest): Promise<Product> {
157
+ const response = await apiRequest<ProductApiResponse>({
158
+ url: '/api/products',
159
+ method: 'POST',
160
+ data,
161
+ });
162
+
163
+ return transformProductResponse(response);
164
+ }
165
+
166
+ /**
167
+ * Update an existing product
168
+ */
169
+ export async function updateProduct(id: string, data: Partial<CreateProductRequest>): Promise<Product> {
170
+ const response = await apiRequest<ProductApiResponse>({
171
+ url: `/api/products/${id}`,
172
+ method: 'PATCH',
173
+ data,
174
+ });
175
+
176
+ return transformProductResponse(response);
177
+ }
178
+
179
+ /**
180
+ * Delete a product
181
+ */
182
+ export async function deleteProduct(id: string): Promise<void> {
183
+ await apiRequest<void>({
184
+ url: `/api/products/${id}`,
185
+ method: 'DELETE',
186
+ });
187
+ }
188
+ ```
189
+
190
+ #### 4. Helper Functions
191
+
192
+ **File:** `src/services/product/helpers/product.helpers.ts`
193
+
194
+ ```typescript
195
+ import type { Product, ProductApiResponse } from '../types/product.types';
196
+
197
+ /**
198
+ * Transform API response to frontend model
199
+ */
200
+ export function transformProductResponse(data: ProductApiResponse): Product {
201
+ return {
202
+ id: data.id,
203
+ name: data.name,
204
+ description: data.description,
205
+ price: data.price,
206
+ formattedPrice: formatPrice(data.price),
207
+ images: data.images,
208
+ primaryImage: data.images[0] || '/placeholder.jpg',
209
+ category: data.category,
210
+ inStock: data.stock > 0,
211
+ createdAt: new Date(data.createdAt),
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Format price with currency
217
+ */
218
+ export function formatPrice(price: number): string {
219
+ return new Intl.NumberFormat('de-AT', {
220
+ style: 'currency',
221
+ currency: 'EUR',
222
+ }).format(price);
223
+ }
224
+
225
+ /**
226
+ * Check if product is new (created within last 30 days)
227
+ */
228
+ export function isNewProduct(createdAt: Date): boolean {
229
+ const thirtyDaysAgo = new Date();
230
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
231
+ return createdAt > thirtyDaysAgo;
232
+ }
233
+ ```
234
+
235
+ #### 5. React Query Hooks
236
+
237
+ **File:** `src/services/product/queries/product.queries.ts`
238
+
239
+ ```typescript
240
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
241
+ import { toast } from 'sonner';
242
+ import type { ProductFilters, CreateProductRequest } from '../types/product.types';
243
+ import {
244
+ getProducts,
245
+ getProduct,
246
+ createProduct,
247
+ updateProduct,
248
+ deleteProduct,
249
+ } from '../api/product.api';
250
+
251
+ // Query Keys
252
+ export const productKeys = {
253
+ all: ['products'] as const,
254
+ lists: () => [...productKeys.all, 'list'] as const,
255
+ list: (filters?: ProductFilters) => [...productKeys.lists(), filters] as const,
256
+ details: () => [...productKeys.all, 'detail'] as const,
257
+ detail: (id: string) => [...productKeys.details(), id] as const,
258
+ };
259
+
260
+ /**
261
+ * Fetch all products with optional filters
262
+ */
263
+ export function useProductsQuery(filters?: ProductFilters) {
264
+ return useQuery({
265
+ queryKey: productKeys.list(filters),
266
+ queryFn: () => getProducts(filters),
267
+ staleTime: 5 * 60 * 1000, // 5 minutes
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Fetch a single product by ID
273
+ */
274
+ export function useProductQuery(id: string) {
275
+ return useQuery({
276
+ queryKey: productKeys.detail(id),
277
+ queryFn: () => getProduct(id),
278
+ enabled: !!id,
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Create a new product
284
+ */
285
+ export function useCreateProductMutation() {
286
+ const queryClient = useQueryClient();
287
+
288
+ return useMutation({
289
+ mutationFn: createProduct,
290
+ onSuccess: () => {
291
+ queryClient.invalidateQueries({ queryKey: productKeys.lists() });
292
+ toast.success('Product created successfully');
293
+ },
294
+ onError: (error: Error) => {
295
+ toast.error(error.message || 'Failed to create product');
296
+ },
297
+ });
298
+ }
299
+
300
+ /**
301
+ * Update an existing product
302
+ */
303
+ export function useUpdateProductMutation() {
304
+ const queryClient = useQueryClient();
305
+
306
+ return useMutation({
307
+ mutationFn: ({ id, data }: { id: string; data: Partial<CreateProductRequest> }) =>
308
+ updateProduct(id, data),
309
+ onSuccess: (_, variables) => {
310
+ queryClient.invalidateQueries({ queryKey: productKeys.lists() });
311
+ queryClient.invalidateQueries({ queryKey: productKeys.detail(variables.id) });
312
+ toast.success('Product updated successfully');
313
+ },
314
+ onError: (error: Error) => {
315
+ toast.error(error.message || 'Failed to update product');
316
+ },
317
+ });
318
+ }
319
+
320
+ /**
321
+ * Delete a product
322
+ */
323
+ export function useDeleteProductMutation() {
324
+ const queryClient = useQueryClient();
325
+
326
+ return useMutation({
327
+ mutationFn: deleteProduct,
328
+ onSuccess: () => {
329
+ queryClient.invalidateQueries({ queryKey: productKeys.lists() });
330
+ toast.success('Product deleted successfully');
331
+ },
332
+ onError: (error: Error) => {
333
+ toast.error(error.message || 'Failed to delete product');
334
+ },
335
+ });
336
+ }
337
+ ```
338
+
339
+ #### 6. Custom Hooks
340
+
341
+ **File:** `src/services/product/hooks/useProducts.ts`
342
+
343
+ ```typescript
344
+ import { useMemo } from 'react';
345
+ import { useProductsQuery } from '../queries/product.queries';
346
+ import type { ProductFilters } from '../types/product.types';
347
+ import { isNewProduct } from '../helpers/product.helpers';
348
+
349
+ export function useProducts(filters?: ProductFilters) {
350
+ const { data, isLoading, error } = useProductsQuery(filters);
351
+
352
+ const products = useMemo(() => {
353
+ if (!data) return [];
354
+
355
+ return data.map(product => ({
356
+ ...product,
357
+ isNew: isNewProduct(product.createdAt),
358
+ }));
359
+ }, [data]);
360
+
361
+ const inStockProducts = useMemo(
362
+ () => products.filter(p => p.inStock),
363
+ [products],
364
+ );
365
+
366
+ const newProducts = useMemo(
367
+ () => products.filter(p => p.isNew),
368
+ [products],
369
+ );
370
+
371
+ return {
372
+ products,
373
+ inStockProducts,
374
+ newProducts,
375
+ isLoading,
376
+ error,
377
+ isEmpty: products.length === 0,
378
+ };
379
+ }
380
+ ```
381
+
382
+ #### 7. Server Actions
383
+
384
+ **File:** `src/services/product/actions/product.actions.ts`
385
+
386
+ ```typescript
387
+ 'use server';
388
+
389
+ import { revalidatePath } from 'next/cache';
390
+ import type { CreateProductRequest } from '../types/product.types';
391
+
392
+ export async function createProductAction(data: CreateProductRequest) {
393
+ try {
394
+ const response = await fetch(`${process.env.API_URL}/products`, {
395
+ method: 'POST',
396
+ headers: {
397
+ 'Content-Type': 'application/json',
398
+ },
399
+ body: JSON.stringify(data),
400
+ });
401
+
402
+ if (!response.ok) {
403
+ const error = await response.json();
404
+ return { success: false, error: error.message };
405
+ }
406
+
407
+ const product = await response.json();
408
+
409
+ // Revalidate relevant paths
410
+ revalidatePath('/products');
411
+ revalidatePath(`/products/${product.id}`);
412
+
413
+ return { success: true, data: product };
414
+ } catch (error) {
415
+ console.error('Create product action error:', error);
416
+ return { success: false, error: 'Failed to create product' };
417
+ }
418
+ }
419
+
420
+ export async function deleteProductAction(id: string) {
421
+ try {
422
+ const response = await fetch(`${process.env.API_URL}/products/${id}`, {
423
+ method: 'DELETE',
424
+ });
425
+
426
+ if (!response.ok) {
427
+ const error = await response.json();
428
+ return { success: false, error: error.message };
429
+ }
430
+
431
+ // Revalidate relevant paths
432
+ revalidatePath('/products');
433
+
434
+ return { success: true };
435
+ } catch (error) {
436
+ console.error('Delete product action error:', error);
437
+ return { success: false, error: 'Failed to delete product' };
438
+ }
439
+ }
440
+ ```
441
+
442
+ #### 8. Zustand Store
443
+
444
+ **File:** `src/services/product/store/product.store.ts`
445
+
446
+ ```typescript
447
+ import { create } from 'zustand';
448
+ import type { ProductFilters } from '../types/product.types';
449
+
450
+ interface ProductStore {
451
+ filters: ProductFilters;
452
+ selectedProductId: string | null;
453
+ setFilters: (filters: ProductFilters) => void;
454
+ setSelectedProductId: (id: string | null) => void;
455
+ resetFilters: () => void;
456
+ reset: () => void;
457
+ }
458
+
459
+ const initialState = {
460
+ filters: {},
461
+ selectedProductId: null,
462
+ };
463
+
464
+ export const useProductStore = create<ProductStore>((set) => ({
465
+ ...initialState,
466
+
467
+ setFilters: (filters) => set({ filters }),
468
+
469
+ setSelectedProductId: (id) => set({ selectedProductId: id }),
470
+
471
+ resetFilters: () => set({ filters: {} }),
472
+
473
+ reset: () => set(initialState),
474
+ }));
475
+ ```
476
+
477
+ #### 9. Constants
478
+
479
+ **File:** `src/services/product/constants/product.constants.ts`
480
+
481
+ ```typescript
482
+ export const PRODUCT_CONSTANTS = {
483
+ MAX_IMAGES: 5,
484
+ MIN_PRICE: 0,
485
+ MAX_PRICE: 10000,
486
+ PRICE_STEP: 0.01,
487
+ NEW_PRODUCT_DAYS: 30,
488
+ } as const;
489
+
490
+ export const PRODUCT_CATEGORIES = [
491
+ { id: 'cutlery', label: 'Cutlery' },
492
+ { id: 'cookware', label: 'Cookware' },
493
+ { id: 'tableware', label: 'Tableware' },
494
+ ] as const;
495
+ ```
496
+
497
+ ---
498
+
499
+ ## State Management with Zustand
500
+
501
+ Use Zustand for global state that needs to be shared across components.
502
+
503
+ ### When to Use Zustand
504
+
505
+ - User authentication state
506
+ - Shopping cart
507
+ - UI preferences (theme, language)
508
+ - Filter/search state across pages
509
+ - Global modals/overlays
510
+
511
+ ### Zustand Store Pattern
512
+
513
+ ```typescript
514
+ import { create } from 'zustand';
515
+
516
+ interface Store {
517
+ // State
518
+ count: number;
519
+ items: string[];
520
+
521
+ // Actions
522
+ increment: () => void;
523
+ decrement: () => void;
524
+ addItem: (item: string) => void;
525
+ removeItem: (id: string) => void;
526
+ reset: () => void;
527
+ }
528
+
529
+ const initialState = {
530
+ count: 0,
531
+ items: [],
532
+ };
533
+
534
+ export const useStore = create<Store>((set) => ({
535
+ ...initialState,
536
+
537
+ increment: () => set((state) => ({ count: state.count + 1 })),
538
+
539
+ decrement: () => set((state) => ({ count: state.count - 1 })),
540
+
541
+ addItem: (item) => set((state) => ({ items: [...state.items, item] })),
542
+
543
+ removeItem: (id) => set((state) => ({
544
+ items: state.items.filter((item) => item !== id),
545
+ })),
546
+
547
+ reset: () => set(initialState),
548
+ }));
549
+ ```
550
+
551
+ ### Using Store in Components
552
+
553
+ ```tsx
554
+ 'use client';
555
+
556
+ import { useStore } from '@/services/store/myStore';
557
+
558
+ export function Counter() {
559
+ const count = useStore((state) => state.count);
560
+ const increment = useStore((state) => state.increment);
561
+ const decrement = useStore((state) => state.decrement);
562
+
563
+ return (
564
+ <div>
565
+ <p>Count: {count}</p>
566
+ <button onClick={increment}>+</button>
567
+ <button onClick={decrement}>-</button>
568
+ </div>
569
+ );
570
+ }
571
+ ```
572
+
573
+ ---
574
+
575
+ ## Data Fetching with React Query
576
+
577
+ Use React Query (@tanstack/react-query) for server state management.
578
+
579
+ ### Query Pattern
580
+
581
+ ```typescript
582
+ import { useQuery } from '@tanstack/react-query';
583
+
584
+ export function useDataQuery(id: string) {
585
+ return useQuery({
586
+ queryKey: ['data', id],
587
+ queryFn: () => fetchData(id),
588
+ staleTime: 5 * 60 * 1000, // 5 minutes
589
+ gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
590
+ enabled: !!id, // Only run if id exists
591
+ });
592
+ }
593
+ ```
594
+
595
+ ### Mutation Pattern
596
+
597
+ ```typescript
598
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
599
+ import { toast } from 'sonner';
600
+
601
+ export function useCreateMutation() {
602
+ const queryClient = useQueryClient();
603
+
604
+ return useMutation({
605
+ mutationFn: createData,
606
+ onSuccess: () => {
607
+ queryClient.invalidateQueries({ queryKey: ['data'] });
608
+ toast.success('Created successfully');
609
+ },
610
+ onError: (error: Error) => {
611
+ toast.error(error.message);
612
+ },
613
+ });
614
+ }
615
+ ```
616
+
617
+ ### Optimistic Updates
618
+
619
+ ```typescript
620
+ export function useUpdateMutation() {
621
+ const queryClient = useQueryClient();
622
+
623
+ return useMutation({
624
+ mutationFn: updateData,
625
+ onMutate: async (newData) => {
626
+ // Cancel outgoing queries
627
+ await queryClient.cancelQueries({ queryKey: ['data', newData.id] });
628
+
629
+ // Snapshot previous value
630
+ const previousData = queryClient.getQueryData(['data', newData.id]);
631
+
632
+ // Optimistically update
633
+ queryClient.setQueryData(['data', newData.id], newData);
634
+
635
+ return { previousData };
636
+ },
637
+ onError: (err, newData, context) => {
638
+ // Rollback on error
639
+ queryClient.setQueryData(['data', newData.id], context?.previousData);
640
+ },
641
+ onSettled: (data, error, variables) => {
642
+ queryClient.invalidateQueries({ queryKey: ['data', variables.id] });
643
+ },
644
+ });
645
+ }
646
+ ```
647
+
648
+ ---
649
+
650
+ ## Form Patterns
651
+
652
+ Use react-hook-form with Zod validation.
653
+
654
+ ### Basic Form Pattern
655
+
656
+ ```tsx
657
+ 'use client';
658
+
659
+ import { useForm } from 'react-hook-form';
660
+ import { zodResolver } from '@hookform/resolvers/zod';
661
+ import { z } from 'zod';
662
+ import { Form } from '@/components/ui/form/Form';
663
+ import { Input } from '@/components/ui/Input';
664
+ import { Button } from '@/components/ui/Button';
665
+
666
+ const schema = z.object({
667
+ email: z.string().email('Errors.validation.email'),
668
+ password: z.string().min(8, 'Errors.validation.minLength|{"min":8}'),
669
+ });
670
+
671
+ type FormData = z.infer<typeof schema>;
672
+
673
+ export function LoginForm() {
674
+ const form = useForm<FormData>({
675
+ resolver: zodResolver(schema),
676
+ defaultValues: {
677
+ email: '',
678
+ password: '',
679
+ },
680
+ });
681
+
682
+ const onSubmit = (data: FormData) => {
683
+ console.log(data);
684
+ };
685
+
686
+ return (
687
+ <Form form={form} validationSchema={schema}>
688
+ <Form.Item name="email">
689
+ {(props) => <Input {...props} label="Email" type="email" />}
690
+ </Form.Item>
691
+
692
+ <Form.Item name="password">
693
+ {(props) => <PasswordInput {...props} label="Password" />}
694
+ </Form.Item>
695
+
696
+ <Button onPress={form.handleSubmit(onSubmit)} isLoading={form.formState.isSubmitting}>
697
+ Login
698
+ </Button>
699
+ </Form>
700
+ );
701
+ }
702
+ ```
703
+
704
+ ### Form with Mutation
705
+
706
+ ```tsx
707
+ import { useLoginMutation } from '@/services/auth';
708
+
709
+ export function LoginForm() {
710
+ const form = useForm<FormData>();
711
+ const loginMutation = useLoginMutation();
712
+
713
+ const onSubmit = (data: FormData) => {
714
+ loginMutation.mutate(data);
715
+ };
716
+
717
+ return (
718
+ <Form form={form}>
719
+ {/* Form fields */}
720
+ <Button onPress={form.handleSubmit(onSubmit)} isLoading={loginMutation.isPending}>
721
+ Login
722
+ </Button>
723
+ </Form>
724
+ );
725
+ }
726
+ ```
727
+
728
+ ---
729
+
730
+ ## Validation Patterns
731
+
732
+ ### Zod Schema Patterns
733
+
734
+ ```typescript
735
+ import { z } from 'zod';
736
+
737
+ // Basic validations
738
+ const basicSchema = z.object({
739
+ email: z.string().email('Errors.validation.email'),
740
+ password: z.string().min(8, 'Errors.validation.minLength|{"min":8}'),
741
+ age: z.number().min(18, 'Errors.validation.minAge|{"age":18}'),
742
+ website: z.string().url('Errors.validation.url').optional(),
743
+ });
744
+
745
+ // Complex validations
746
+ const complexSchema = z.object({
747
+ password: z.string()
748
+ .min(8, 'Password must be at least 8 characters')
749
+ .regex(/[A-Z]/, 'Password must contain uppercase letter')
750
+ .regex(/[a-z]/, 'Password must contain lowercase letter')
751
+ .regex(/[0-9]/, 'Password must contain number'),
752
+
753
+ confirmPassword: z.string(),
754
+ }).refine((data) => data.password === data.confirmPassword, {
755
+ message: 'Passwords do not match',
756
+ path: ['confirmPassword'],
757
+ });
758
+
759
+ // Array validation
760
+ const arraySchema = z.object({
761
+ tags: z.array(z.string()).min(1, 'At least one tag required'),
762
+ items: z.array(z.object({
763
+ id: z.string(),
764
+ quantity: z.number().min(1),
765
+ })),
766
+ });
767
+
768
+ // Conditional validation
769
+ const conditionalSchema = z.object({
770
+ type: z.enum(['individual', 'company']),
771
+ companyName: z.string().optional(),
772
+ }).refine((data) => {
773
+ if (data.type === 'company') {
774
+ return !!data.companyName;
775
+ }
776
+ return true;
777
+ }, {
778
+ message: 'Company name is required',
779
+ path: ['companyName'],
780
+ });
781
+ ```
782
+
783
+ ---
784
+
785
+ ## Internationalization (i18n)
786
+
787
+ Use next-intl for translations.
788
+
789
+ ### Translation Files
790
+
791
+ **English:** `/src/locales/en.json`
792
+ **German:** `/src/locales/de.json`
793
+
794
+ ```json
795
+ {
796
+ "Common": {
797
+ "submit": "Submit",
798
+ "cancel": "Cancel",
799
+ "save": "Save"
800
+ },
801
+ "Errors": {
802
+ "validation": {
803
+ "required": "This field is required",
804
+ "email": "Invalid email address",
805
+ "minLength": "Minimum {min} characters required"
806
+ }
807
+ }
808
+ }
809
+ ```
810
+
811
+ ### Using Translations
812
+
813
+ ```tsx
814
+ 'use client';
815
+
816
+ import { useTranslations } from 'next-intl';
817
+
818
+ export function MyComponent() {
819
+ const t = useTranslations('Common');
820
+
821
+ return (
822
+ <div>
823
+ <h1>{t('title')}</h1>
824
+ <Button>{t('submit')}</Button>
825
+ </div>
826
+ );
827
+ }
828
+ ```
829
+
830
+ ### Translation with Parameters
831
+
832
+ ```tsx
833
+ const t = useTranslations('Errors.validation');
834
+
835
+ // Usage
836
+ t('minLength', { min: 8 }); // "Minimum 8 characters required"
837
+ ```
838
+
839
+ ---
840
+
841
+ ## Authentication Patterns
842
+
843
+ ### Auth Hook Pattern
844
+
845
+ ```typescript
846
+ 'use client';
847
+
848
+ import { useMutation } from '@tanstack/react-query';
849
+ import { useRouter } from 'next/navigation';
850
+ import { toast } from 'sonner';
851
+
852
+ export function useLoginMutation(redirectUrl?: string) {
853
+ const router = useRouter();
854
+
855
+ return useMutation({
856
+ mutationFn: loginAction,
857
+ onSuccess: async (result) => {
858
+ if (result.success) {
859
+ toast.success('Login successful');
860
+
861
+ // Wait for cookies to propagate
862
+ await new Promise(resolve => setTimeout(resolve, 800));
863
+
864
+ // Force reload for clean state
865
+ window.location.href = redirectUrl || '/dashboard';
866
+ } else {
867
+ toast.error(result.error);
868
+ }
869
+ },
870
+ onError: (error: Error) => {
871
+ toast.error(error.message);
872
+ },
873
+ });
874
+ }
875
+ ```
876
+
877
+ ---
878
+
879
+ ## API Communication
880
+
881
+ ### API Request Utility
882
+
883
+ ```typescript
884
+ interface ApiRequestOptions {
885
+ url: string;
886
+ method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
887
+ data?: unknown;
888
+ headers?: Record<string, string>;
889
+ }
890
+
891
+ export async function apiRequest<T>({ url, method, data, headers }: ApiRequestOptions): Promise<T> {
892
+ const response = await fetch(url, {
893
+ method,
894
+ headers: {
895
+ 'Content-Type': 'application/json',
896
+ ...headers,
897
+ },
898
+ ...(data && { body: JSON.stringify(data) }),
899
+ });
900
+
901
+ if (!response.ok) {
902
+ const error = await response.json();
903
+ throw new Error(error.message || 'API request failed');
904
+ }
905
+
906
+ return response.json();
907
+ }
908
+ ```
909
+
910
+ ---
911
+
912
+ ## Summary
913
+
914
+ Follow these architectural patterns for:
915
+
916
+ 1. **Consistency** - All features use the same structure
917
+ 2. **Maintainability** - Easy to find and update code
918
+ 3. **Type Safety** - Full TypeScript coverage
919
+ 4. **Performance** - Optimized data fetching and caching
920
+ 5. **Developer Experience** - Clear patterns and conventions
921
+
922
+ ## Need More Information?
923
+
924
+ - **Quick Reference** → See `AI_QUICK_REFERENCE.md`
925
+ - **UI Components** → See `UI_COMPONENTS_GUIDE.md`
926
+ - **Implementation Guide** → See `IMPLEMENTATION_GUIDE.md`
927
+ - **Figma to Code** → See `FIGMA_TO_CODE_GUIDE.md`