@matteoaliano/forest-ui 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/theme.mjs CHANGED
@@ -1,3 +1,3 @@
1
- export { alkemyPlusPreset, alpha, avatarColors, bg, border, breadcrumbColors, buildTheme, buildThemeOptions, buttonColors, chartColors, colors, components, container, display, fg, focusRings, fontFamily, fontSize, fontWeight, forestPreset, forestTheme, forestThemeOptions, getAvailablePresets, getPreset, iconColors, lineHeight, navColors, palette, radius, registerPreset, shadows2 as shadows, sliderColors, spacing, text, toggleColors, typography, widths } from './chunk-QF5T6J4D.mjs';
1
+ export { alkemyPlusPreset, alpha, avatarColors, bg, border, breadcrumbColors, buildTheme, buildThemeOptions, buttonColors, chartColors, colors, components, container, display, fg, focusRings, fontFamily, fontSize, fontWeight, forestPreset, forestTheme, forestThemeOptions, getAvailablePresets, getPreset, iconColors, lineHeight, navColors, palette, radius, registerPreset, shadows2 as shadows, sliderColors, spacing, text, toggleColors, typography, widths } from './chunk-6W3RIXXY.mjs';
2
2
  //# sourceMappingURL=theme.mjs.map
3
3
  //# sourceMappingURL=theme.mjs.map
@@ -0,0 +1,90 @@
1
+ # FastAPI API Project: Requirements & Best Practices
2
+
3
+ > **forest-ui v0.2.11**
4
+
5
+ > **This file is synced by the `forest-ui` package.**
6
+ > Run `npx forest-ui sync` to update it.
7
+
8
+ ---
9
+
10
+ **Stack:** FastAPI (with dependency injection), Python >=3.9 (via Poetry), PostgreSQL/SQL Server, Redis cache, OpenTelemetry, on-prem Kubernetes. Frontend on Vercel, authentication via Clerk, CI/CD with GitHub Actions, Docker images in Azure Container Registry (ACR) deployed to the cluster.
11
+
12
+ FastAPI is a modern Python web framework built on Starlette and Pydantic. It offers an intuitive dependency-injection system for shared components like DB sessions or auth. Pydantic models automatically validate and parse request data. Organize code into an `app` Python package (with `app/main.py`, sub-packages for routers and a `dependencies.py`) so that imports work cleanly. Use **APIRouters** to group related endpoints and share tags/dependencies. Declare shared logic (auth checks, DB, etc.) as FastAPI dependencies (`Depends(...)`) in `app/dependencies.py` for reuse. Keep path operations concise by leveraging DI: for example, inject database sessions or authorization checks into endpoints rather than repeating code.
13
+
14
+ ## Environment & Packaging (Poetry)
15
+
16
+ - **Python & Poetry:** Use Python 3.9+. Manage dependencies with [Poetry](https://python-poetry.org) and define metadata in `pyproject.toml` (PEP 621). Poetry creates isolated virtualenvs and a lockfile for reproducible installs.
17
+ - **Dependency Best Practices:** Initialize with `poetry init` to generate `pyproject.toml`. Add packages with `poetry add <pkg>` so they're recorded in both `pyproject.toml` and `poetry.lock`. Separate dev dependencies (e.g. pytest, linters) using `poetry add --dev`. Commit `poetry.lock` to source control to ensure all installs use exact versions. Regularly run `poetry update` and test to keep dependencies current. Use multi-stage Docker builds to minimize image size (install only production deps).
18
+ - **Project Layout:** Follow a logical package structure: e.g.
19
+ ```
20
+ app/
21
+ __init__.py
22
+ main.py # app startup
23
+ dependencies.py # shared Depends (DB sessions, auth checks, etc.)
24
+ routers/ # API route modules
25
+ __init__.py
26
+ items.py
27
+ users.py
28
+ models/ # SQLModel/Pydantic models
29
+ services/ # business logic if needed
30
+ ```
31
+ Keep code organized into modules; use semantic imports like `from app.routers import items`. Use `Annotated` dependencies where possible for clarity (e.g. `session: Session = Depends(get_session)`).
32
+
33
+ ## Databases (PostgreSQL, SQL Server)
34
+
35
+ - **SQL Databases:** FastAPI works with any SQL DB via SQLAlchemy/SQLModel. For example, [SQLModel](https://github.com/tiangolo/sqlmodel) (built on SQLAlchemy and Pydantic) can connect to PostgreSQL or SQL Server (via `pyodbc` or `pymssql`). In development you might use SQLite for simplicity, but **production** should use a dedicated DB server (e.g. PostgreSQL).
36
+ - **Connection Handling:** Use one DB **session/connection per request** via a FastAPI dependency (`yield session` pattern). Configure SQLAlchemy connection pools to match workload (avoid re-creating engine per query). Use environment variables (or Kubernetes Secrets) for DB URLs/credentials. Use alembic or similar for migrations, rather than auto-creating tables in prod. Ensure proper indexes and foreign keys in schema.
37
+ - **Security:** Never embed credentials in code. Use TLS to connect to the DB if supported. Sanitize inputs (Pydantic prevents SQL injection by type-checking and requiring parameters).
38
+
39
+ ## Caching (Redis)
40
+
41
+ - **Redis Usage:** Use Redis for caching or session data. Access via a Redis client (e.g. [redis-py](https://pypi.org/project/redis/) or `aioredis` for async). Store only non-sensitive, expirable data with appropriate TTLs. Abstract Redis access behind a service layer or dependency.
42
+ - **Configuration:** Run Redis in a secured network (not public-facing). Require strong passwords and/or disable the default user. Enable TLS if possible to encrypt in-flight cache traffic. Set memory limits and eviction policies. Monitor usage and consider using Redis clusters for high availability.
43
+ - **Best Practices:** Use Redis only as a cache; do not rely on it for permanent storage unless using Redis persistence properly. Use mature caching patterns (e.g. cache-aside). Flush or handle stale caches on deploy as needed.
44
+
45
+ ## Observability (OpenTelemetry)
46
+
47
+ - **Instrumentation:** Use [OpenTelemetry for Python](https://opentelemetry.io/docs/languages/python/) to collect traces and metrics. The Python SDK supports Python 3.9+. Install via pip: `pip install opentelemetry-api opentelemetry-sdk` and any needed instrumentations/exporters.
48
+ - **Tracing & Metrics:** Auto-instrument FastAPI (there are middleware or instrumentation libs for ASGI frameworks) to trace HTTP requests. Instrument database calls (SQLAlchemy) and Redis calls. Export telemetry using OTLP or a vendor (Jaeger, Zipkin, Prometheus). Use trace data to diagnose latency; use metrics (like request rate, DB latency) to monitor health.
49
+ - **Deployment:** Ensure an OpenTelemetry Collector or compatible backend is running to receive data. Tag telemetry with the service name and environment. Use semantic conventions for naming.
50
+
51
+ ## Frontend (Vercel) & Authentication (Clerk)
52
+
53
+ - **Vercel Deployment:** Host the frontend on Vercel (typically a Next.js or static SPA). Configure environment variables in Vercel for the API base URL. Use custom domains and automatic HTTPS. Restrict API CORS to the frontend domain using FastAPI's `CORSMiddleware` so only your front-end origin can access endpoints.
54
+ - **Clerk Authentication:** Use [Clerk](https://clerk.com) to handle user signup/sign-in and sessions. Clerk provides UI components (for React/Next) and issues JWT tokens for authenticated users. In the FastAPI backend, verify these JWTs on each request. For example, use the [fastapi-clerk-auth](https://pypi.org/project/fastapi-clerk-auth/) middleware to automatically validate Clerk JWTs via Clerk's JWKS. This cleanly integrates with FastAPI's DI: endpoints requiring auth simply depend on the token guard.
55
+ - **Auth Best Practices:** Enforce HTTPS so tokens can't be stolen in transit. Use Clerk's features (MFA, password policies, session limits) to harden accounts. Never expose backend secrets (like Clerk API keys) to the frontend. Use short-lived JWTs or session tokens.
56
+
57
+ ## Security Considerations
58
+
59
+ - **Transport & API Security:** Serve all traffic over HTTPS (TLS). Validate all inputs using Pydantic models to prevent injection or malformed data. Implement CORS rules to only allow trusted origins. Use FastAPI's security dependencies (e.g. `OAuth2PasswordBearer`, HTTP Bearer) to enforce auth on endpoints. Consider rate-limiting and IP blocking for brute-force protection.
60
+ - **Kubernetes & Infrastructure:** Secure the on-prem cluster using Kubernetes best practices. Ensure the API server and etcd have TLS in-transit and (if needed) at-rest encryption. Use Role-Based Access Control (RBAC) to limit cluster operations. Enforce Pod Security Standards: run containers as non-root, use read-only filesystems, drop Linux capabilities. Define NetworkPolicies so Pods can only talk to required services (e.g. API Pod talks to DB/Redis, but not to other namespaces). Use secrets or a vault for all credentials (K8s Secrets should be encrypted at rest by enabling encryption). Audit and log all access (enable Kubernetes audit logs). Keep nodes patched and minimize host privileges.
61
+ - **Container Image Security:** Scan images for vulnerabilities before deployment. Use minimal base images (e.g. Alpine or slim variants) to reduce attack surface. Do not run the application as root inside the container.
62
+ - **Redis Security:** Only allow Redis access from internal service accounts. Use Redis AUTH and TLS. Restrict Redis CLI or admin interfaces.
63
+ - **Clerk/Authentication:** Rely on standard protocols. Verify the `iat` and `exp` claims in JWTs to prevent replay. Synchronize clocks or add leeway if needed. Restrict token scopes so that clients only have the privileges they need.
64
+ - **Secrets Management:** Store sensitive config (DB passwords, JWT keys) outside code. In Kubernetes, use Secrets and mount them into pods. In GitHub Actions, use encrypted secrets (do NOT hardcode credentials). Consider using OpenID Connect (OIDC) in GitHub Actions to avoid long-lived secrets when deploying to Azure.
65
+ - **Audit & Compliance:** Log all significant events (logins, errors, deployments). Regularly review audit logs. Follow principle of least privilege for all services.
66
+
67
+ ## Deployment & CI/CD Pipeline
68
+
69
+ - **Docker & ACR:** Dockerize the app with a multi-stage `Dockerfile`: install Poetry and build the app, then copy only the `venv/lib/python...` and app code into a smaller final image. Tag images by commit/PR. Push images to Azure Container Registry in the same region as your cluster for low latency. Use a dedicated ACR per environment or namespace. In ACR, enable Azure RBAC: assign a service principal (for CI/CD) push rights and another identity pull rights. Disable the ACR admin user if not needed.
70
+ - **GitHub Actions:** Automate CI/CD with Actions:
71
+ - **CI (on push/PR):** Steps include `actions/checkout`, `actions/setup-python@v3` (choose Python 3.10+), `poetry install` (or `poetry install --no-dev` for quick CI), run linter (flake8/mypy) and tests. Cache the Poetry virtualenv or pip cache to speed up builds. Fail on test or lint errors.
72
+ - **Build & Push (on main):** After CI passes, build the Docker image. Use `azure/login@v1` (or OIDC) to authenticate to Azure using a service principal stored in a GitHub secret. Then use `azure/CLI` or `docker/login-action` and `docker/build-push-action` to push the image to ACR. Tag images by semantic version or commit SHA.
73
+ - **Deploy to K8s:** After pushing, use `azure/k8s-set-context` (or `kubectl` inside `azure/CLI`) to point to the on-prem cluster (this may require a kubeconfig stored securely). Apply updated Kubernetes manifests (using `kubectl apply` or `helm upgrade`). You can use Helm or Kustomize; store manifests alongside code or in a separate repo.
74
+ - **Checks:** Include branch protection so only successful checks (lint/tests) allow merging to main. Use pull request previews (deploy to a test namespace) before production. Use Actions cache for Docker layers and Poetry packages.
75
+
76
+ ## Kubernetes Deployment Patterns
77
+
78
+ - **Manifests:** Define Deployments and Services in YAML. Always create a Service *before* pods that use it, so environment variables get injected correctly. Use DNS service names for inter-service calls. Avoid `hostPort`/`hostNetwork` (it ties pods to nodes); use a NodePort or Ingress for external access. For internal-only services, use ClusterIP or headless Services as needed.
79
+ - **Labels & Configuration:** Use semantic, standardized labels (`app.kubernetes.io/name`, `component`, `tier`, etc.) to identify workloads. Store app config (like DB URLs or feature flags) in ConfigMaps/Secrets and mount them as env vars or files. Keep resource limits/requests set on pods. Use liveness/readiness probes to restart unhealthy pods. Consider HorizontalPodAutoscalers based on CPU/memory or custom metrics (if cluster has VPA/HPA enabled).
80
+ - **Secrets:** Load Kubernetes Secrets (e.g. database credentials, JWT secret) into pods. Optionally use a tool like SealedSecrets or Vault for rotation.
81
+ - **Ingress & Networking:** Expose the API via an Ingress or LoadBalancer with TLS. Ensure the TLS certificate is valid (use internal CA or Let's Encrypt).
82
+ - **Monitoring:** Run a Prometheus/Alertmanager stack (or other monitoring) in the cluster. Configure probes and health endpoints for FastAPI. Forward logs to a central system (ELK/EFK or Grafana Loki). Use OpenTelemetry collector if needed.
83
+
84
+ ## Final Checklist
85
+
86
+ - **Code Quality:** Follow PEP 8 and Pylint/myPy linting. Ensure unit and integration tests cover key logic. Use `@pytest` with the TestClient for endpoint tests.
87
+ - **Dependency Audit:** Before each release, run a security scan on Python packages (e.g. `poetry audit` or `safety`) and on container images. Update vulnerable dependencies promptly.
88
+ - **Review Configuration:** Verify all environment variables and secrets are properly set in production. Check that no debug or verbose logging is enabled.
89
+ - **Performance Checks:** Ensure Redis and database are configured for expected load. Benchmark API endpoints and add indexes or cache hot queries as needed.
90
+ - **Security Review:** Confirm TLS is enforced (no HTTP allowed). Test auth flows (invalid tokens are rejected, access is limited by role). Ensure network policies isolate components.
@@ -0,0 +1,543 @@
1
+ # Forest UI — Development Best Practices
2
+
3
+ > **forest-ui v0.2.11**
4
+
5
+ > **This file is synced by the `forest-ui` package.**
6
+ > Run `npx forest-ui sync` to update it.
7
+
8
+ # Next.js Code Agent - v2.0
9
+
10
+ ## CORE PHILOSOPHY
11
+
12
+ 1. **Server First**: Default Server Components, `'use client'` solo quando necessario
13
+ 2. **Type Everything**: TypeScript strict, zero `any`
14
+ 3. **Single Responsibility**: Ogni file = 1 job, pagine = orchestratori puri
15
+ 4. **Separation of Concerns**: Logica separata da presentazione, data access isolato
16
+ 5. **Explicit > Implicit**: Codice auto-documentante, no magic
17
+
18
+ ---
19
+
20
+ ## 1. ARCHITETTURA & STRUTTURA
21
+
22
+ ### File System Organization
23
+ ```
24
+ /app # App Router (Next.js 13+)
25
+ /(routes)/ # Route groups
26
+ /api/ # API routes
27
+ /[route]/
28
+ page.tsx # Pagina (max 20 righe, solo orchestrazione)
29
+ layout.tsx # Layout condiviso
30
+ loading.tsx # Loading UI
31
+ error.tsx # Error handling
32
+ /components
33
+ /ui/ # Design system base (Button, Card, Input...)
34
+ /features/ # Feature-specific (UserCard, ProductGrid...)
35
+ /lib
36
+ /actions/ # Server Actions (mutations)
37
+ /queries/ # Data fetching (read operations)
38
+ /hooks/ # Custom React hooks
39
+ /utils/ # Pure utility functions
40
+ /services/ # Business logic complessa
41
+ /parsers/ # URL params & form data parsing
42
+ /validations/ # Zod schemas
43
+ /types # TypeScript interfaces/types
44
+ /public # Static assets
45
+ ```
46
+
47
+ ### Naming Conventions
48
+ - **Componenti**: `PascalCase.tsx` (UserCard.tsx)
49
+ - **Hooks**: `use[Name].ts` (useDebounce.ts)
50
+ - **Actions**: `[entity].actions.ts` (user.actions.ts)
51
+ - **Queries**: `[entity].queries.ts` (user.queries.ts)
52
+ - **Utils**: `[entity].util.ts` (format.util.ts)
53
+ - **Parsers**: `[entity].parser.ts` (product.parser.ts)
54
+ - **Services**: `[entity].service.ts` (analytics.service.ts)
55
+
56
+ ---
57
+
58
+ ## 2. SINGLE RESPONSIBILITY - PAGE LEVEL
59
+
60
+ ### Regola d'Oro
61
+ **Una pagina Next.js ha 1 sola responsabilità: "Comporre UI per questa route"**
62
+
63
+ ### Pagina Ideale (Template)
64
+ ```typescript
65
+ // app/products/page.tsx - Max 20 righe
66
+ import { getProducts } from '@/lib/queries/product.queries';
67
+ import { ProductGrid } from '@/components/features/products/ProductGrid';
68
+
69
+ export default async function ProductsPage() {
70
+ const products = await getProducts(); // Delega fetch
71
+ return <ProductGrid products={products} />; // Delega UI
72
+ }
73
+ ```
74
+
75
+ ### ❌ Una pagina NON deve:
76
+ - Costruire query complesse (>5 righe di logic)
77
+ - Fare trasformazioni dati (.map/.filter/.reduce con logica)
78
+ - Validare o parsare parametri inline
79
+ - Gestire errori con try/catch (usa error.tsx)
80
+ - Contenere JSX >50 righe (estrai componenti)
81
+ - Avere calcoli o aggregazioni
82
+ - Gestire state (useState, useReducer)
83
+
84
+ ### ✅ Una pagina deve:
85
+ - Chiamare 1-3 funzioni di data fetching (in parallelo con Promise.all se >1)
86
+ - Comporre componenti feature
87
+ - Passare props ai componenti
88
+ - **Nient'altro**
89
+
90
+ ---
91
+
92
+ ## 3. SEPARATION OF CONCERNS - EXTRACTION PATTERNS
93
+
94
+ ### Data Fetching → lib/queries/
95
+ **Responsabilità:** Read operations, DB access, API calls
96
+ ```typescript
97
+ // lib/queries/product.queries.ts
98
+ 'use server'
99
+
100
+ export async function getProducts(): Promise<Product[]> {
101
+ return await db.product.findMany({
102
+ where: { status: 'active' },
103
+ orderBy: { createdAt: 'desc' }
104
+ });
105
+ }
106
+
107
+ export async function getProductById(id: string): Promise<Product | null> {
108
+ return await db.product.findUnique({ where: { id } });
109
+ }
110
+ ```
111
+
112
+ ### Mutations → lib/actions/
113
+ **Responsabilità:** Create, Update, Delete operations
114
+ ```typescript
115
+ // lib/actions/product.actions.ts
116
+ 'use server'
117
+
118
+ import { revalidatePath } from 'next/cache';
119
+ import { productSchema } from '@/lib/validations/product.schema';
120
+
121
+ export async function createProduct(formData: FormData) {
122
+ const parsed = productSchema.safeParse(Object.fromEntries(formData));
123
+ if (!parsed.success) return { error: parsed.error };
124
+
125
+ const product = await db.product.create({ data: parsed.data });
126
+ revalidatePath('/products');
127
+
128
+ return { success: true, product };
129
+ }
130
+ ```
131
+
132
+ ### URL Parsing → lib/parsers/
133
+ **Responsabilità:** Validare e parsare searchParams, form data
134
+ ```typescript
135
+ // lib/parsers/product.parser.ts
136
+ import { z } from 'zod';
137
+
138
+ const filterSchema = z.object({
139
+ category: z.string().default('all'),
140
+ sort: z.enum(['asc', 'desc']).default('desc'),
141
+ page: z.coerce.number().int().min(1).default(1)
142
+ });
143
+
144
+ export function parseProductFilters(params: Record<string, string | undefined>) {
145
+ return filterSchema.parse(params);
146
+ }
147
+ ```
148
+
149
+ ### Pure Logic → lib/utils/
150
+ **Responsabilità:** Funzioni pure (input → output, no side effects)
151
+ ```typescript
152
+ // lib/utils/product.util.ts
153
+
154
+ export function calculateDiscount(price: number, discountPercent: number): number {
155
+ return price * (1 - discountPercent / 100);
156
+ }
157
+
158
+ export function formatPrice(amount: number): string {
159
+ return new Intl.NumberFormat('it-IT', {
160
+ style: 'currency',
161
+ currency: 'EUR'
162
+ }).format(amount);
163
+ }
164
+
165
+ export function isRecentProduct(createdAt: Date): boolean {
166
+ const daysSinceCreation = (Date.now() - createdAt.getTime()) / (1000 * 60 * 60 * 24);
167
+ return daysSinceCreation <= 30;
168
+ }
169
+ ```
170
+
171
+ ### Complex Business Logic → lib/services/
172
+ **Responsabilità:** Orchestrazione multi-entity, calcoli complessi, aggregazioni
173
+ ```typescript
174
+ // lib/services/analytics.service.ts
175
+ 'use server'
176
+
177
+ import { getOrders } from '@/lib/queries/order.queries';
178
+ import { getProducts } from '@/lib/queries/product.queries';
179
+
180
+ export async function calculateDashboardStats(userId: string) {
181
+ const [orders, products] = await Promise.all([
182
+ getOrders(userId),
183
+ getProducts()
184
+ ]);
185
+
186
+ return {
187
+ totalRevenue: orders.reduce((sum, o) => sum + o.total, 0),
188
+ avgOrderValue: orders.length > 0 ? orders.reduce((sum, o) => sum + o.total, 0) / orders.length : 0,
189
+ topProducts: calculateTopProducts(orders, products),
190
+ conversionRate: calculateConversionRate(orders, products)
191
+ };
192
+ }
193
+ ```
194
+
195
+ ### Client Logic → lib/hooks/
196
+ **Responsabilità:** Stateful logic riutilizzabile, side effects
197
+ ```typescript
198
+ // lib/hooks/useProductFilters.ts
199
+ 'use client'
200
+
201
+ import { useState, useMemo } from 'react';
202
+
203
+ export function useProductFilters(products: Product[]) {
204
+ const [search, setSearch] = useState('');
205
+ const [category, setCategory] = useState<string>('all');
206
+
207
+ const filtered = useMemo(() => {
208
+ return products.filter(p => {
209
+ const matchesSearch = p.name.toLowerCase().includes(search.toLowerCase());
210
+ const matchesCategory = category === 'all' || p.category === category;
211
+ return matchesSearch && matchesCategory;
212
+ });
213
+ }, [products, search, category]);
214
+
215
+ return { filtered, search, setSearch, category, setCategory };
216
+ }
217
+ ```
218
+
219
+ ### Validation → lib/validations/
220
+ **Responsabilità:** Zod schemas, validation rules
221
+ ```typescript
222
+ // lib/validations/product.schema.ts
223
+ import { z } from 'zod';
224
+
225
+ export const productSchema = z.object({
226
+ name: z.string().min(3).max(100),
227
+ price: z.number().positive(),
228
+ category: z.enum(['electronics', 'clothing', 'food']),
229
+ description: z.string().max(500).optional()
230
+ });
231
+
232
+ export type ProductInput = z.infer<typeof productSchema>;
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 4. REFACTORING MODE
238
+
239
+ ### Auto-Trigger Refactoring quando:
240
+ - File pagina >50 righe
241
+ - File componente >150 righe
242
+ - Più di 1 await non in Promise.all
243
+ - Try/catch in pagina (usa error.tsx)
244
+ - Logica trasformazione dati in pagina (.map/.filter con >1 riga)
245
+ - Duplicazione codice (>2 occorrenze stesso pattern)
246
+
247
+ ### Processo Refactoring (3 Fasi)
248
+
249
+ #### FASE 1: AUDIT
250
+ ```markdown
251
+ Analizza file e identifica:
252
+
253
+ 🔴 CRITICAL (Refactoring obbligatorio):
254
+ - [ ] Mixing concerns (fetch + validation + UI stesso file)
255
+ - [ ] Logica business in componenti UI
256
+ - [ ] File >200 righe
257
+ - [ ] Funzioni >50 righe
258
+ - [ ] `any` types presenti
259
+ - [ ] Prop drilling >3 livelli
260
+
261
+ 🟡 WARNINGS (Miglioramento consigliato):
262
+ - [ ] Codice duplicato (>2 occorrenze)
263
+ - [ ] Nomi generici (data, item, temp)
264
+ - [ ] Magic numbers/strings
265
+ - [ ] Nessun error handling
266
+
267
+ Genera report: problemi + metriche + priorità
268
+ ```
269
+
270
+ #### FASE 2: PLAN
271
+ ```markdown
272
+ Proponi struttura target:
273
+
274
+ Before (PROBLEMA):
275
+ ❌ app/products/page.tsx (250 righe)
276
+ ├─ Fetch + trasformazioni
277
+ ├─ Validazione
278
+ ├─ Logica filtri
279
+ └─ UI rendering
280
+
281
+ After (SOLUZIONE):
282
+ ✅ app/products/page.tsx (15 righe) - Orchestrazione
283
+ ✅ lib/queries/product.queries.ts (60 righe) - Data access
284
+ ✅ lib/utils/product.util.ts (30 righe) - Trasformazioni
285
+ ✅ lib/parsers/product.parser.ts (20 righe) - Validation
286
+ ✅ components/features/products/ProductGrid.tsx (80 righe) - UI
287
+ ✅ lib/hooks/useProductFilters.ts (40 righe) - Client logic
288
+ ```
289
+
290
+ #### FASE 3: REFACTOR (Step-by-Step)
291
+ ```markdown
292
+ Implementa in questo ordine:
293
+
294
+ 1. Types & Validation → types/ + validations/
295
+ 2. Pure Utils → lib/utils/
296
+ 3. Parsers → lib/parsers/
297
+ 4. Queries → lib/queries/
298
+ 5. Actions → lib/actions/
299
+ 6. Services → lib/services/ (se necessario)
300
+ 7. Hooks → lib/hooks/ (client logic)
301
+ 8. Components → components/features/
302
+ 9. Page Rebuild → app/[route]/page.tsx (minimalista)
303
+ 10. Error/Loading → error.tsx, loading.tsx
304
+
305
+ Ogni step: commit separato, testabile incrementalmente
306
+ ```
307
+
308
+ ### SRP Compliance Score
309
+ ```
310
+ Score = 100 - penalità
311
+
312
+ Penalità pagine:
313
+ - Righe codice: -1 ogni 10 oltre 20
314
+ - Await multipli: -5 se >1 (non in Promise.all)
315
+ - Nesting depth: -10 ogni livello oltre 2
316
+ - Inline JSX: -2 ogni 10 righe oltre 30
317
+ - Try/catch: -15
318
+ - Transformazioni: -5 per ogni .map/.filter/.reduce
319
+ - Validazioni inline: -10
320
+
321
+ Target: Score ≥ 80
322
+ ```
323
+
324
+ ---
325
+
326
+ ## 5. COMPONENT PATTERNS
327
+
328
+ ### Server Components (Default)
329
+ ```typescript
330
+ // ✅ Server Component - Fetch diretto
331
+ export default async function ProductPage({ params }: { params: { id: string } }) {
332
+ const product = await getProductById(params.id);
333
+ return <ProductDetail product={product} />;
334
+ }
335
+ ```
336
+
337
+ ### Client Components
338
+ ```typescript
339
+ // ✅ Client Component - Solo quando necessario
340
+ 'use client'
341
+
342
+ export function ProductFilters({ onFilterChange }: Props) {
343
+ const [search, setSearch] = useState('');
344
+ // Interattività, hooks, browser APIs
345
+ }
346
+ ```
347
+
348
+ ### Composition Over Configuration
349
+ ```typescript
350
+ // ✅ Preferisci
351
+ <Card>
352
+ <CardHeader>{title}</CardHeader>
353
+ <CardContent>{children}</CardContent>
354
+ </Card>
355
+
356
+ // ❌ Evita props drilling
357
+ <Card title={title} content={content} footer={footer} />
358
+ ```
359
+
360
+ ---
361
+
362
+ ## 6. TYPESCRIPT STRICT
363
+ ```typescript
364
+ // ✅ Type safety completo
365
+ interface UserCardProps {
366
+ user: User;
367
+ onEdit?: (id: string) => Promise<void>;
368
+ }
369
+
370
+ export function UserCard({ user, onEdit }: UserCardProps) {
371
+ // Implementation
372
+ }
373
+
374
+ // ❌ Evita any
375
+ function Component({ data }: { data: any }) { ... }
376
+
377
+ // ✅ Usa unknown + narrowing se tipo incerto
378
+ function processData(data: unknown) {
379
+ if (typeof data === 'object' && data !== null && 'id' in data) {
380
+ // Safe to use data.id
381
+ }
382
+ }
383
+ ```
384
+
385
+ ---
386
+
387
+ ## 7. PERFORMANCE
388
+ ```typescript
389
+ // ✅ Dynamic imports
390
+ const HeavyChart = dynamic(() => import('./HeavyChart'), {
391
+ loading: () => <Skeleton />,
392
+ ssr: false
393
+ });
394
+
395
+ // ✅ Parallel data fetching
396
+ const [products, categories] = await Promise.all([
397
+ getProducts(),
398
+ getCategories()
399
+ ]);
400
+
401
+ // ✅ Image optimization
402
+ import Image from 'next/image';
403
+ <Image src={src} alt={alt} width={500} height={300} />
404
+
405
+ // ❌ Mai
406
+ <img src={src} alt={alt} />
407
+ ```
408
+
409
+ ---
410
+
411
+ ## 8. ERROR HANDLING
412
+ ```typescript
413
+ // ✅ Error boundaries dedicated
414
+ // app/products/error.tsx
415
+ 'use client'
416
+
417
+ export default function Error({ error, reset }: {
418
+ error: Error;
419
+ reset: () => void;
420
+ }) {
421
+ return <ErrorBoundary error={error} onReset={reset} />;
422
+ }
423
+
424
+ // ✅ Safe data access
425
+ const userName = user?.profile?.name ?? 'Guest';
426
+
427
+ // ✅ Server Action error handling
428
+ export async function createUser(formData: FormData) {
429
+ const parsed = userSchema.safeParse(Object.fromEntries(formData));
430
+ if (!parsed.success) {
431
+ return { error: parsed.error.format() };
432
+ }
433
+ // ... resto logica
434
+ }
435
+ ```
436
+
437
+ ---
438
+
439
+ ## 9. OUTPUT STANDARDS
440
+
441
+ Quando generi codice, fornisci sempre:
442
+
443
+ 1. **File Path** completo
444
+ 2. **Imports** ordinati (external → @/ → relative)
445
+ 3. **Types/Interfaces** prima dell'implementazione
446
+ 4. **Implementation** con commenti su logica complessa
447
+ 5. **Usage Example** se non ovvio
448
+ ```typescript
449
+ // File: lib/queries/user.queries.ts
450
+
451
+ import { db } from '@/lib/db';
452
+ import type { User } from '@/types/user.types';
453
+
454
+ /**
455
+ * Recupera utenti attivi con i loro profili
456
+ * @returns Array di utenti con relazioni caricate
457
+ */
458
+ export async function getActiveUsers(): Promise<User[]> {
459
+ return await db.user.findMany({
460
+ where: { status: 'active' },
461
+ include: { profile: true }
462
+ });
463
+ }
464
+ ```
465
+
466
+ ---
467
+
468
+ ## 10. PRE-DELIVERY CHECKLIST
469
+
470
+ Prima di consegnare codice, verifica:
471
+
472
+ **TypeScript:**
473
+ - [ ] Zero errori TS
474
+ - [ ] Zero `any` (usa `unknown` se necessario)
475
+ - [ ] Tutte props/functions tipizzate
476
+
477
+ **Architecture:**
478
+ - [ ] Server Components dove possibile
479
+ - [ ] Pagine <20 righe (solo orchestrazione)
480
+ - [ ] Zero logica business in componenti UI
481
+ - [ ] File <150 righe (split se necessario)
482
+
483
+ **Code Quality:**
484
+ - [ ] Import ordinati (external → @ → relative)
485
+ - [ ] Naming conventions rispettate
486
+ - [ ] Single responsibility rispettata
487
+ - [ ] Zero codice duplicato
488
+ - [ ] Nomi espliciti (no `data`, `temp`, `x`)
489
+
490
+ **Safety:**
491
+ - [ ] Error handling presente
492
+ - [ ] Safe data access (optional chaining)
493
+ - [ ] Input validation (Zod per form/API)
494
+ - [ ] No magic numbers/strings
495
+
496
+ **Performance:**
497
+ - [ ] `next/image` per immagini
498
+ - [ ] Dynamic imports per componenti pesanti
499
+ - [ ] Parallel fetch con Promise.all
500
+
501
+ ---
502
+
503
+ ## CONTEXT LOADING (Per documentazione dettagliata)
504
+
505
+ Se task coinvolge:
506
+ - **Refactoring pagine** → Rileggi questa sezione 3
507
+ - **Separation of concerns** → Rileggi sezione 3 + esempi
508
+ - **Performance optimization** → Focus su sezione 7
509
+ - **Error handling** → Focus su sezione 8
510
+
511
+ ---
512
+
513
+ ## QUICK REFERENCE
514
+ ```typescript
515
+ // ✅ PAGINA IDEALE
516
+ export default async function Page() {
517
+ const data = await getData();
518
+ return <Feature data={data} />;
519
+ }
520
+
521
+ // ✅ SERVER ACTION
522
+ 'use server'
523
+ export async function createItem(formData: FormData) {
524
+ const parsed = schema.safeParse(...);
525
+ if (!parsed.success) return { error: ... };
526
+ const item = await db.create(...);
527
+ revalidatePath('/items');
528
+ return { success: true, item };
529
+ }
530
+
531
+ // ✅ CUSTOM HOOK
532
+ 'use client'
533
+ export function useFilters<T>(items: T[], filterFn: (item: T) => boolean) {
534
+ const [filtered, setFiltered] = useState(items);
535
+ // Logic...
536
+ return { filtered, /* ... */ };
537
+ }
538
+ ```
539
+
540
+ ---
541
+
542
+ **Versione:** 2.0
543
+ **Focus:** SRP + Separation of Concerns + Context Efficiency