@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,892 @@
1
+ # Implementation Guide
2
+
3
+ Step-by-step guide for implementing features in the Berndorf e-commerce project. Follow this guide to ensure consistency and quality.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Pre-Implementation Checklist](#pre-implementation-checklist)
8
+ 2. [Implementation Steps](#implementation-steps)
9
+ 3. [Quality Checklist](#quality-checklist)
10
+ 4. [Troubleshooting](#troubleshooting)
11
+ 5. [Complete Example](#complete-example)
12
+
13
+ ---
14
+
15
+ ## Pre-Implementation Checklist
16
+
17
+ Before starting any implementation, verify:
18
+
19
+ ### 1. Requirements Clarity
20
+
21
+ - [ ] Figma design is complete and reviewed
22
+ - [ ] Feature requirements are documented
23
+ - [ ] API endpoints are defined
24
+ - [ ] Data models are specified
25
+ - [ ] User flows are clear
26
+
27
+ ### 2. Technical Review
28
+
29
+ - [ ] Checked existing components in `/src/components/ui/`
30
+ - [ ] Checked existing elements in `/src/components/elements/`
31
+ - [ ] Reviewed similar features in `/src/services/`
32
+ - [ ] Identified reusable patterns
33
+ - [ ] No new UI libraries needed
34
+
35
+ ### 3. Planning
36
+
37
+ - [ ] Service module structure planned
38
+ - [ ] Component hierarchy defined
39
+ - [ ] State management approach decided
40
+ - [ ] Translation keys prepared
41
+ - [ ] Validation rules defined
42
+
43
+ ---
44
+
45
+ ## Implementation Steps
46
+
47
+ Follow these steps in order for any new feature.
48
+
49
+ ### Step 1: Create Service Module Structure
50
+
51
+ Create the directory structure for your feature.
52
+
53
+ ```bash
54
+ # Create directory structure
55
+ mkdir -p src/services/[feature]/{api,queries,hooks,types,actions,store,constants,helpers}
56
+ ```
57
+
58
+ Create `index.ts` to export all modules:
59
+
60
+ ```typescript
61
+ // src/services/[feature]/index.ts
62
+ export * from './api/[feature].api';
63
+ export * from './queries/[feature].queries';
64
+ export * from './hooks/use[Feature]';
65
+ export * from './types/[feature].types';
66
+ export * from './actions/[feature].actions';
67
+ export * from './store/[feature].store';
68
+ export * from './constants/[feature].constants';
69
+ export * from './helpers/[feature].helpers';
70
+ ```
71
+
72
+ ### Step 2: Define TypeScript Types
73
+
74
+ Define all types for your feature.
75
+
76
+ **File:** `src/services/[feature]/types/[feature].types.ts`
77
+
78
+ ```typescript
79
+ // API Response types (match backend structure)
80
+ export interface FeatureApiResponse {
81
+ id: string;
82
+ name: string;
83
+ created_at: string; // snake_case from API
84
+ }
85
+
86
+ // Frontend Model types (camelCase for frontend)
87
+ export interface Feature {
88
+ id: string;
89
+ name: string;
90
+ createdAt: Date;
91
+ }
92
+
93
+ // Request types
94
+ export interface CreateFeatureRequest {
95
+ name: string;
96
+ }
97
+
98
+ export interface UpdateFeatureRequest {
99
+ name?: string;
100
+ }
101
+
102
+ // Filter types
103
+ export interface FeatureFilters {
104
+ search?: string;
105
+ status?: 'active' | 'inactive';
106
+ }
107
+ ```
108
+
109
+ ### Step 3: Create Helper Functions
110
+
111
+ Create transformation and utility functions.
112
+
113
+ **File:** `src/services/[feature]/helpers/[feature].helpers.ts`
114
+
115
+ ```typescript
116
+ import type { Feature, FeatureApiResponse } from '../types/[feature].types';
117
+
118
+ /**
119
+ * Transform API response to frontend model
120
+ */
121
+ export function transformFeatureResponse(data: FeatureApiResponse): Feature {
122
+ return {
123
+ id: data.id,
124
+ name: data.name,
125
+ createdAt: new Date(data.created_at),
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Format date for display
131
+ */
132
+ export function formatFeatureDate(date: Date): string {
133
+ return new Intl.DateTimeFormat('de-AT', {
134
+ year: 'numeric',
135
+ month: 'long',
136
+ day: 'numeric',
137
+ }).format(date);
138
+ }
139
+ ```
140
+
141
+ ### Step 4: Create API Client
142
+
143
+ Create API client functions.
144
+
145
+ **File:** `src/services/[feature]/api/[feature].api.ts`
146
+
147
+ ```typescript
148
+ import { apiRequest } from '@/lib/apiRequest';
149
+ import type {
150
+ Feature,
151
+ FeatureApiResponse,
152
+ CreateFeatureRequest,
153
+ UpdateFeatureRequest,
154
+ FeatureFilters,
155
+ } from '../types/[feature].types';
156
+ import { transformFeatureResponse } from '../helpers/[feature].helpers';
157
+
158
+ /**
159
+ * Fetch all features
160
+ */
161
+ export async function getFeatures(filters?: FeatureFilters): Promise<Feature[]> {
162
+ const queryParams = new URLSearchParams();
163
+
164
+ if (filters?.search) queryParams.append('search', filters.search);
165
+ if (filters?.status) queryParams.append('status', filters.status);
166
+
167
+ const url = `/api/features${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
168
+
169
+ const response = await apiRequest<FeatureApiResponse[]>({
170
+ url,
171
+ method: 'GET',
172
+ });
173
+
174
+ return response.map(transformFeatureResponse);
175
+ }
176
+
177
+ /**
178
+ * Fetch single feature
179
+ */
180
+ export async function getFeature(id: string): Promise<Feature> {
181
+ const response = await apiRequest<FeatureApiResponse>({
182
+ url: `/api/features/${id}`,
183
+ method: 'GET',
184
+ });
185
+
186
+ return transformFeatureResponse(response);
187
+ }
188
+
189
+ /**
190
+ * Create new feature
191
+ */
192
+ export async function createFeature(data: CreateFeatureRequest): Promise<Feature> {
193
+ const response = await apiRequest<FeatureApiResponse>({
194
+ url: '/api/features',
195
+ method: 'POST',
196
+ data,
197
+ });
198
+
199
+ return transformFeatureResponse(response);
200
+ }
201
+
202
+ /**
203
+ * Update feature
204
+ */
205
+ export async function updateFeature(id: string, data: UpdateFeatureRequest): Promise<Feature> {
206
+ const response = await apiRequest<FeatureApiResponse>({
207
+ url: `/api/features/${id}`,
208
+ method: 'PATCH',
209
+ data,
210
+ });
211
+
212
+ return transformFeatureResponse(response);
213
+ }
214
+
215
+ /**
216
+ * Delete feature
217
+ */
218
+ export async function deleteFeature(id: string): Promise<void> {
219
+ await apiRequest<void>({
220
+ url: `/api/features/${id}`,
221
+ method: 'DELETE',
222
+ });
223
+ }
224
+ ```
225
+
226
+ ### Step 5: Create React Query Hooks
227
+
228
+ Create React Query hooks for data fetching.
229
+
230
+ **File:** `src/services/[feature]/queries/[feature].queries.ts`
231
+
232
+ ```typescript
233
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
234
+ import { toast } from 'sonner';
235
+ import { useTranslations } from 'next-intl';
236
+ import type { FeatureFilters, CreateFeatureRequest, UpdateFeatureRequest } from '../types/[feature].types';
237
+ import {
238
+ getFeatures,
239
+ getFeature,
240
+ createFeature,
241
+ updateFeature,
242
+ deleteFeature,
243
+ } from '../api/[feature].api';
244
+
245
+ // Query Keys
246
+ export const featureKeys = {
247
+ all: ['features'] as const,
248
+ lists: () => [...featureKeys.all, 'list'] as const,
249
+ list: (filters?: FeatureFilters) => [...featureKeys.lists(), filters] as const,
250
+ details: () => [...featureKeys.all, 'detail'] as const,
251
+ detail: (id: string) => [...featureKeys.details(), id] as const,
252
+ };
253
+
254
+ /**
255
+ * Fetch all features
256
+ */
257
+ export function useFeaturesQuery(filters?: FeatureFilters) {
258
+ return useQuery({
259
+ queryKey: featureKeys.list(filters),
260
+ queryFn: () => getFeatures(filters),
261
+ staleTime: 5 * 60 * 1000, // 5 minutes
262
+ });
263
+ }
264
+
265
+ /**
266
+ * Fetch single feature
267
+ */
268
+ export function useFeatureQuery(id: string) {
269
+ return useQuery({
270
+ queryKey: featureKeys.detail(id),
271
+ queryFn: () => getFeature(id),
272
+ enabled: !!id,
273
+ });
274
+ }
275
+
276
+ /**
277
+ * Create feature mutation
278
+ */
279
+ export function useCreateFeatureMutation() {
280
+ const queryClient = useQueryClient();
281
+ const t = useTranslations('Feature');
282
+
283
+ return useMutation({
284
+ mutationFn: createFeature,
285
+ onSuccess: () => {
286
+ queryClient.invalidateQueries({ queryKey: featureKeys.lists() });
287
+ toast.success(t('createSuccess'));
288
+ },
289
+ onError: (error: Error) => {
290
+ toast.error(error.message || t('createError'));
291
+ },
292
+ });
293
+ }
294
+
295
+ /**
296
+ * Update feature mutation
297
+ */
298
+ export function useUpdateFeatureMutation() {
299
+ const queryClient = useQueryClient();
300
+ const t = useTranslations('Feature');
301
+
302
+ return useMutation({
303
+ mutationFn: ({ id, data }: { id: string; data: UpdateFeatureRequest }) =>
304
+ updateFeature(id, data),
305
+ onSuccess: (_, variables) => {
306
+ queryClient.invalidateQueries({ queryKey: featureKeys.lists() });
307
+ queryClient.invalidateQueries({ queryKey: featureKeys.detail(variables.id) });
308
+ toast.success(t('updateSuccess'));
309
+ },
310
+ onError: (error: Error) => {
311
+ toast.error(error.message || t('updateError'));
312
+ },
313
+ });
314
+ }
315
+
316
+ /**
317
+ * Delete feature mutation
318
+ */
319
+ export function useDeleteFeatureMutation() {
320
+ const queryClient = useQueryClient();
321
+ const t = useTranslations('Feature');
322
+
323
+ return useMutation({
324
+ mutationFn: deleteFeature,
325
+ onSuccess: () => {
326
+ queryClient.invalidateQueries({ queryKey: featureKeys.lists() });
327
+ toast.success(t('deleteSuccess'));
328
+ },
329
+ onError: (error: Error) => {
330
+ toast.error(error.message || t('deleteError'));
331
+ },
332
+ });
333
+ }
334
+ ```
335
+
336
+ ### Step 6: Create Custom Hooks (Optional)
337
+
338
+ Create custom hooks for complex logic.
339
+
340
+ **File:** `src/services/[feature]/hooks/useFeature.ts`
341
+
342
+ ```typescript
343
+ import { useMemo } from 'react';
344
+ import { useFeaturesQuery } from '../queries/[feature].queries';
345
+ import type { FeatureFilters } from '../types/[feature].types';
346
+
347
+ export function useFeatures(filters?: FeatureFilters) {
348
+ const { data, isLoading, error } = useFeaturesQuery(filters);
349
+
350
+ const features = useMemo(() => data || [], [data]);
351
+
352
+ const activeFeatures = useMemo(
353
+ () => features.filter(f => f.status === 'active'),
354
+ [features],
355
+ );
356
+
357
+ return {
358
+ features,
359
+ activeFeatures,
360
+ isLoading,
361
+ error,
362
+ isEmpty: features.length === 0,
363
+ };
364
+ }
365
+ ```
366
+
367
+ ### Step 7: Create Zustand Store (If Needed)
368
+
369
+ Create Zustand store for global state.
370
+
371
+ **File:** `src/services/[feature]/store/[feature].store.ts`
372
+
373
+ ```typescript
374
+ import { create } from 'zustand';
375
+ import type { FeatureFilters } from '../types/[feature].types';
376
+
377
+ interface FeatureStore {
378
+ filters: FeatureFilters;
379
+ selectedId: string | null;
380
+ setFilters: (filters: FeatureFilters) => void;
381
+ setSelectedId: (id: string | null) => void;
382
+ resetFilters: () => void;
383
+ reset: () => void;
384
+ }
385
+
386
+ const initialState = {
387
+ filters: {},
388
+ selectedId: null,
389
+ };
390
+
391
+ export const useFeatureStore = create<FeatureStore>((set) => ({
392
+ ...initialState,
393
+
394
+ setFilters: (filters) => set({ filters }),
395
+
396
+ setSelectedId: (id) => set({ selectedId: id }),
397
+
398
+ resetFilters: () => set({ filters: {} }),
399
+
400
+ reset: () => set(initialState),
401
+ }));
402
+ ```
403
+
404
+ ### Step 8: Create Server Actions (If Needed)
405
+
406
+ Create server actions for server-side operations.
407
+
408
+ **File:** `src/services/[feature]/actions/[feature].actions.ts`
409
+
410
+ ```typescript
411
+ 'use server';
412
+
413
+ import { revalidatePath } from 'next/cache';
414
+ import type { CreateFeatureRequest } from '../types/[feature].types';
415
+
416
+ export async function createFeatureAction(data: CreateFeatureRequest) {
417
+ try {
418
+ const response = await fetch(`${process.env.API_URL}/features`, {
419
+ method: 'POST',
420
+ headers: {
421
+ 'Content-Type': 'application/json',
422
+ },
423
+ body: JSON.stringify(data),
424
+ });
425
+
426
+ if (!response.ok) {
427
+ const error = await response.json();
428
+ return { success: false, error: error.message };
429
+ }
430
+
431
+ const feature = await response.json();
432
+
433
+ // Revalidate relevant paths
434
+ revalidatePath('/features');
435
+ revalidatePath(`/features/${feature.id}`);
436
+
437
+ return { success: true, data: feature };
438
+ } catch (error) {
439
+ console.error('Create feature action error:', error);
440
+ return { success: false, error: 'Failed to create feature' };
441
+ }
442
+ }
443
+ ```
444
+
445
+ ### Step 9: Add Translations
446
+
447
+ Add translation keys to both English and German files.
448
+
449
+ **English:** `/src/locales/en.json`
450
+
451
+ ```json
452
+ {
453
+ "Feature": {
454
+ "title": "Features",
455
+ "create": "Create Feature",
456
+ "edit": "Edit Feature",
457
+ "delete": "Delete Feature",
458
+ "name": "Name",
459
+ "description": "Description",
460
+ "createSuccess": "Feature created successfully",
461
+ "createError": "Failed to create feature",
462
+ "updateSuccess": "Feature updated successfully",
463
+ "updateError": "Failed to update feature",
464
+ "deleteSuccess": "Feature deleted successfully",
465
+ "deleteError": "Failed to delete feature"
466
+ }
467
+ }
468
+ ```
469
+
470
+ **German:** `/src/locales/de.json`
471
+
472
+ ```json
473
+ {
474
+ "Feature": {
475
+ "title": "Funktionen",
476
+ "create": "Funktion erstellen",
477
+ "edit": "Funktion bearbeiten",
478
+ "delete": "Funktion löschen",
479
+ "name": "Name",
480
+ "description": "Beschreibung",
481
+ "createSuccess": "Funktion erfolgreich erstellt",
482
+ "createError": "Funktion konnte nicht erstellt werden",
483
+ "updateSuccess": "Funktion erfolgreich aktualisiert",
484
+ "updateError": "Funktion konnte nicht aktualisiert werden",
485
+ "deleteSuccess": "Funktion erfolgreich gelöscht",
486
+ "deleteError": "Funktion konnte nicht gelöscht werden"
487
+ }
488
+ }
489
+ ```
490
+
491
+ ### Step 10: Create Page Components
492
+
493
+ Create page components using the service module.
494
+
495
+ **File:** `src/app/[locale]/features/page.tsx`
496
+
497
+ ```tsx
498
+ 'use client';
499
+
500
+ import { useTranslations } from 'next-intl';
501
+ import { Button } from '@/components/ui/Button';
502
+ import { useFeaturesQuery } from '@/services/feature';
503
+ import { FeatureList } from './_components/FeatureList';
504
+
505
+ export default function FeaturesPage() {
506
+ const t = useTranslations('Feature');
507
+ const { data: features, isLoading } = useFeaturesQuery();
508
+
509
+ return (
510
+ <div className="container mx-auto px-4 py-8">
511
+ <div className="flex items-center justify-between mb-6">
512
+ <h1 className="text-2xl font-bold">{t('title')}</h1>
513
+ <Button href="/features/new">{t('create')}</Button>
514
+ </div>
515
+
516
+ {isLoading ? (
517
+ <div>Loading...</div>
518
+ ) : (
519
+ <FeatureList features={features || []} />
520
+ )}
521
+ </div>
522
+ );
523
+ }
524
+ ```
525
+
526
+ ### Step 11: Create Form Components
527
+
528
+ Create form components with validation.
529
+
530
+ **File:** `src/app/[locale]/features/_components/FeatureForm.tsx`
531
+
532
+ ```tsx
533
+ 'use client';
534
+
535
+ import { useForm } from 'react-hook-form';
536
+ import { zodResolver } from '@hookform/resolvers/zod';
537
+ import { z } from 'zod';
538
+ import { useTranslations } from 'next-intl';
539
+ import { Form } from '@/components/ui/form/Form';
540
+ import { Input } from '@/components/ui/Input';
541
+ import { Textarea } from '@/components/ui/Textarea';
542
+ import { Button } from '@/components/ui/Button';
543
+ import { useCreateFeatureMutation } from '@/services/feature';
544
+
545
+ const schema = z.object({
546
+ name: z.string().min(1, 'Errors.validation.required'),
547
+ description: z.string().min(1, 'Errors.validation.required'),
548
+ });
549
+
550
+ type FormData = z.infer<typeof schema>;
551
+
552
+ export function FeatureForm() {
553
+ const t = useTranslations('Feature');
554
+ const createMutation = useCreateFeatureMutation();
555
+
556
+ const form = useForm<FormData>({
557
+ resolver: zodResolver(schema),
558
+ defaultValues: {
559
+ name: '',
560
+ description: '',
561
+ },
562
+ });
563
+
564
+ const onSubmit = (data: FormData) => {
565
+ createMutation.mutate(data);
566
+ };
567
+
568
+ return (
569
+ <Form form={form} validationSchema={schema}>
570
+ <Form.Item name="name">
571
+ {(props) => <Input {...props} label={t('name')} />}
572
+ </Form.Item>
573
+
574
+ <Form.Item name="description">
575
+ {(props) => <Textarea {...props} label={t('description')} />}
576
+ </Form.Item>
577
+
578
+ <div className="col-span-10 flex justify-end gap-4">
579
+ <Button variant="bordered" href="/features">
580
+ {t('cancel')}
581
+ </Button>
582
+ <Button
583
+ onPress={form.handleSubmit(onSubmit)}
584
+ isLoading={createMutation.isPending}
585
+ >
586
+ {t('create')}
587
+ </Button>
588
+ </div>
589
+ </Form>
590
+ );
591
+ }
592
+ ```
593
+
594
+ ### Step 12: Create Element Components (If Needed)
595
+
596
+ Create reusable element components.
597
+
598
+ **File:** `src/components/elements/FeatureCard.tsx`
599
+
600
+ ```tsx
601
+ import { Card, CardBody, CardHeader } from '@heroui/react';
602
+ import { Button } from '@/components/ui/Button';
603
+ import type { Feature } from '@/services/feature';
604
+
605
+ interface FeatureCardProps {
606
+ feature: Feature;
607
+ onEdit?: (id: string) => void;
608
+ onDelete?: (id: string) => void;
609
+ }
610
+
611
+ export function FeatureCard({ feature, onEdit, onDelete }: FeatureCardProps) {
612
+ return (
613
+ <Card>
614
+ <CardHeader>
615
+ <h3 className="text-lg font-semibold">{feature.name}</h3>
616
+ </CardHeader>
617
+ <CardBody>
618
+ <p className="text-default-600">{feature.description}</p>
619
+ <div className="flex gap-2 mt-4">
620
+ {onEdit && (
621
+ <Button size="sm" onPress={() => onEdit(feature.id)}>
622
+ Edit
623
+ </Button>
624
+ )}
625
+ {onDelete && (
626
+ <Button
627
+ size="sm"
628
+ variant="light"
629
+ color="danger"
630
+ onPress={() => onDelete(feature.id)}
631
+ >
632
+ Delete
633
+ </Button>
634
+ )}
635
+ </div>
636
+ </CardBody>
637
+ </Card>
638
+ );
639
+ }
640
+ ```
641
+
642
+ ---
643
+
644
+ ## Quality Checklist
645
+
646
+ Before marking implementation as complete:
647
+
648
+ ### Code Quality
649
+
650
+ - [ ] TypeScript types are defined for all data
651
+ - [ ] No `any` types used
652
+ - [ ] ESLint shows no errors
653
+ - [ ] Code follows existing patterns
654
+ - [ ] Functions have JSDoc comments
655
+ - [ ] Complex logic is documented
656
+
657
+ ### Functionality
658
+
659
+ - [ ] All CRUD operations work correctly
660
+ - [ ] Form validation works as expected
661
+ - [ ] Error handling is implemented
662
+ - [ ] Loading states are shown
663
+ - [ ] Success/error messages are displayed
664
+ - [ ] Data refreshes after mutations
665
+
666
+ ### Translations
667
+
668
+ - [ ] All strings use translations
669
+ - [ ] English translations added
670
+ - [ ] German translations added
671
+ - [ ] Translation keys are organized
672
+ - [ ] No hardcoded text
673
+
674
+ ### UI/UX
675
+
676
+ - [ ] Responsive design works on all screens
677
+ - [ ] Components use existing UI library
678
+ - [ ] Styling follows design system
679
+ - [ ] Accessibility considerations met
680
+ - [ ] Loading states are user-friendly
681
+ - [ ] Error states are clear
682
+
683
+ ### Performance
684
+
685
+ - [ ] React Query cache configured correctly
686
+ - [ ] Unnecessary re-renders avoided
687
+ - [ ] Images are optimized
688
+ - [ ] Data fetching is efficient
689
+
690
+ ### Testing
691
+
692
+ - [ ] Manual testing completed
693
+ - [ ] Edge cases tested
694
+ - [ ] Error scenarios tested
695
+ - [ ] Browser compatibility checked
696
+
697
+ ---
698
+
699
+ ## Troubleshooting
700
+
701
+ ### Common Issues and Solutions
702
+
703
+ #### Issue: Form validation not working
704
+
705
+ **Solution:**
706
+ - Ensure `resolver: zodResolver(schema)` is in `useForm`
707
+ - Verify Zod schema is correct
708
+ - Check that field names match schema keys
709
+ - Ensure `validationSchema` prop is passed to `<Form>`
710
+
711
+ #### Issue: React Query not refetching
712
+
713
+ **Solution:**
714
+ - Check `queryKey` is unique and consistent
715
+ - Verify `invalidateQueries` is called after mutations
716
+ - Check `staleTime` configuration
717
+ - Ensure `enabled` condition is correct
718
+
719
+ #### Issue: Translations not showing
720
+
721
+ **Solution:**
722
+ - Verify translation keys exist in both `en.json` and `de.json`
723
+ - Check namespace matches `useTranslations('Namespace')`
724
+ - Ensure JSON syntax is valid
725
+ - Restart dev server after changing translations
726
+
727
+ #### Issue: TypeScript errors
728
+
729
+ **Solution:**
730
+ - Run `pnpm check:types` to see all errors
731
+ - Ensure types are imported correctly
732
+ - Check that API response types match actual API
733
+ - Verify generic types in React Query hooks
734
+
735
+ #### Issue: Components not updating
736
+
737
+ **Solution:**
738
+ - Check if component is wrapped in 'use client'
739
+ - Verify state updates are triggering re-renders
740
+ - Check React Query cache invalidation
741
+ - Ensure Zustand selectors are correct
742
+
743
+ ---
744
+
745
+ ## Complete Example
746
+
747
+ Here's a complete example implementing a "Tasks" feature:
748
+
749
+ ### 1. Types
750
+
751
+ ```typescript
752
+ // src/services/tasks/types/tasks.types.ts
753
+ export interface TaskApiResponse {
754
+ id: string;
755
+ title: string;
756
+ description: string;
757
+ completed: boolean;
758
+ created_at: string;
759
+ }
760
+
761
+ export interface Task {
762
+ id: string;
763
+ title: string;
764
+ description: string;
765
+ completed: boolean;
766
+ createdAt: Date;
767
+ }
768
+
769
+ export interface CreateTaskRequest {
770
+ title: string;
771
+ description: string;
772
+ }
773
+ ```
774
+
775
+ ### 2. API Client
776
+
777
+ ```typescript
778
+ // src/services/tasks/api/tasks.api.ts
779
+ import { apiRequest } from '@/lib/apiRequest';
780
+ import type { Task, TaskApiResponse, CreateTaskRequest } from '../types/tasks.types';
781
+
782
+ export async function getTasks(): Promise<Task[]> {
783
+ const response = await apiRequest<TaskApiResponse[]>({
784
+ url: '/api/tasks',
785
+ method: 'GET',
786
+ });
787
+
788
+ return response.map(task => ({
789
+ ...task,
790
+ createdAt: new Date(task.created_at),
791
+ }));
792
+ }
793
+
794
+ export async function createTask(data: CreateTaskRequest): Promise<Task> {
795
+ const response = await apiRequest<TaskApiResponse>({
796
+ url: '/api/tasks',
797
+ method: 'POST',
798
+ data,
799
+ });
800
+
801
+ return {
802
+ ...response,
803
+ createdAt: new Date(response.created_at),
804
+ };
805
+ }
806
+ ```
807
+
808
+ ### 3. Queries
809
+
810
+ ```typescript
811
+ // src/services/tasks/queries/tasks.queries.ts
812
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
813
+ import { toast } from 'sonner';
814
+ import { getTasks, createTask } from '../api/tasks.api';
815
+
816
+ export const taskKeys = {
817
+ all: ['tasks'] as const,
818
+ lists: () => [...taskKeys.all, 'list'] as const,
819
+ };
820
+
821
+ export function useTasksQuery() {
822
+ return useQuery({
823
+ queryKey: taskKeys.lists(),
824
+ queryFn: getTasks,
825
+ });
826
+ }
827
+
828
+ export function useCreateTaskMutation() {
829
+ const queryClient = useQueryClient();
830
+
831
+ return useMutation({
832
+ mutationFn: createTask,
833
+ onSuccess: () => {
834
+ queryClient.invalidateQueries({ queryKey: taskKeys.lists() });
835
+ toast.success('Task created');
836
+ },
837
+ });
838
+ }
839
+ ```
840
+
841
+ ### 4. Component
842
+
843
+ ```tsx
844
+ // src/app/[locale]/tasks/page.tsx
845
+ 'use client';
846
+
847
+ import { useTasksQuery, useCreateTaskMutation } from '@/services/tasks';
848
+
849
+ export default function TasksPage() {
850
+ const { data: tasks, isLoading } = useTasksQuery();
851
+ const createMutation = useCreateTaskMutation();
852
+
853
+ const handleCreate = () => {
854
+ createMutation.mutate({
855
+ title: 'New Task',
856
+ description: 'Task description',
857
+ });
858
+ };
859
+
860
+ if (isLoading) return <div>Loading...</div>;
861
+
862
+ return (
863
+ <div>
864
+ <h1>Tasks</h1>
865
+ <button onClick={handleCreate}>Create Task</button>
866
+ <ul>
867
+ {tasks?.map(task => (
868
+ <li key={task.id}>{task.title}</li>
869
+ ))}
870
+ </ul>
871
+ </div>
872
+ );
873
+ }
874
+ ```
875
+
876
+ ---
877
+
878
+ ## Summary
879
+
880
+ Follow this implementation guide to:
881
+
882
+ 1. **Maintain consistency** across the codebase
883
+ 2. **Ensure quality** through checklists
884
+ 3. **Avoid common pitfalls** with troubleshooting guide
885
+ 4. **Speed up development** with complete examples
886
+
887
+ ## Need More Information?
888
+
889
+ - **Quick Reference** → See `AI_QUICK_REFERENCE.md`
890
+ - **UI Components** → See `UI_COMPONENTS_GUIDE.md`
891
+ - **Architecture** → See `ARCHITECTURE_PATTERNS.md`
892
+ - **Figma to Code** → See `FIGMA_TO_CODE_GUIDE.md`