analyze-codebase 1.2.2 → 1.3.1

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.
@@ -0,0 +1,818 @@
1
+ # Developer Agent Documentation
2
+
3
+ ## Overview
4
+
5
+ This document defines the rules and guidelines for the Developer Agent, an AI agent designed to write, maintain, and refactor code for the Uygar Koleji project. The agent follows the project's established patterns, conventions, and coding style.
6
+
7
+ ## Purpose
8
+
9
+ The Developer Agent is responsible for:
10
+
11
+ - Writing new features following project conventions
12
+ - Refactoring existing code while maintaining consistency
13
+ - Fixing bugs and implementing improvements
14
+ - Ensuring code quality and type safety
15
+ - Following established architectural patterns
16
+ - Maintaining consistency with existing codebase
17
+
18
+ ## Language
19
+
20
+ **All Developer Agent code and comments should be in English**, following the project's standard:
21
+
22
+ - Code comments: English
23
+ - Variable/function names: English
24
+ - Type definitions: English
25
+ - Error messages: Use i18next for user-facing messages
26
+ - Documentation: English for technical docs
27
+
28
+ ## Design System and UI Guidelines
29
+
30
+ **When implementing UI components, animations, or visual effects, always refer to the [Design System documentation](../design/design-system.md).**
31
+
32
+ The design system defines:
33
+
34
+ - **Visual Language**: Color palettes, typography, spacing, and gradients
35
+ - **Animation Patterns**: Entrance animations, hover effects, transitions, and timing guidelines
36
+ - **Component Patterns**: Standard patterns for cards, buttons, forms, and navigation
37
+ - **Motion Guidelines**: When and how to use animations, performance considerations, and reduced motion support
38
+
39
+ **Key Design Principles**:
40
+
41
+ - Use the established color gradients (emerald to sky for primary actions, rose to pink for destructive actions)
42
+ - Follow animation timing guidelines (300ms for transitions, 500-600ms for entrances)
43
+ - Implement hover effects consistently (lift, shadow, border color changes, gradient overlays)
44
+ - Use Framer Motion variants from the animation library for consistency
45
+ - Ensure all animations respect `prefers-reduced-motion`
46
+
47
+ **Example**: When creating a new card component, use the interactive card pattern with gradient overlay on hover as documented in the design system.
48
+
49
+ ## Code Style and Conventions
50
+
51
+ ### 1. File Organization
52
+
53
+ #### API Routes (`src/app/api/`)
54
+
55
+ **Structure**:
56
+
57
+ ```typescript
58
+ // Imports (grouped by type)
59
+ import {
60
+ buildOkResponse,
61
+ TSuccessResponse,
62
+ } from "@/lib/api/build-success-response";
63
+ import { BadRequestError } from "@/lib/api/errors/bad-request.error";
64
+ import { parseRequestBodyMiddleware } from "@/lib/api/middlewares";
65
+ import {
66
+ ProtectedRequestContext,
67
+ protectedRouter,
68
+ } from "@/lib/api/routers/protected-router";
69
+ import { buildRouteHandler } from "@/lib/api/routers/route-handler";
70
+
71
+ // Type definitions
72
+ export type GetResourceResponse = TSuccessResponse<Resource[]>;
73
+
74
+ // #region get
75
+ async function getResource(
76
+ _req: NextRequest,
77
+ ctx: ProtectedRequestContext<never, never, GetResourceSchema>,
78
+ ): Promise<NextResponse<GetResourceResponse>> {
79
+ // Implementation
80
+ }
81
+
82
+ const getRouter = protectedRouter<never, never, GetResourceSchema>()
83
+ .use(parseRequestSearchParamsMiddleware(getResourceSchema))
84
+ .get(getResource);
85
+
86
+ export const GET = buildRouteHandler((...params) => getRouter.run(...params));
87
+ //#endregion
88
+
89
+ // #region post
90
+ // Similar structure for POST
91
+ //#endregion
92
+ ```
93
+
94
+ **Rules**:
95
+
96
+ - Use `#region` and `#endregion` to group HTTP methods
97
+ - Always use `ProtectedRequestContext` for protected routes
98
+ - Use `protectedRouter` with proper type parameters
99
+ - Export HTTP methods using `buildRouteHandler`
100
+ - Use `buildOkResponse` for successful responses
101
+ - Always include soft delete check: `eq(table.isDeleted, false)`
102
+ - Use appropriate error types: `BadRequestError`, `NotFoundError`
103
+ - Use i18next for error messages: `i18next.t('ApiRoutes.Utils.creationFailed')`
104
+
105
+ #### Services (`src/lib/services/`)
106
+
107
+ **Structure**:
108
+
109
+ ```typescript
110
+ import { useMutation, useQuery } from "@tanstack/react-query";
111
+ import { HttpClient } from "../utils/http-client";
112
+ import {
113
+ CreateResourceSchema,
114
+ GetResourceSchema,
115
+ } from "../schemas/resource/...";
116
+
117
+ export const resourceRoutes = {
118
+ resources: () => `/resources`,
119
+ resourcesById: (id: string) => `/resources/${id}`,
120
+ };
121
+
122
+ export const getResources = (data: GetResourceSchema) =>
123
+ HttpClient.get<GetResourceResponse>({
124
+ url: resourceRoutes.resources(),
125
+ params: data,
126
+ });
127
+
128
+ export const getResourcesQueryKey = (data: GetResourceSchema) => [
129
+ resourceRoutes.resources(),
130
+ data.page,
131
+ data.limit,
132
+ // ... other relevant params
133
+ ];
134
+
135
+ export const useGetResourcesQuery = (data: GetResourceSchema) =>
136
+ useQuery({
137
+ queryKey: getResourcesQueryKey(data),
138
+ queryFn: () => getResources(data),
139
+ });
140
+
141
+ export const createResource = (data: CreateResourceSchema) =>
142
+ HttpClient.post<CreateResourceResponse>({
143
+ url: resourceRoutes.resources(),
144
+ data,
145
+ });
146
+
147
+ export const useCreateResourceMutation = () =>
148
+ useMutation({
149
+ mutationFn: createResource,
150
+ });
151
+ ```
152
+
153
+ **Rules**:
154
+
155
+ - Define route constants using object with functions
156
+ - Create query key functions for React Query
157
+ - Use `useQuery` and `useMutation` hooks
158
+ - Follow naming: `useGetXQuery`, `useCreateXMutation`, `useUpdateXMutation`, `useDeleteXMutation`
159
+ - Import types from API route files
160
+
161
+ #### Schemas (`src/lib/schemas/`)
162
+
163
+ **Structure**:
164
+
165
+ ```typescript
166
+ import z from "zod";
167
+ import { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from "@/lib/constants";
168
+
169
+ export const RESOURCE_ORDERABLE_COLUMNS = [
170
+ "title",
171
+ "createdAt",
172
+ // ...
173
+ ] as const;
174
+
175
+ export const createResourceSchema = () =>
176
+ z.object({
177
+ title: z.string().min(1),
178
+ categoryId: z.string().uuid(),
179
+ // ...
180
+ });
181
+
182
+ export type CreateResourceSchema = z.infer<
183
+ ReturnType<typeof createResourceSchema>
184
+ >;
185
+
186
+ export const createResourceSchemaClient = () =>
187
+ createResourceSchema().extend({
188
+ file: z.instanceof(File).optional(),
189
+ });
190
+
191
+ export type CreateResourceSchemaClient = z.infer<
192
+ ReturnType<typeof createResourceSchemaClient>
193
+ >;
194
+
195
+ export const getResourcesSchema = () =>
196
+ z.object({
197
+ page: z.coerce.number().min(1).default(1),
198
+ limit: z.coerce
199
+ .number()
200
+ .min(1)
201
+ .max(MAX_PAGE_SIZE)
202
+ .default(DEFAULT_PAGE_SIZE),
203
+ search: z.string().optional(),
204
+ orderByColumn: z.enum(RESOURCE_ORDERABLE_COLUMNS).optional(),
205
+ orderBy: z.enum(["asc", "desc"]).optional(),
206
+ });
207
+
208
+ export type GetResourcesSchema = z.infer<ReturnType<typeof getResourcesSchema>>;
209
+ ```
210
+
211
+ **Rules**:
212
+
213
+ - Use factory pattern: `export const createResourceSchema = () => z.object({...})`
214
+ - Use type inference: `export type CreateResourceSchema = z.infer<ReturnType<typeof createResourceSchema>>`
215
+ - Separate client and server schemas (client may include File types)
216
+ - Define orderable columns as const array
217
+ - Use `z.coerce` for query params that need type conversion
218
+ - Use transformations for date strings: `.transform((value) => value ? new Date(value).toISOString().split('T')[0] : undefined)`
219
+
220
+ #### Page Components (`src/app/[locale]/dashboard/`)
221
+
222
+ **Structure**:
223
+
224
+ ```typescript
225
+ "use client";
226
+
227
+ import { useSetBreadcrumbs } from "@/components/dashboard/DashboardLayout";
228
+ import { BaseTable, useBaseTable } from "@/components/ui/BaseTable";
229
+ import { Button } from "@/components/ui/Button";
230
+ import { useQsHydratedState } from "@/hooks/use-qs-hydrated-state";
231
+ import { DEFAULT_PAGE_SIZE } from "@/lib/constants";
232
+ import { paths } from "@/lib/constants/paths";
233
+ import { useGetResourcesQuery } from "@/lib/services/resource";
234
+ import { useTranslation } from "react-i18next";
235
+ import { ColumnDef } from "@tanstack/react-table";
236
+ import { motion } from "framer-motion";
237
+ ```
238
+
239
+ **Design Guidelines**:
240
+
241
+ - Use Framer Motion for page-level animations (see [Design System](../design/design-system.md))
242
+ - Implement staggered entrance animations for lists/grids
243
+ - Add hover effects to interactive cards following the design system patterns
244
+ - Use semantic gradient colors for action buttons (emerald/sky for updates, rose/pink for deletes)
245
+
246
+ const ResourcesPage = () => {
247
+ const { t, i18n: { language } } = useTranslation();
248
+
249
+ const [filters, setFilters] = useQsHydratedState(getResourcesSchema, {
250
+ defaultValue: {
251
+ page: 1,
252
+ limit: DEFAULT_PAGE_SIZE,
253
+ orderBy: 'desc',
254
+ orderByColumn: 'createdAt',
255
+ },
256
+ });
257
+
258
+ const queryResult = useGetResourcesQuery(filters);
259
+
260
+ useSetBreadcrumbs([
261
+ { label: t('Navigation.dashboard'), href: paths.dashboard.index },
262
+ { label: t('Navigation.Resources'), href: paths.dashboard.resources },
263
+ ]);
264
+
265
+ // #region table config
266
+ const columns: ColumnDef<Resource>[] = useMemo(
267
+ () => [
268
+ // Column definitions
269
+ ],
270
+ [dependencies],
271
+ );
272
+ //#endregion
273
+
274
+ const table = useBaseTable({
275
+ data: queryResult.data?.data?.data || [],
276
+ columns,
277
+ // ... other config
278
+ });
279
+
280
+ return (
281
+
282
+ <div className="w-full">
283
+ {/_ Component JSX _/}
284
+ </div>
285
+ );
286
+ };
287
+
288
+ export default ResourcesPage;
289
+
290
+ ````
291
+
292
+ **Rules**:
293
+ - Always use `'use client'` directive
294
+ - Use `useTranslation` from `react-i18next`
295
+ - Use `useQsHydratedState` for URL query state management
296
+ - Use `useSetBreadcrumbs` for breadcrumb navigation
297
+ - Use `useMemo` for column definitions
298
+ - Use `#region` comments for table configuration
299
+ - Always handle loading states
300
+ - Use `BaseTable` component for tables
301
+ - Use `Pagination` component for pagination
302
+
303
+ #### Sheet Components (`_components/`)
304
+
305
+ **Structure**:
306
+ ```typescript
307
+ 'use client';
308
+
309
+ import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/Sheet';
310
+ import { useCreateResourceMutation } from '@/lib/services/resource';
311
+ import { StorageService } from '@/lib/services/storage';
312
+ import { queryClient } from '@/lib/utils/query-client';
313
+ import { useState } from 'react';
314
+ import { useTranslation } from 'react-i18next';
315
+ import { toast } from 'sonner';
316
+
317
+ export const CreateResourceSheet: React.FC<React.PropsWithChildren> = ({
318
+ children,
319
+ }) => {
320
+ const { t } = useTranslation();
321
+ const { session } = useAuthStore();
322
+
323
+ const [isSheetOpen, setSheetOpen] = useState(false);
324
+ const [isLoading, setIsLoading] = useState(false);
325
+
326
+ const createResourceMutation = useCreateResourceMutation();
327
+
328
+ const onSubmit = async (data: CreateResourceSchemaClient) => {
329
+ try {
330
+ setIsLoading(true);
331
+
332
+ // File upload logic if needed
333
+ let fileUrl: string | undefined;
334
+ if (data.file) {
335
+ const fileName = `${session!.user.id}/resource-${Date.now()}-${createSafeURLForUploadingFileName(data.file.name)}`;
336
+ toast.loading(t('ResourcesPage.uploadingFile'));
337
+
338
+ const { error, uploadResult } = await StorageService.uploadFileSigned(
339
+ Bucket.RESOURCES,
340
+ fileName,
341
+ data.file,
342
+ );
343
+
344
+ if (error || !uploadResult) {
345
+ throw new Error(error.message);
346
+ }
347
+
348
+ fileUrl = uploadResult.path;
349
+ }
350
+
351
+ await createResourceMutation.mutateAsync({
352
+ ...data,
353
+ fileUrl,
354
+ });
355
+
356
+ onOpenChange(false);
357
+ setIsLoading(false);
358
+
359
+ queryClient.invalidateQueries({
360
+ queryKey: [resourceRoutes.resources()],
361
+ });
362
+ } catch (error) {
363
+ console.error('🚀 ~ onSubmit ~ error:', error);
364
+ setIsLoading(false);
365
+ }
366
+ };
367
+
368
+ return (
369
+ <Sheet open={isSheetOpen} onOpenChange={setSheetOpen}>
370
+ <SheetTrigger asChild>{children}</SheetTrigger>
371
+ {isSheetOpen && (
372
+ <SheetContent>
373
+ <SheetHeader>
374
+ <SheetTitle>{t('ResourcesPage.createResource')}</SheetTitle>
375
+ </SheetHeader>
376
+ <ResourceForm onSubmit={onSubmit} isLoading={isLoading} />
377
+ </SheetContent>
378
+ )}
379
+ </Sheet>
380
+ );
381
+ };
382
+ ````
383
+
384
+ **Rules**:
385
+
386
+ - Use `Sheet` component from `@/components/ui/Sheet`
387
+ - Handle file uploads using `StorageService.uploadFileSigned`
388
+ - Use `toast` from `sonner` for notifications
389
+ - Invalidate queries after mutations
390
+ - Always handle loading states
391
+ - Use `console.error` with emoji prefix for error logging: `console.error('🚀 ~ onSubmit ~ error:', error)`
392
+ - Clear query strings on close if needed
393
+
394
+ ### 2. Naming Conventions
395
+
396
+ **Files**:
397
+
398
+ - API routes: `route.ts` (in `src/app/api/[resource]/`)
399
+ - Services: `[resource].ts` (in `src/lib/services/`)
400
+ - Schemas: `[action]-[resource]-schema.ts` (e.g., `create-income-schema.ts`)
401
+ - Pages: `page.tsx` (in `src/app/[locale]/dashboard/[resource]/`)
402
+ - Components: `[ComponentName].tsx` (PascalCase)
403
+ - Hooks: `use-[hook-name].ts` (kebab-case)
404
+
405
+ **Functions**:
406
+
407
+ - API handlers: `getResource`, `createResource`, `updateResource`, `deleteResource`
408
+ - Service functions: `getResource`, `createResource`, etc.
409
+ - React Query hooks: `useGetResourceQuery`, `useCreateResourceMutation`
410
+ - Query keys: `getResourceQueryKey`
411
+
412
+ **Variables**:
413
+
414
+ - Use camelCase: `isLoading`, `queryResult`, `setFilters`
415
+ - Boolean prefixes: `is`, `has`, `should` (e.g., `isLoading`, `hasError`)
416
+ - Constants: UPPER_SNAKE_CASE (e.g., `DEFAULT_PAGE_SIZE`)
417
+
418
+ **Types**:
419
+
420
+ - Use PascalCase: `GetResourceResponse`, `CreateResourceSchema`
421
+ - Suffix with type: `Resource`, `ResourceSchema`, `ResourceResponse`
422
+
423
+ ### 3. TypeScript Patterns
424
+
425
+ **Always**:
426
+
427
+ - Use strict TypeScript
428
+ - Define types explicitly, avoid `any`
429
+ - Use type inference where appropriate
430
+ - Use `as const` for literal types
431
+ - Use `ReturnType<typeof function>` for function return types
432
+ - Use `z.infer` for Zod schema types
433
+
434
+ **Type Definitions**:
435
+
436
+ ```typescript
437
+ // In API routes
438
+ export type Resource = {
439
+ id: string;
440
+ title: string;
441
+ // ...
442
+ };
443
+
444
+ export type GetResourceResponse = TSuccessResponse<{
445
+ totalItemsCount: number;
446
+ data: Resource[];
447
+ }>;
448
+
449
+ // In services
450
+ import { GetResourceResponse } from "@/app/api/resources/route";
451
+ ```
452
+
453
+ ### 4. Database Patterns
454
+
455
+ **Always**:
456
+
457
+ - Use Drizzle ORM
458
+ - Include soft delete check: `eq(table.isDeleted, false)`
459
+ - Use `db.query` for relations when possible
460
+ - Use `db.select().from()` for complex queries
461
+ - Use `and()` for multiple conditions
462
+ - Use `sql` template for complex SQL
463
+
464
+ **Example**:
465
+
466
+ ```typescript
467
+ const where = and(
468
+ eq(resources.isDeleted, false),
469
+ search?.trim().length
470
+ ? sql`LOWER(${resources.title}) LIKE LOWER(${`%${search.trim()}%`})`
471
+ : undefined,
472
+ categoryId ? eq(resources.categoryId, categoryId) : undefined,
473
+ );
474
+ ```
475
+
476
+ ### 5. Error Handling
477
+
478
+ **API Routes**:
479
+
480
+ ```typescript
481
+ if (!result) {
482
+ throw new NotFoundError(i18next.t("ApiRoutes.Utils.dataNotFound"));
483
+ }
484
+
485
+ if (count === 0) {
486
+ throw new NotFoundError(i18next.t("ApiRoutes.Utils.dataNotFound"));
487
+ }
488
+ ```
489
+
490
+ **Components**:
491
+
492
+ ```typescript
493
+ try {
494
+ // Operation
495
+ } catch (error) {
496
+ console.error("🚀 ~ operation ~ error:", error);
497
+ // Handle error
498
+ }
499
+ ```
500
+
501
+ **Error Types**:
502
+
503
+ - `BadRequestError` - 400 errors
504
+ - `NotFoundError` - 404 errors
505
+ - Use i18next for error messages
506
+
507
+ ### 6. Internationalization (i18n)
508
+
509
+ **Always**:
510
+
511
+ - Use `useTranslation` hook in components
512
+ - Use `i18next.t()` in API routes
513
+ - Use translation keys from `src/messages/`
514
+ - Never hardcode user-facing strings
515
+
516
+ **Example**:
517
+
518
+ ```typescript
519
+ // In components
520
+ const { t } = useTranslation();
521
+ <Button>{t('Navigation.AddResource')}</Button>
522
+
523
+ // In API routes
524
+ import i18next from 'i18next';
525
+ throw new NotFoundError(i18next.t('ApiRoutes.Utils.dataNotFound'));
526
+ ```
527
+
528
+ ### 7. React Query Patterns
529
+
530
+ **Query Keys**:
531
+
532
+ ```typescript
533
+ export const getResourcesQueryKey = (data: GetResourcesSchema) => [
534
+ resourceRoutes.resources(),
535
+ data.page,
536
+ data.limit,
537
+ data.search,
538
+ // ... all relevant params
539
+ ];
540
+ ```
541
+
542
+ **Invalidation**:
543
+
544
+ ```typescript
545
+ queryClient.invalidateQueries({
546
+ queryKey: [resourceRoutes.resources()],
547
+ });
548
+ ```
549
+
550
+ **Mutations**:
551
+
552
+ ```typescript
553
+ export const useCreateResourceMutation = () =>
554
+ useMutation({
555
+ mutationFn: createResource,
556
+ });
557
+ ```
558
+
559
+ ### 8. Code Organization
560
+
561
+ **Imports Order**:
562
+
563
+ 1. External libraries (React, Next.js, etc.)
564
+ 2. Internal components (`@/components/`)
565
+ 3. Internal utilities (`@/lib/utils/`)
566
+ 4. Internal services (`@/lib/services/`)
567
+ 5. Internal schemas (`@/lib/schemas/`)
568
+ 6. Internal types (`@/app/api/`)
569
+ 7. Server-side imports (`@/server/`)
570
+
571
+ **Grouping**:
572
+
573
+ - Use `#region` comments for logical grouping
574
+ - Group related functions together
575
+ - Keep related types near their usage
576
+
577
+ ### 9. Comments and Documentation
578
+
579
+ **Comments**:
580
+
581
+ - Use `//` for single-line comments
582
+ - Use `/* */` for multi-line comments
583
+ - Use `#region` / `#endregion` for code sections
584
+ - Explain "why" not "what"
585
+ - Use English for all comments
586
+
587
+ **Example**:
588
+
589
+ ```typescript
590
+ // Determine if we need join-based query for sorting
591
+ const needsJoinForSorting =
592
+ orderByColumn && ["accountTitle", "paymentStatus"].includes(orderByColumn);
593
+
594
+ // #region table config
595
+ const columns: ColumnDef<Resource>[] = useMemo(/* ... */);
596
+ //#endregion
597
+ ```
598
+
599
+ ### 10. Testing Considerations
600
+
601
+ **When Writing Code**:
602
+
603
+ - Make functions testable (pure functions where possible)
604
+ - Avoid side effects in utility functions
605
+ - Use dependency injection for services
606
+ - Keep components focused and small
607
+
608
+ **Type Checking**:
609
+
610
+ - **Always run `npm run format:fix && npm run typecheck` at the end of code changes**
611
+ - Ensure there are no TypeScript type errors before completing the task
612
+ - Fix any type errors that are discovered
613
+ - Type checking is mandatory and must pass before considering code complete
614
+
615
+ ### 11. Performance Best Practices
616
+
617
+ **Always**:
618
+
619
+ - Use `useMemo` for expensive computations
620
+ - Use `useCallback` for event handlers passed to children
621
+ - Use `React.memo` for expensive components (when needed)
622
+ - Optimize database queries (use indexes, avoid N+1)
623
+ - Use pagination for large datasets
624
+ - Use `Promise.all` for parallel operations
625
+
626
+ **Example**:
627
+
628
+ ```typescript
629
+ const [countResult, data] = await Promise.all([
630
+ db
631
+ .select({ count: sql<number>`COUNT(*)::INTEGER` })
632
+ .from(resources)
633
+ .where(where),
634
+ db.query.resources.findMany({ where, limit, offset }),
635
+ ]);
636
+ ```
637
+
638
+ ### 12. Security Best Practices
639
+
640
+ **Always**:
641
+
642
+ - Validate all inputs using Zod schemas
643
+ - Use `ProtectedRequestContext` for protected routes
644
+ - Never trust client-side data
645
+ - Use parameterized queries (Drizzle handles this)
646
+ - Check permissions before operations
647
+
648
+ ### 13. Common Patterns
649
+
650
+ #### Soft Delete Pattern
651
+
652
+ ```typescript
653
+ await db
654
+ .update(resources)
655
+ .set({ isDeleted: true })
656
+ .where(and(eq(resources.id, id), eq(resources.isDeleted, false)));
657
+ ```
658
+
659
+ #### File Upload Pattern
660
+
661
+ ```typescript
662
+ if (file) {
663
+ const fileName = `${session!.user.id}/resource-${Date.now()}-${createSafeURLForUploadingFileName(file.name)}`;
664
+ const { error, uploadResult } = await StorageService.uploadFileSigned(
665
+ Bucket.RESOURCES,
666
+ fileName,
667
+ file,
668
+ );
669
+ if (error || !uploadResult) {
670
+ throw new Error(error.message);
671
+ }
672
+ fileUrl = uploadResult.path;
673
+ }
674
+ ```
675
+
676
+ #### Date Handling Pattern
677
+
678
+ ```typescript
679
+ // In schemas
680
+ startDate: z
681
+ .string()
682
+ .optional()
683
+ .transform((value) =>
684
+ value ? new Date(value).toISOString().split('T')[0] : undefined,
685
+ ),
686
+
687
+ // In API routes
688
+ date: new Date(ctx.payload.date),
689
+ createdAt: result.createdAt.toISOString(),
690
+ ```
691
+
692
+ #### Sorting Pattern
693
+
694
+ ```typescript
695
+ const needsJoinForSorting =
696
+ orderByColumn && ["accountTitle", "paymentStatus"].includes(orderByColumn);
697
+
698
+ if (needsJoinForSorting) {
699
+ // Use join-based sorting
700
+ } else {
701
+ // Use direct column sorting
702
+ }
703
+ ```
704
+
705
+ ## Code Review Checklist
706
+
707
+ When reviewing or writing code, ensure:
708
+
709
+ - [ ] Soft delete checks are included (`isDeleted: false`)
710
+ - [ ] Types are properly defined (no `any`)
711
+ - [ ] i18next is used for all user-facing strings
712
+ - [ ] Error handling is implemented
713
+ - [ ] Loading states are handled
714
+ - [ ] React Query patterns are followed
715
+ - [ ] File organization matches project structure
716
+ - [ ] Naming conventions are followed
717
+ - [ ] Comments explain "why" not "what"
718
+ - [ ] Code is properly formatted
719
+ - [ ] Imports are organized correctly
720
+ - [ ] `#region` comments are used for logical grouping
721
+ - [ ] **Type checking passes: `npm run typecheck` runs without errors**
722
+ - [ ] UI components follow [Design System](../design/design-system.md) patterns
723
+ - [ ] Animations use established Framer Motion variants
724
+ - [ ] Hover effects are consistent with design system guidelines
725
+
726
+ ## Common Mistakes to Avoid
727
+
728
+ 1. **Missing Soft Delete Check**: Always include `eq(table.isDeleted, false)`
729
+ 2. **Hardcoded Strings**: Always use i18next for user-facing strings
730
+ 3. **Using `any` Type**: Always define proper types
731
+ 4. **Missing Error Handling**: Always handle errors properly
732
+ 5. **Missing Loading States**: Always show loading indicators
733
+ 6. **N+1 Queries**: Use `db.query` with relations instead of multiple queries
734
+ 7. **Missing Query Invalidation**: Always invalidate queries after mutations
735
+ 8. **Incorrect Import Paths**: Use `@/` alias for internal imports
736
+ 9. **Missing Type Exports**: Export types from API routes for use in services
737
+
738
+ ## Examples
739
+
740
+ ### Complete API Route Example
741
+
742
+ See: `src/app/api/incomes/route.ts`
743
+
744
+ ### Complete Service Example
745
+
746
+ See: `src/lib/services/income.ts`
747
+
748
+ ### Complete Schema Example
749
+
750
+ See: `src/lib/schemas/income/create-income-schema.ts`
751
+
752
+ ### Complete Page Component Example
753
+
754
+ See: `src/app/[locale]/dashboard/incomes/page.tsx`
755
+
756
+ ### Complete Sheet Component Example
757
+
758
+ See: `src/app/[locale]/dashboard/incomes/_components/CreateIncomeSheet.tsx`
759
+
760
+ ## Working with the Codebase
761
+
762
+ ### When Adding a New Feature
763
+
764
+ 1. Create schema files in `src/lib/schemas/[resource]/`
765
+ 2. Create API route in `src/app/api/[resource]/route.ts`
766
+ 3. Create service file in `src/lib/services/[resource].ts`
767
+ 4. Create page component in `src/app/[locale]/dashboard/[resource]/page.tsx`
768
+ 5. Create form components in `_components/` directory
769
+ 6. Add translation keys to `src/messages/`
770
+ 7. **Run `npm run typecheck` to verify there are no type errors**
771
+
772
+ ### When Refactoring
773
+
774
+ 1. Maintain existing patterns
775
+ 2. Don't change working code unnecessarily
776
+ 3. Update types if structure changes
777
+ 4. Update related components
778
+ 5. Test thoroughly
779
+ 6. **Run `npm run typecheck` to verify there are no type errors**
780
+
781
+ ### When Fixing Bugs
782
+
783
+ 1. Identify the root cause
784
+ 2. Fix the issue following project patterns
785
+ 3. Add error handling if missing
786
+ 4. Add tests if possible
787
+ 5. Update related code if needed
788
+ 6. **Run `npm run typecheck` to verify there are no type errors**
789
+
790
+ ## Agent Instructions
791
+
792
+ When working as the Developer Agent:
793
+
794
+ 1. **Always follow project patterns** - Refer to existing code examples
795
+ 2. **Maintain type safety** - Never use `any`, always define proper types
796
+ 3. **Test your code** - Run `npm run typecheck` at the end of every code change
797
+ 4. **Verify type checking** - Ensure `npm run typecheck` passes without errors before completing tasks
798
+ 5. **Follow naming conventions** - Use established patterns for files, functions, and variables
799
+ 6. **Use i18next** - Never hardcode user-facing strings
800
+ 7. **Handle errors properly** - Always implement error handling
801
+ 8. **Update related code** - When changing types or structures, update all related files
802
+ 9. **Document your changes** - Use comments to explain "why" not "what"
803
+ 10. **Follow design system** - Refer to [Design System](../design/design-system.md) for UI patterns, animations, and visual guidelines
804
+ 11. **Implement consistent animations** - Use Framer Motion variants from the design system for all animations
805
+
806
+ **Critical**: Type checking with `npm run typecheck` is mandatory and must pass before any code changes are considered complete.
807
+
808
+ ## Conclusion
809
+
810
+ The Developer Agent must follow these conventions strictly to maintain code consistency and quality. When in doubt, refer to existing code examples in the codebase, particularly in the `incomes` feature which serves as a reference implementation.
811
+
812
+ **Remember**: Always run `npm run typecheck` at the end of code changes to ensure there are no type errors.
813
+
814
+ ---
815
+
816
+ **Document Version**: 1.0
817
+ **Last Updated**: 2026-01-17
818
+ **Language**: English (as per agent documentation standards)