These rules enforce enterprise-level type safety, maintainability, and predictable React architecture.
## 1️⃣ Strict tsconfig.json
``` json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"module": "ESNext",
"jsx": "react-jsx",
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true,
"useUnknownInCatchVariables": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"skipLibCheck": false
}
}
```
------------------------------------------------------------------------
## 2️⃣ Never Use `any`
Use `unknown` and narrow types safely.
------------------------------------------------------------------------
## 3️⃣ Always Type Component Props
``` tsx
interface ButtonProps {
label: string;
onClick: () => void;
}
export function Button({ label, onClick }: ButtonProps): JSX.Element {
return <button onClick={onClick}>{label}</button>;
}
```
------------------------------------------------------------------------
## 4️⃣ Always Define Component Return Types
``` tsx
export function Header(): JSX.Element {
return <header>App</header>;
}
```
------------------------------------------------------------------------
## 5️⃣ Do NOT Use `React.FC`
Prefer explicit function components with typed props.
------------------------------------------------------------------------
## 6️⃣ Properly Type useState
``` tsx
interface User {
id: string;
name: string;
}
const [user, setUser] = useState<User | null>(null);
```
------------------------------------------------------------------------
## 7️⃣ Strict Event Typing
``` tsx
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
setValue(e.target.value);
};
```
------------------------------------------------------------------------
## 8️⃣ Use Discriminated Unions for State
``` tsx
type FetchState =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string }
| { status: "error"; error: Error };
```
------------------------------------------------------------------------
## 9️⃣ Never Use Non-Null Assertion (`!`)
Always check for null explicitly.
------------------------------------------------------------------------
## 🔟 Always Type useRef
``` tsx
const inputRef = useRef<HTMLInputElement | null>(null);
```
------------------------------------------------------------------------
## 1️⃣1️⃣ Strict Context Typing
``` tsx
interface AuthContextType {
user: User | null;
login: (email: string) => Promise<void>;
}
```
------------------------------------------------------------------------
## 🏆 Golden Enterprise Rules
- ❌ No `any`
- ❌ No implicit return types
- ❌ No `React.FC`
- ❌ No non-null assertion
- ❌ No unsafe casting
- ✅ Discriminated unions
- ✅ Explicit typing everywhere
- ✅ Strict ESLint + tsconfigNo description provided.
You are an expert Chrome extension developer, proficient in JavaScript/TypeScript, browser extension APIs, and web development. Code Style and Structure - Write clear, modular TypeScript code with proper type definitions - Follow functional programming patterns; avoid classes - Use descriptive variable names (e.g., isLoading, hasPermission) - Structure files logically: popup, background, content scripts, utils - Implement proper error handling and logging - Document code with JSDoc comments Architecture and Best Practices - Strictly follow Manifest V3 specifications - Divide responsibilities between background, content scripts and popup - Configure permissions following the principle of least privilege - Use modern build tools (webpack/vite) for development - Implement proper version control and change management Chrome API Usage - Use chrome.* APIs correctly (storage, tabs, runtime, etc.) - Handle asynchronous operations with Promises - Use Service Worker for background scripts (MV3 requirement) - Implement chrome.alarms for scheduled tasks - Use chrome.action API for browser actions - Handle offline functionality gracefully Security and Privacy - Implement Content Security Policy (CSP) - Handle user data securely - Prevent XSS and injection attacks - Use secure messaging between components - Handle cross-origin requests safely - Implement secure data encryption - Follow web_accessible_resources best practices Performance and Optimization - Minimize resource usage and avoid memory leaks - Optimize background script performance - Implement proper caching mechanisms - Handle asynchronous operations efficiently - Monitor and optimize CPU/memory usage UI and User Experience - Follow Material Design guidelines - Implement responsive popup windows - Provide clear user feedback - Support keyboard navigation - Ensure proper loading states - Add appropriate animations Internationalization - Use chrome.i18n API for translations - Follow _locales structure - Support RTL languages - Handle regional formats Accessibility - Implement ARIA labels - Ensure sufficient color contrast - Support screen readers - Add keyboard shortcuts Testing and Debugging - Use Chrome DevTools effectively - Write unit and integration tests - Test cross-browser compatibility - Monitor performance metrics - Handle error scenarios Publishing and Maintenance - Prepare store listings and screenshots - Write clear privacy policies - Implement update mechanisms - Handle user feedback - Maintain documentation Follow Official Documentation - Refer to Chrome Extension documentation - Stay updated with Manifest V3 changes - Follow Chrome Web Store guidelines - Monitor Chrome platform updates Output Expectations - Provide clear, working code examples - Include necessary error handling - Follow security best practices - Ensure cross-browser compatibility - Write maintainable and scalable code
This guide provides a production-ready architectural pattern for implementing TanStack Query in a React application. It focuses on scalability, type safety, and maintainability.
# The Guide to TanStack Query (React Query) in React + Vite + TypeScript
This guide provides a production-ready architectural pattern for implementing TanStack Query in a React application. It focuses on scalability, type safety, and maintainability.
## 1. Installation & Setup
First, install the core package and the devtools.
```bash
npm install @tanstack/react-query @tanstack/react-query-devtools axios
```
### Global Configuration (`src/main.tsx`)
Wrap your application in `QueryClientProvider`.
```tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import App from './App';
// Create a client
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // Data is fresh for 5 minutes
gcTime: 1000 * 60 * 60, // Garbage collect unused data after 1 hour
retry: 1, // Retry failed requests once
refetchOnWindowFocus: false, // Prevent refetching on window focus (optional)
},
},
});
createRoot(document.getElementById('root')!).render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<App />
{/* DevTools are essential for debugging */}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</StrictMode>
);
```
---
## 2. Recommended Directory Structure
Isolate your data fetching logic from your UI components.
```
src/
├── api/ # Pure Axios/Fetch functions
│ ├── axios-client.ts # configured axios instance
│ └── todos.api.ts # API methods for a specific feature
├── hooks/ # Custom React Query hooks
│ └── queries/ # Group hooks by feature
│ └── useTodos.ts
├── types/ # TypeScript interfaces
│ └── todo.types.ts
└── lib/
└── query-keys.ts # Centralized query keys
```
---
## 3. Query Key Factory Pattern (`src/lib/query-keys.ts`)
**Crucial:** Never hardcode query keys (strings/arrays) directly in your components. Use a factory to maintain consistency.
```typescript
// src/lib/query-keys.ts
export const todoKeys = {
all: ['todos'] as const,
lists: () => [...todoKeys.all, 'list'] as const,
list: (filters: string) => [...todoKeys.lists(), { filters }] as const,
details: () => [...todoKeys.all, 'detail'] as const,
detail: (id: number) => [...todoKeys.details(), id] as const,
};
```
---
## 4. The API Layer (`src/api/*`)
Keep API calls strictly as pure functions returning Promises. They should know nothing about React.
```typescript
// src/api/todos.api.ts
import axios from 'axios';
import { Todo } from '../types/todo.types';
const api = axios.create({ baseURL: 'https://jsonplaceholder.typicode.com' });
export const fetchTodos = async (): Promise<Todo[]> => {
const { data } = await api.get('/todos');
return data;
};
export const fetchTodoById = async (id: number): Promise<Todo> => {
const { data } = await api.get(`/todos/${id}`);
return data;
};
export const createTodo = async (newTodo: Omit<Todo, 'id'>): Promise<Todo> => {
const { data } = await api.post('/todos', newTodo);
return data;
};
```
---
## 5. Custom Hooks (The "Glue" Layer)
Wrap `useQuery` and `useMutation` in custom hooks. This gives you a single place to handle key management, types, and default options.
### Fetching Data (`useQuery`)
```typescript
// src/hooks/queries/useTodos.ts
import { useQuery } from '@tanstack/react-query';
import { todoKeys } from '../../lib/query-keys';
import { fetchTodos, fetchTodoById } from '../../api/todos.api';
export const useTodos = () => {
return useQuery({
queryKey: todoKeys.lists(),
queryFn: fetchTodos,
staleTime: 1000 * 60, // 1 minute specific stale time for this query
});
};
export const useTodo = (id: number) => {
return useQuery({
queryKey: todoKeys.detail(id),
queryFn: () => fetchTodoById(id),
enabled: !!id, // Only run if ID is present
});
};
```
### Mutating Data (`useMutation`)
Always invalidate related queries on success to keep the UI in sync.
```typescript
// src/hooks/queries/useTodos.ts
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { createTodo } from '../../api/todos.api';
import { todoKeys } from '../../lib/query-keys';
export const useCreateTodo = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createTodo,
onSuccess: () => {
// Invalidate the 'lists' query so the new item appears
queryClient.invalidateQueries({ queryKey: todoKeys.lists() });
},
onError: (error) => {
console.error('Failed to create todo:', error);
},
});
};
```
---
## 6. Usage in Components
Components become clean and focused purely on UI logic.
```tsx
// src/components/TodoList.tsx
import { useTodos, useCreateTodo } from '../hooks/queries/useTodos';
export const TodoList = () => {
const { data: todos, isLoading, isError } = useTodos();
const createMutation = useCreateTodo();
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error fetching todos</div>;
const handleCreate = () => {
createMutation.mutate({ title: 'New Task', completed: false, userId: 1 });
};
return (
<div>
<button onClick={handleCreate} disabled={createMutation.isPending}>
{createMutation.isPending ? 'Adding...' : 'Add Todo'}
</button>
<ul>
{todos?.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
);
};
```
---
## 7. Advanced Patterns
### Optimistic Updates
Update the UI _immediately_ before the server responds.
```typescript
export const useUpdateTodo = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateTodoApi,
onMutate: async (newTodo) => {
// 1. Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: todoKeys.detail(newTodo.id) });
// 2. Snapshot previous value
const previousTodo = queryClient.getQueryData(todoKeys.detail(newTodo.id));
// 3. Optimistically update
queryClient.setQueryData(todoKeys.detail(newTodo.id), (old: any) => ({
...old,
...newTodo,
}));
// 4. Return context
return { previousTodo };
},
onError: (err, newTodo, context) => {
// 5. Rollback on error
queryClient.setQueryData(todoKeys.detail(newTodo.id), context?.previousTodo);
},
onSettled: (newTodo) => {
// 6. Refetch to ensure server sync
queryClient.invalidateQueries({ queryKey: todoKeys.detail(newTodo?.id) });
},
});
};
```
### Type-Safe Error Handling
Define a global error type for your API.
```typescript
// types/api.types.ts
export interface ApiError {
message: string;
statusCode: number;
}
// In custom hook
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { ApiError } from '../types/api.types';
export const useTodos = (options?: UseQueryOptions<Todo[], ApiError>) => {
return useQuery({
queryKey: todoKeys.lists(),
queryFn: fetchTodos,
...options,
});
};
```
---
## 8. Best Practices Checklist
- [ ] **Global Stale Time**: Set a reasonable global `staleTime` (e.g., 5 mins) to avoid excessive background fetching.
- [ ] **Query Key Factories**: Always use a factory/object for keys (`todoKeys.list(filter)`).
- [ ] **Separation of Concerns**: `Component` -> `Custom Hook` -> `API Function`.
- [ ] **Invalidation**: Always invalidate parent lists when creating/deleting items.
- [ ] **DevTools**: Keep `ReactQueryDevtools` in your app wrapper (it's stripped in production).Production-ready PostgreSQL and Drizzle ORM performance rules for scalable SaaS applications.
# PostgreSQL + Drizzle Performance Rules for Production SaaS > Production-ready PostgreSQL and Drizzle ORM performance rules for scalable SaaS applications. --- ## Database Query Performance - Always use indexed columns in `WHERE` clauses. - Prefer composite indexes when filtering by multiple frequently used columns. - Avoid `SELECT *` in production queries. Explicitly select only required columns. - Use `EXPLAIN ANALYZE` before deploying complex queries. - Never run unbounded queries in API endpoints. --- ## Pagination & Large Data Handling - Use `LIMIT` and `OFFSET` carefully. - Prefer keyset pagination for large datasets. - Avoid loading large datasets into memory. - Always paginate API responses returning collections. --- ## Indexing Strategy - Use partial indexes for frequently filtered subsets (e.g., active records). - Create GIN indexes for full-text search (`tsvector`). - Monitor index bloat and reindex periodically. - Avoid over-indexing rarely queried columns. --- ## Drizzle ORM Best Practices - Avoid N+1 query patterns. - Prefer server-side filtering over client-side filtering. - Use transactions for multi-step writes. - Keep ORM queries predictable and optimized. - Avoid dynamic raw SQL unless necessary and always sanitize inputs. --- ## Full-Text Search Optimization - Use `tsvector` with weighted fields. - Rank results using `ts_rank`. - Create a GIN index on the search vector. - Normalize search queries using `plainto_tsquery`. --- ## Data Modeling - Use appropriate data types (`UUID` instead of `text` for IDs when possible). - Avoid excessive `JSONB` nesting. - Keep schema normalized unless denormalization is justified. - Use foreign key constraints for relational integrity. --- ## Production Safety - Use connection pooling in production environments. - Avoid blocking queries inside request lifecycles. - Implement caching for frequently accessed rule lists. - Move heavy data processing to background jobs. - Monitor slow queries using PostgreSQL logs. --- ## Observability & Monitoring - Enable query logging in staging environments. - Track performance regressions after migrations. - Audit long-running transactions. - Monitor connection pool exhaustion.
Best practices to improve web performance and Lighthouse score.
When writing frontend code, follow these performance rules: 1. Reduce JavaScript bundle size. 2. Lazy load components when possible. 3. Use code splitting. 4. Avoid unnecessary state updates. 5. Debounce expensive operations. 6. Optimize images and use modern formats (WebP). 7. Avoid blocking scripts. 8. Use memoization for heavy computations. 9. Reduce DOM nodes where possible. 10. Ensure Lighthouse performance score stays above 90.
No description provided.
# Fastify + TypeScript + MongoDB Backend - Project Initialization Guide
> **AI Instruction**: Use this document to fully scaffold and initialize the backend project. Follow each section in order. Do not skip steps. Generate all files with the exact structure and content described.
---
## Tech Stack
| Layer | Technology |
|---|---|
| Runtime | Node.js (v20+) |
| Framework | Fastify v4 |
| Language | TypeScript (strict mode) |
| Database | MongoDB (via Mongoose v8) |
| Validation | Zod |
| Environment | dotenv |
| Dev Tooling | tsx, ts-node, eslint, prettier |
---
## Folder Structure
Generate the following folder and file structure exactly:
```
project-root/
├── src/
│ ├── config/
│ │ ├── db.ts # MongoDB connection logic
│ │ └── env.ts # Zod-validated environment variables
│ ├── modules/
│ │ └── example/
│ │ ├── example.controller.ts
│ │ ├── example.route.ts
│ │ ├── example.schema.ts # Zod schemas
│ │ ├── example.model.ts # Mongoose model
│ │ └── example.service.ts
│ ├── plugins/
│ │ ├── sensible.ts # fastify-sensible plugin
│ │ └── swagger.ts # Swagger/OpenAPI plugin (optional)
│ ├── hooks/
│ │ └── auth.hook.ts # Global auth hooks (if needed)
│ ├── utils/
│ │ ├── logger.ts # Custom logger wrapper
│ │ └── response.ts # Standard API response helpers
│ ├── types/
│ │ └── index.d.ts # Global type augmentations
│ ├── app.ts # Fastify app factory
│ └── server.ts # Entry point — starts server
├── .env
├── .env.example
├── .eslintrc.json
├── .prettierrc
├── tsconfig.json
├── package.json
└── README.md
```
---
## Step 1 — Initialize the Project
Run the following commands:
```bash
mkdir project-root && cd project-root
npm init -y
git init
```
---
## Step 2 — Install Dependencies
```bash
# Production dependencies
npm install fastify @fastify/sensible @fastify/cors mongoose zod dotenv
# Development dependencies
npm install -D typescript tsx ts-node @types/node \
eslint prettier eslint-config-prettier \
@typescript-eslint/parser @typescript-eslint/eslint-plugin
```
---
## Step 3 — TypeScript Configuration
**File: `tsconfig.json`**
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
```
---
## Step 4 — Package.json Scripts
Add the following `scripts` block to `package.json`:
```json
{
"type": "module",
"scripts": {
"dev": "tsx watch src/server.ts",
"build": "tsc",
"start": "node dist/server.js",
"lint": "eslint src --ext .ts",
"format": "prettier --write src/**/*.ts"
}
}
```
---
## Step 5 — Environment Variables
**File: `.env.example`**
```env
NODE_ENV=development
PORT=3000
HOST=0.0.0.0
MONGODB_URI=mongodb://localhost:27017/mydb
JWT_SECRET=your_jwt_secret_here
```
**File: `.env`** — copy from `.env.example` and fill in real values.
---
## Step 6 — Zod Environment Validation
**File: `src/config/env.ts`**
```typescript
import { z } from 'zod';
import dotenv from 'dotenv';
dotenv.config();
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
PORT: z.coerce.number().default(3000),
HOST: z.string().default('0.0.0.0'),
MONGODB_URI: z.string().url(),
JWT_SECRET: z.string().min(16),
});
const parsed = envSchema.safeParse(process.env);
if (!parsed.success) {
console.error('❌ Invalid environment variables:');
console.error(parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = parsed.data;
```
---
## Step 7 — MongoDB Connection
**File: `src/config/db.ts`**
```typescript
import mongoose from 'mongoose';
import { env } from './env.js';
export async function connectDB(): Promise<void> {
try {
await mongoose.connect(env.MONGODB_URI);
console.log('✅ MongoDB connected');
} catch (error) {
console.error('❌ MongoDB connection error:', error);
process.exit(1);
}
}
export async function disconnectDB(): Promise<void> {
await mongoose.disconnect();
console.log('🔌 MongoDB disconnected');
}
```
---
## Step 8 — Fastify App Factory
**File: `src/app.ts`**
```typescript
import Fastify, { FastifyInstance } from 'fastify';
import sensible from '@fastify/sensible';
import cors from '@fastify/cors';
import { exampleRoutes } from './modules/example/example.route.js';
export async function buildApp(): Promise<FastifyInstance> {
const app = Fastify({
logger: {
level: 'info',
transport: {
target: 'pino-pretty',
options: { colorize: true },
},
},
});
// Plugins
await app.register(sensible);
await app.register(cors, { origin: true });
// Routes
await app.register(exampleRoutes, { prefix: '/api/v1/examples' });
// Health check
app.get('/health', async () => ({ status: 'ok' }));
return app;
}
```
---
## Step 9 — Server Entry Point
**File: `src/server.ts`**
```typescript
import { buildApp } from './app.js';
import { connectDB, disconnectDB } from './config/db.js';
import { env } from './config/env.js';
async function main() {
const app = await buildApp();
await connectDB();
try {
await app.listen({ port: env.PORT, host: env.HOST });
console.log(`🚀 Server running at http://${env.HOST}:${env.PORT}`);
} catch (err) {
app.log.error(err);
await disconnectDB();
process.exit(1);
}
// Graceful shutdown
const shutdown = async (signal: string) => {
console.log(`\n⚠️ Received ${signal}. Shutting down...`);
await app.close();
await disconnectDB();
process.exit(0);
};
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('SIGTERM', () => shutdown('SIGTERM'));
}
main();
```
---
## Step 10 — Example Module
### Zod Schema
**File: `src/modules/example/example.schema.ts`**
```typescript
import { z } from 'zod';
export const createExampleSchema = z.object({
name: z.string().min(1, 'Name is required').max(100),
description: z.string().optional(),
isActive: z.boolean().default(true),
});
export const updateExampleSchema = createExampleSchema.partial();
export const exampleParamsSchema = z.object({
id: z.string().length(24, 'Invalid MongoDB ObjectId'),
});
export type CreateExampleInput = z.infer<typeof createExampleSchema>;
export type UpdateExampleInput = z.infer<typeof updateExampleSchema>;
export type ExampleParams = z.infer<typeof exampleParamsSchema>;
```
---
### Mongoose Model
**File: `src/modules/example/example.model.ts`**
```typescript
import mongoose, { Document, Schema } from 'mongoose';
export interface IExample extends Document {
name: string;
description?: string;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
}
const exampleSchema = new Schema<IExample>(
{
name: { type: String, required: true, trim: true },
description: { type: String },
isActive: { type: Boolean, default: true },
},
{
timestamps: true,
versionKey: false,
}
);
export const Example = mongoose.model<IExample>('Example', exampleSchema);
```
---
### Service Layer
**File: `src/modules/example/example.service.ts`**
```typescript
import { Example, IExample } from './example.model.js';
import { CreateExampleInput, UpdateExampleInput } from './example.schema.js';
export async function getAllExamples(): Promise<IExample[]> {
return Example.find({ isActive: true }).lean();
}
export async function getExampleById(id: string): Promise<IExample | null> {
return Example.findById(id).lean();
}
export async function createExample(data: CreateExampleInput): Promise<IExample> {
const example = new Example(data);
return example.save();
}
export async function updateExample(
id: string,
data: UpdateExampleInput
): Promise<IExample | null> {
return Example.findByIdAndUpdate(id, data, { new: true, runValidators: true }).lean();
}
export async function deleteExample(id: string): Promise<IExample | null> {
return Example.findByIdAndDelete(id).lean();
}
```
---
### Controller
**File: `src/modules/example/example.controller.ts`**
```typescript
import { FastifyRequest, FastifyReply } from 'fastify';
import { CreateExampleInput, ExampleParams, UpdateExampleInput } from './example.schema.js';
import * as service from './example.service.js';
export async function getAll(req: FastifyRequest, reply: FastifyReply) {
const data = await service.getAllExamples();
return reply.send({ success: true, data });
}
export async function getOne(
req: FastifyRequest<{ Params: ExampleParams }>,
reply: FastifyReply
) {
const item = await service.getExampleById(req.params.id);
if (!item) return reply.notFound('Example not found');
return reply.send({ success: true, data: item });
}
export async function create(
req: FastifyRequest<{ Body: CreateExampleInput }>,
reply: FastifyReply
) {
const data = await service.createExample(req.body);
return reply.status(201).send({ success: true, data });
}
export async function update(
req: FastifyRequest<{ Params: ExampleParams; Body: UpdateExampleInput }>,
reply: FastifyReply
) {
const data = await service.updateExample(req.params.id, req.body);
if (!data) return reply.notFound('Example not found');
return reply.send({ success: true, data });
}
export async function remove(
req: FastifyRequest<{ Params: ExampleParams }>,
reply: FastifyReply
) {
const data = await service.deleteExample(req.params.id);
if (!data) return reply.notFound('Example not found');
return reply.send({ success: true, message: 'Deleted successfully' });
}
```
---
### Route Registration
**File: `src/modules/example/example.route.ts`**
```typescript
import { FastifyInstance } from 'fastify';
import { zodToJsonSchema } from 'zod-to-json-schema';
import {
createExampleSchema,
updateExampleSchema,
exampleParamsSchema,
} from './example.schema.js';
import * as controller from './example.controller.js';
export async function exampleRoutes(app: FastifyInstance) {
app.get('/', { schema: { tags: ['Examples'] } }, controller.getAll);
app.get(
'/:id',
{ schema: { tags: ['Examples'], params: zodToJsonSchema(exampleParamsSchema) } },
controller.getOne
);
app.post(
'/',
{
schema: {
tags: ['Examples'],
body: zodToJsonSchema(createExampleSchema),
},
},
controller.create
);
app.put(
'/:id',
{
schema: {
tags: ['Examples'],
params: zodToJsonSchema(exampleParamsSchema),
body: zodToJsonSchema(updateExampleSchema),
},
},
controller.update
);
app.delete(
'/:id',
{ schema: { tags: ['Examples'], params: zodToJsonSchema(exampleParamsSchema) } },
controller.remove
);
}
```
> **Note**: Install `zod-to-json-schema` with: `npm install zod-to-json-schema`
---
## Step 11 — Utility Helpers
**File: `src/utils/response.ts`**
```typescript
export function successResponse<T>(data: T, message = 'Success') {
return { success: true, message, data };
}
export function errorResponse(message: string, errors?: unknown) {
return { success: false, message, errors };
}
```
---
## Step 12 — ESLint & Prettier Config
**File: `.eslintrc.json`**
```json
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"env": { "node": true, "es2022": true },
"rules": {
"@typescript-eslint/no-unused-vars": ["warn"],
"@typescript-eslint/explicit-function-return-type": "off"
}
}
```
**File: `.prettierrc`**
```json
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"tabWidth": 2
}
```
---
## Step 13 — .gitignore
**File: `.gitignore`**
```
node_modules/
dist/
.env
*.log
.DS_Store
```
---
## Conventions & Patterns
### Adding a New Module
To add a new module (e.g., `user`), create the following files following the same pattern:
```
src/modules/user/
├── user.controller.ts
├── user.route.ts
├── user.schema.ts
├── user.model.ts
└── user.service.ts
```
Then register the route in `src/app.ts`:
```typescript
await app.register(userRoutes, { prefix: '/api/v1/users' });
```
### Validation Pattern
Always validate input using Zod schemas in the schema file. Pass type-safe inferred types to controllers and services. Never bypass Zod for request body or params.
### Error Handling
Use `reply.notFound()`, `reply.badRequest()`, and `reply.internalServerError()` from `@fastify/sensible`. Wrap async service calls in try/catch at the controller level for unexpected errors.
---
## API Endpoints (Example Module)
| Method | Path | Description |
|---|---|---|
| GET | `/health` | Health check |
| GET | `/api/v1/examples` | List all examples |
| GET | `/api/v1/examples/:id` | Get one by ID |
| POST | `/api/v1/examples` | Create new |
| PUT | `/api/v1/examples/:id` | Update by ID |
| DELETE | `/api/v1/examples/:id` | Delete by ID |
---
## Final Checklist for AI Initialization
- [ ] Run `npm install` after generating `package.json`
- [ ] Create `.env` from `.env.example` with real values
- [ ] Ensure MongoDB is running locally or provide Atlas URI
- [ ] Run `npm run dev` to verify the server starts
- [ ] Hit `GET /health` to confirm the app is live
- [ ] Check MongoDB connection log for `✅ MongoDB connected`No description provided.
# Next.js SSR Project Development Rules
These rules define the architecture and coding standards for this
Next.js project.
Supported AI IDEs: - Cursor - Windsurf - GitHub Copilot - VS Code AI
tools - JetBrains AI Assistant
Framework: Next.js (App Router) Language: TypeScript Rendering: Server
Components + SSR
------------------------------------------------------------------------
# Core Principles
Always prioritize:
1. Server Components
2. SSR data fetching
3. Type safety
4. Separation of concerns
5. Scalable folder structure
Avoid unnecessary client components.
------------------------------------------------------------------------
# Project Folder Structure
Use the following structure.
app/ (api)/ (auth)/ dashboard/ layout.tsx page.tsx
components/ ui/ forms/ shared/
services/ api/ server/
lib/ db/ auth/ config/
hooks/ types/ utils/ constants/ styles/
Rules: - UI components → components/ - API communication →
services/api - Server logic → services/server - Shared utilities →
utils - Types → types
------------------------------------------------------------------------
# Rendering Rules
Default behavior must be Server Components.
Example:
``` tsx
export default async function Page() {
const users = await getUsers()
return (
<div>
{users.map(user => (
<p key={user.id}>{user.name}</p>
))}
</div>
)
}
```
Only use client components when needed.
Client component must start with:
"use client"
------------------------------------------------------------------------
# SSR Data Fetching Rules
Always fetch data on the server.
Example:
``` ts
async function getUsers() {
const res = await fetch("https://api.example.com/users", {
cache: "no-store"
})
return res.json()
}
```
Rules: - Prefer fetch() inside server components - Use revalidate for
caching - Avoid client-side API calls unless required
------------------------------------------------------------------------
# Server Actions Rules
Use Server Actions for mutations.
Example:
``` ts
"use server"
export async function createUser(formData: FormData) {
const name = formData.get("name")
await db.user.create({
data: { name }
})
}
```
Rules: - All mutations must be server actions - Never expose secrets to
client components
------------------------------------------------------------------------
# API Route Rules
Location:
app/api/
Example:
app/api/users/route.ts
Example API handler:
``` ts
export async function GET() {
return Response.json({ success: true })
}
```
Rules: - API routes should only contain request handling - Business
logic must live in services
------------------------------------------------------------------------
# Component Rules
Component guidelines: - Functional components only - Keep components
small - Separate UI and logic
Example:
components/UserCard.tsx
Example:
``` tsx
type Props = {
name: string
}
export function UserCard({ name }: Props) {
return <div>{name}</div>
}
```
------------------------------------------------------------------------
# TypeScript Rules
Strict TypeScript must be used.
Never use: any
Always type: - Props - API responses - Services
Example:
``` ts
type User = {
id: string
name: string
email: string
}
```
------------------------------------------------------------------------
# Service Layer Rules
All API logic must live in services.
Example structure:
services/ api/ userService.ts authService.ts
Example:
``` ts
export async function getUsers(): Promise<User[]> {
const res = await fetch("/api/users")
return res.json()
}
```
Rules: - UI components must not call APIs directly - Use service
functions
------------------------------------------------------------------------
# SEO Rules
Always use Next.js metadata API.
Example:
``` ts
export const metadata = {
title: "Dashboard",
description: "User dashboard"
}
```
------------------------------------------------------------------------
# Performance Rules
Always use built-in Next.js optimizations.
Required tools: - next/image - next/font - dynamic imports
Example:
``` tsx
import Image from "next/image"
```
------------------------------------------------------------------------
# Environment Variables
Secrets must live in:
.env.local
Example:
DATABASE_URL= NEXT_PUBLIC_API_URL= JWT_SECRET=
Rules: - Server secrets must never be exposed to client components
------------------------------------------------------------------------
# Error Handling
Use proper error boundaries.
Example:
app/error.tsx
Example:
``` tsx
export default function Error({ error }) {
return <div>Something went wrong</div>
}
```
------------------------------------------------------------------------
# Naming Conventions
Components → PascalCase Hooks → camelCase starting with use Services →
camelCase
Examples: UserCard.tsx useAuth.ts userService.ts formatPrice.ts
------------------------------------------------------------------------
# Testing Rules
Testing tools: - Jest - React Testing Library
Example test file:
UserCard.test.tsx
------------------------------------------------------------------------
# Code Quality Rules
Never: - Use any - Put business logic inside UI - Fetch data inside
client components unnecessarily - Duplicate logic
Always: - Write reusable components - Use proper types - Follow folder
structure - Keep components smallNo description provided.
# Expo React Native + TypeScript Development Rules
## Project Stack
- Framework: Expo (React Native)
- Language: TypeScript
- Navigation: Expo Router or React Navigation
- State Management: Prefer React Context or Zustand
- Styling: React Native StyleSheet or Tailwind (NativeWind)
------------------------------------------------------------------------
## File Structure
src/ components/ screens/ hooks/ services/ utils/ types/ constants/
Rules: - Components must live in `components/` - Screens must live in
`screens/` - Business logic should be inside `services/` - Reusable
hooks should be inside `hooks/` - Type definitions must live in `types/`
------------------------------------------------------------------------
## TypeScript Rules
Always follow strict TypeScript rules.
Required: - Avoid `any` - Prefer `type` or `interface` - Always type
props - Always type API responses
Example:
``` ts
type User = {
id: string
name: string
email: string
}
```
Component example:
``` ts
type Props = {
title: string
}
export function Header({ title }: Props) {
return <Text>{title}</Text>
}
```
------------------------------------------------------------------------
## Component Rules
Preferred component style:
- Functional components only
- Use hooks
- Avoid class components
Example:
``` tsx
export const Button = () => {
return <Pressable></Pressable>
}
```
Rules: - One component per file - Component name must match file name
Example:
components/Button.tsx
------------------------------------------------------------------------
## Styling Rules
Preferred order:
1. StyleSheet
2. NativeWind (if enabled)
Example:
``` ts
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16
}
})
```
Rules: - Do not inline large styles - Shared styles go in `/styles`
------------------------------------------------------------------------
## Hooks Rules
Custom hooks must start with `use`.
Example:
useAuth.ts\
useUser.ts\
useLocation.ts
Example implementation:
``` ts
export function useUser() {
const [user, setUser] = useState<User | null>(null)
return { user, setUser }
}
```
------------------------------------------------------------------------
## API Rules
All API calls must live in:
services/api/
Example:
services/api/userService.ts
Example:
``` ts
export async function getUsers(): Promise<User[]> {
const res = await fetch("/users")
return res.json()
}
```
Rules: - No API calls inside UI components - Always type API responses
------------------------------------------------------------------------
## Performance Rules
Always:
- Use React.memo for heavy components
- Use useCallback for handlers
- Use useMemo for computed values
- Avoid unnecessary re-renders
------------------------------------------------------------------------
## Expo Rules
Always prefer Expo APIs:
Examples:
expo-location\
expo-camera\
expo-secure-store\
expo-image-picker
Rules: - Do not install native packages if Expo already provides them -
Keep compatibility with Expo managed workflow
------------------------------------------------------------------------
## Error Handling
All async code must handle errors.
Example:
``` ts
try {
const users = await getUsers()
} catch (error) {
console.error(error)
}
```
------------------------------------------------------------------------
## Naming Conventions
Components → PascalCase\
Hooks → camelCase starting with `use`\
Files → PascalCase for components
Example:
UserCard.tsx\
useAuth.ts\
userService.ts
------------------------------------------------------------------------
## Testing
Preferred tools:
- Jest
- React Native Testing Library
Test files:
ComponentName.test.tsx
------------------------------------------------------------------------
## Code Quality Rules
Never:
- Use `any`
- Put business logic in UI
- Duplicate code
- Ignore TypeScript errors
Always:
- Write readable code
- Use proper types
- Split large componentsRules to ensure scalable, performant, and maintainable Next.js applications.
You are an expert Next.js developer. Follow these rules when generating or modifying code: 1. Always prefer Server Components in Next.js unless client-side interactivity is required. 2. Use the App Router structure and organize files by feature: /app /components /lib /hooks /services 3. Avoid unnecessary client-side JavaScript. Use "use client" only when required. 4. Optimize images using next/image. 5. Use dynamic imports for heavy components to reduce bundle size. 6. Always implement loading.tsx and error.tsx for routes. 7. Follow SEO best practices using metadata API. 8. Avoid inline styles; prefer Tailwind or CSS modules. 9. Ensure accessibility (aria labels, semantic HTML). 10. Optimize performance by reducing main-thread work and avoiding heavy libraries. Always prioritize performance, readability, and scalability.
No description provided.
# Pure State — Zustand Patterns That Actually Scale
> **AI Instruction**: This document defines the rules, conventions, and architecture decisions for implementing Zustand state management in a React + TypeScript project. Do not deviate from these patterns. When generating stores, hooks, or components — always refer back to these rules first.
---
## Stack
- **Zustand v4+** — primary state management
- **TypeScript strict mode** — all stores must be fully typed
- **Immer middleware** — for any nested state mutations
- **DevTools middleware** — applied to every store, always
- **Persist middleware** — only for state that must survive page refresh
---
## Folder Structure
```
src/
├── stores/
│ ├── index.ts # Re-export all stores + resetAllStores()
│ ├── useAuthStore.ts
│ ├── useUIStore.ts
│ ├── useUserStore.ts
│ └── slices/ # Only for large, multi-concern stores
│ ├── types.ts
│ ├── authSlice.ts
│ └── cartSlice.ts
├── hooks/
│ └── useStoreSelectors.ts # All memoized selectors live here
└── types/
└── store.d.ts # Shared store type declarations
```
---
## Store Architecture Rules
### One Store Per Domain
Every store must own exactly one concern. Never mix auth logic with UI state, or user profile with cart data. If two pieces of state are unrelated, they belong in separate stores. The store name must clearly reflect what it owns — `useAuthStore`, `useCartStore`, `useUIStore`.
### Always Define an Initial State Object
Every store must declare a separate `initialState` const above the store definition. This object is what the `reset()` action returns to. It also documents at a glance what shape the store holds without reading the full type definition.
### Every Store Must Have a Reset Action
Without exception, every store must implement a `reset()` action that restores the store to its `initialState`. This is called on logout, session expiry, or any global teardown. A store without `reset()` is incomplete.
### Always Apply DevTools Middleware
Every store — no matter how small — must be wrapped with `devtools()` middleware. The store name must be passed as the `name` option. Every `set()` call must include a descriptive action name as the third argument so that DevTools traces are meaningful and debuggable.
### Actions Belong Inside the Store
No business logic or state mutation should live outside the store. Components call store actions — they never call `set()` directly or manage async themselves. If a component is doing `setState` based on API data, that logic needs to move into a store action.
---
## TypeScript Conventions
### Always Separate State from Actions in the Interface
Define the store interface with a clear visual separation — state fields first, then actions. Use comments to divide them. This makes the interface scannable and prevents confusion between what is data and what is callable.
### Use Strict Typing for All State Fields
Never use `any`. Every field must have an explicit type. Optional fields must be typed as `T | null` — never as `T | undefined` unless the field is genuinely optional in a form or partial update context. Null signals "not yet loaded". Undefined signals "doesn't exist".
### Infer Action Parameter Types from Zod Schemas When Available
If the project uses Zod for API validation, action input types should be inferred from those schemas using `z.infer<typeof schema>`. Never duplicate type definitions between Zod schemas and store interfaces.
---
## Async Action Rules
### Every Async Action Must Follow the Three-Phase Pattern
When an async action starts, immediately set `isLoading: true` and `error: null`. On success, set the result data and `isLoading: false`. On failure, set the error message and `isLoading: false`. No async action is complete without all three phases handled.
### Always Name Async Action States in DevTools
When calling `set()` inside an async action, name each phase clearly — for example `login/pending`, `login/fulfilled`, `login/rejected`. This mirrors Redux Toolkit conventions and makes DevTools traces readable.
### Never Let Errors Silently Fail
Every catch block must write to the store's `error` field. The error message must be a human-readable string. Always check if the caught value is an instance of `Error` before accessing `.message` — otherwise fall back to a generic string.
### Access Current State Inside Async Actions with `get()`
When an async action needs to read current state mid-execution — for example to attach a token to a request — use `get()` from the store creator. Never close over state values from outside the action, as they may be stale.
### Never Trigger Actions from Inside Other Actions
Actions must not call sibling actions directly. If two actions share logic, extract that logic into a private utility function inside the store file and call it from both. Cross-action dependencies cause unpredictable execution order.
---
## Selector Rules
### Never Subscribe to the Whole Store
Components must never destructure the full store object. Subscribing to the whole store causes the component to re-render on every single state change regardless of relevance. Always pass a selector function that picks exactly the value the component needs.
### All Selectors Live in `useStoreSelectors.ts`
Every named selector — `useIsAuthenticated`, `useCurrentUser`, `useAuthLoading` — must be defined in the dedicated selectors file and exported from there. Components import from this file, not directly from the store. This centralizes all selector logic and makes refactoring easier.
### Actions Are Safe to Destructure Together
Action functions are stable references and do not cause re-renders. It is acceptable to select a group of actions together in one selector. State values must always be selected individually.
### Use Shallow Comparison for Object Selections
If a selector must return an object with multiple fields, use `shallow` from Zustand as the equality function. Without this, the component re-renders even when the object's values haven't changed because a new object reference is returned on every call.
---
## Immer Middleware Rules
### Use Immer Only When State is Nested Two or More Levels Deep
For flat state with primitive values, use regular `set()`. Apply Immer middleware to stores where deeply nested objects need to be updated — user profiles with nested preferences, addresses, or settings. Immer is not needed for simple top-level assignments.
### Never Return and Mutate in the Same Immer Callback
Inside an Immer `set()` callback, either mutate the draft directly or return a new object — never both. Mixing the two causes Immer to throw. Choose mutation style for nested updates, return style for complete state replacements.
### Always Guard Against Null Before Mutating Nested Objects
Before mutating a nested object inside an Immer callback, always check that the parent exists. If the parent is null and the action tries to mutate a child property, Immer will throw a runtime error. Defensive null checks are mandatory.
---
## Persist Middleware Rules
### Only Persist What Is Truly Necessary
Never persist entire store state by default. Always use `partialize` to explicitly whitelist fields that should survive a page refresh. Persisting loading states, error messages, or transient UI values is a bug.
### Always Name the Storage Key Explicitly
The `name` field in persist config is the localStorage key. It must be explicit, unique, and human-readable — for example `auth-storage` or `theme-preferences`. Never use auto-generated or ambiguous names.
### Persist Tokens, Not Sensitive Data
Authentication tokens may be persisted in localStorage for session continuity. Passwords, raw API responses, or personally identifiable information must never be persisted. When in doubt, do not persist.
---
## Slice Pattern Rules
### Use Slices Only for Large Multi-Domain Stores
The slice pattern — combining multiple `StateCreator` functions into one bound store — is appropriate when a single store legitimately crosses domains, such as a checkout flow that needs both cart state and auth state together. For typical apps, separate stores are preferred over slices.
### Define All Slice Types in a Shared Types File
Every slice interface must be defined in `slices/types.ts`. The combined `AppStore` type that merges all slice interfaces also lives there. Individual slice files import from types — they never redefine their own interfaces inline.
### Each Slice Is Responsible Only for Its Own State
A slice action must never directly mutate another slice's state. If coordination is needed between slices, it must happen at the bound store level through composition, not by cross-referencing slice internals.
---
## Reset and Cleanup Rules
### Export a `resetAllStores()` Function from `stores/index.ts`
The `index.ts` file must export a single `resetAllStores()` function that calls `.getState().reset()` on every store. This function is called in exactly one place — the logout handler. It is never called from components directly.
### Subscriptions Created Outside React Must Be Unsubscribed
If `store.subscribe()` is used outside a React component — for example to attach an auth token to an API client — the returned unsubscribe function must be stored and called during application teardown. Leaking subscriptions causes stale callbacks.
---
## Component Integration Rules
### Components Are Consumers Only
A component's only job with respect to state is to read values via selectors and call actions on user interaction. Components must not derive new state, filter arrays, or compute totals inline. That logic belongs in the store or in a dedicated selector.
### Co-locate Loading and Error State with Their Data
Whenever a component renders async data, it must also handle the corresponding `isLoading` and `error` states from the same store. Rendering data without handling its loading and error states is incomplete.
### Clear Errors Explicitly
After an async action fails and the error is displayed, always provide a mechanism — a dismiss button, a timeout, or a navigation event — to call `clearError()`. Errors must not persist in state indefinitely.
---
## Anti-Patterns — Never Do These
| ❌ Never | ✅ Always |
|---|---|
| Subscribe to the full store object | Select only the value needed |
| Put async logic inside components | Move async into store actions |
| Mutate state directly | Use `set()` or Immer |
| Create a store without DevTools | Every store gets `devtools()` |
| Skip loading or error state | All three async phases are required |
| Mix UI state and domain state | Separate stores per concern |
| Persist loading, errors, or UI flags | Only persist tokens and preferences |
| Call `reset()` from components | Use `resetAllStores()` from logout only |
| Duplicate types already in Zod schemas | Infer with `z.infer<>` |
| Hardcode localStorage key strings | Define as named constants |
---
## Final Checklist for AI Initialization
- [ ] One store file created per domain concern
- [ ] Every store has `initialState` const defined above the store
- [ ] Every store has a `reset()` action returning `initialState`
- [ ] Every store is wrapped with `devtools()` middleware and named
- [ ] All async actions handle `pending`, `fulfilled`, and `rejected` phases
- [ ] All selectors are defined in `useStoreSelectors.ts`
- [ ] No component subscribes to the full store object
- [ ] `resetAllStores()` is exported from `stores/index.ts`
- [ ] Persist middleware uses `partialize` to whitelist only necessary fields
- [ ] Immer middleware applied only to stores with nested state
- [ ] All store interfaces separate state fields from action fields
- [ ] No async logic lives inside React componentsBest practices for managing application state in React using Redux Toolkit. This rule promotes using createSlice, createAsyncThunk, typed hooks, and a feature-based structure to build scalable and ma
Use Redux Toolkit as the standard state management solution for React applications. Always create Redux logic using createSlice instead of manually writing reducers and action types. Structure Redux features using a feature-based folder structure where each slice contains its reducer, actions, and selectors. Use createAsyncThunk for handling asynchronous logic such as API calls. Keep Redux state minimal and avoid storing derived values that can be calculated from existing state. Prefer using the Redux Toolkit configureStore function to automatically enable useful middleware and dev tools. Avoid writing mutable logic in reducers unless using Redux Toolkit's Immer-powered syntax. Use typed hooks in TypeScript projects: - useAppDispatch - useAppSelector Do not store UI-only state (modals, form inputs, temporary values) in Redux unless it needs to be shared globally. Place all slices inside a dedicated "store" or "features" directory. Use selectors to access Redux state instead of directly referencing state structure in components. Ensure slices remain small and focused on a single domain or feature.
No description provided.
## **Core Principles**
* Use server-first architecture; prefer server components unless client-side behavior is required.
* Maintain strict separation of concerns across UI, business logic, and data layers.
* Ensure all code is scalable, modular, and maintainable.
---
## **Data Fetching Rules**
* Do not call `fetch()` directly inside components.
* All API communication must be handled through a centralized HTTP client.
* API logic must exist only in the `services` layer.
* UI components must access data only through hooks.
---
## **Component Rules**
* Each component must have a single responsibility.
* Component files must not exceed 150 lines.
* Target component size should be between 50–80 lines.
* Large components must be split into smaller reusable components.
---
## **State Management Rules**
* Use a centralized state management solution (e.g., Zustand or Redux Toolkit).
* Do not use `useContext` for global state management.
* Keep global state minimal and domain-specific.
---
## **Forms & Validation Rules**
* All forms must use a structured form library (e.g., React Hook Form).
* All validation must be schema-based (e.g., Zod).
* Validation schemas must be reusable and stored separately.
---
## **TypeScript Rules**
* Strict TypeScript is mandatory.
* Do not use `any` type.
* All API responses must use a generic structure (e.g., `ApiResponse<T>`).
* Types must be defined and reused across the application.
---
## **Routing Rules**
* All routes must be centralized in a constants file.
* Do not hardcode route paths inside components or navigation logic.
---
## **Enums & Constants Rules**
* Do not hardcode strings such as roles, statuses, or API identifiers.
* All enums must be defined in a centralized location.
* Reuse enums across all features.
---
## **Directory Structure Rules**
* Follow feature-based architecture:
```
src/
features/
[feature]/
components/
services/
hooks/
types/
schemas/
components/ui/
store/
lib/
constants/
types/enums/
```
---
## **Layer Responsibilities**
* UI layer must handle rendering only.
* Hooks must handle business logic and data orchestration.
* Services must handle API communication.
* Store must handle global state only.
* Schemas must handle validation.
* Types must define contracts and interfaces.
---
## **Prohibited Practices**
* Do not call APIs directly inside UI components.
* Do not use `fetch()` directly.
* Do not hardcode routes or static strings.
* Do not create large monolithic components.
* Do not use `any` in TypeScript.
---
## **Architecture Philosophy**
* Build systems, not pages.
* Prioritize consistency over flexibility.
* Ensure every module is reusable and replaceable.
* Maintain clear boundaries between layers.
---
## **Compatibility**
* This rule set is designed for modern frontend stacks (React, Next.js, TanStack, etc.).
* Aligns with standardized rule-sharing ecosystems like Airuleshub .