fine-planets-strive/AGENTS.md
2026-05-08 19:21:20 +05:00

734 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AI Agent Instructions for TaylorDB Full-Stack Template
This template is designed for AI agents to build **modern, type-safe, full-stack applications** using TaylorDB as the data source. This template provides a complete monorepo setup with a React frontend (Vite + shadcn/ui) and a Node.js backend (tRPC + TaylorDB query builder).
---
## 🎯 Your Mission
Build production-ready, modern web applications (primarily dashboards and CRUD interfaces) that:
- Are **fully type-safe** from database to UI
- Use TaylorDB as the single source of truth for data
- Have **stunning, modern UI/UX** that wows users
- Follow best practices in architecture and code organization
---
## 📚 Docs for Agents
Before you start implementing, skim these docs in the `docs/` folder:
- **TaylorDB Query Builder**
- `docs/TAYLORDB_QUERY_REFERENCE.md` index for all query examples
- `docs/TAYLORDB_BASIC_QUERIES.md` basic reads, filtering, dates
- `docs/TAYLORDB_WRITE_OPERATIONS.md` inserts, updates, deletes
- `docs/TAYLORDB_ADVANCED_PATTERNS.md` aggregations, pagination, conditional queries
- `docs/TAYLORDB_FIELD_TYPES.md` field type mapping & enums
- `docs/TAYLORDB_ATTACHMENTS.md` working with attachment fields
- `docs/TAYLORDB_PITFALLS_BEST_PRACTICES.md` common mistakes & best practices
- **shadcn/ui Components & Dashboard Patterns**
- `docs/SHADCN_COMPONENTS_GUIDE.md` index for all shadcn/ui docs
- `docs/SHADCN_INSTALLATION.md` how to install shadcn/ui components
- `docs/SHADCN_DASHBOARD_PATTERNS.md` ready-made dashboard/layout patterns
- `docs/SHADCN_DESIGN_AND_LAYOUT.md` design tokens, layout, responsive & performance tips
Use `AGENTS.md` for **workflow and rules** and the `docs/` files for **detailed code examples**.
---
## 📋 Development Workflow
### **Phase 1: Understand Requirements & Design**
#### Step 1: Gather Requirements
Ask the user clarifying questions about:
- What data they want to work with (understand the domain)
- Key features and user workflows
- Target users and use cases
- Any specific UI/UX preferences
#### Step 2: Understand the Database Schema
**CRITICAL**: Always start by reading these files to understand the data model:
- `apps/server/taylordb/types.ts` - TypeScript types generated from TaylorDB schema
- `apps/server/taylordb/query-builder.ts` - Query builder patterns (review for examples)
> ⚠️ **IMPORTANT**: If these files don't exist, STOP and ask the user to generate them first. Never proceed with mock data.
#### Step 3: Design the Color Scheme & Visual Identity
Based on the requirements, decide on:
- **Primary color scheme** (use HSL values for flexibility)
- **Design aesthetic** (modern glassmorphism, gradients, minimalism, etc.)
- **Typography** (Google Fonts like Inter, Outfit, or Manrope)
- **Animation style** (subtle micro-interactions vs. bold animations)
Document your design decisions briefly before implementing.
---
### **Phase 2: Build the Foundation**
#### Step 1: Set Up Server-Side Data Layer
Use querybuilder which is in **File: `apps/server/taylordb/query-builder.ts`**
You can access the query builder from
```typescript
publicProcedure.input({}).query(({ input, ctx }) => {
const queryBuilder = ctx.queryBuilder;
});
```
// ============================================================================
// READ Operations
// ============================================================================
/**
* Get all records from a table
*/
export async function getAllItems() {
return await queryBuilder
.selectFrom("items")
.select(["id", "name", "status", "createdAt"])
.orderBy("createdAt", "desc")
.execute();
}
/**
* Get a single record by ID
*/
export async function getItemById(id: number) {
return await queryBuilder
.selectFrom("items")
.where("id", "=", id)
.executeTakeFirst();
}
// ============================================================================
// CREATE Operations
// ============================================================================
export async function createItem(data: { name: string; status: string }) {
return await queryBuilder.insertInto("items").values(data).executeTakeFirst();
}
// ============================================================================
// UPDATE Operations
// ============================================================================
export async function updateItem(
id: number,
data: { name?: string; status?: string },
) {
return await queryBuilder
.update("items")
.set(data)
.where("id", "=", id)
.execute();
}
// ============================================================================
// DELETE Operations
// ============================================================================
export async function deleteItem(id: number) {
return await queryBuilder.deleteFrom("items").where("id", "=", id).execute();
}
```
**Query Builder Patterns:**
- **Filtering**: `.where("field", "=", value)`, `.where("date", ">=", ["exactDay", "2024-01-01"])`
- **Select specific fields**: `.select(["id", "name", "status"])`
- **Ordering**: `.orderBy("createdAt", "desc")`
- **Single record**: `.executeTakeFirst()`
- **Multiple records**: `.execute()`
- **Array fields**: Use `[value]` for single-select enums
- **Date filters**: Use `["exactDay", date]` format
Organize functions by domain (e.g., all user-related functions together).
#### Step 2: Create tRPC API Router
**File: `apps/server/router.ts`**
Expose your database functions as type-safe tRPC procedures:
```typescript
import { z } from "zod";
import { router, publicProcedure } from "./trpc";
import * as db from "./taylordb/query-builder";
export const appRouter = router({
// Group by domain/feature
items: {
getAll: publicProcedure.query(async () => {
return await db.getAllItems();
}),
getById: publicProcedure
.input(z.object({ id: z.number() }))
.query(async ({ input }) => {
return await db.getItemById(input.id);
}),
create: publicProcedure
.input(
z.object({
name: z.string().min(1),
status: z.string(),
}),
)
.mutation(async ({ input }) => {
return await db.createItem(input);
}),
update: publicProcedure
.input(
z.object({
id: z.number(),
name: z.string().optional(),
status: z.string().optional(),
}),
)
.mutation(async ({ input }) => {
const { id, ...data } = input;
return await db.updateItem(id, data);
}),
delete: publicProcedure
.input(z.object({ id: z.number() }))
.mutation(async ({ input }) => {
return await db.deleteItem(input.id);
}),
},
});
export type AppRouter = typeof appRouter;
```
**Organization:**
- Group related procedures (e.g., `items`, `users`, `projects`)
- Use Zod for input validation
- Queries for reads, mutations for writes
- Export `AppRouter` type for frontend
---
### **Phase 3: Build the Frontend**
#### Step 1: Update Design System
**File: `apps/client/src/index.css`**
Update the design tokens based on your chosen color scheme:
```css
@layer base {
:root {
/* Update these HSL values for your color scheme */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 262 83% 58%; /* Example: Purple */
--primary-foreground: 210 40% 98%;
--accent: 262 90% 95%;
--accent-foreground: 262 83% 58%;
/* ... customize all tokens ... */
--radius: 0.75rem; /* Border radius */
}
.dark {
/* Dark mode colors */
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 263 70% 65%;
/* ... */
}
}
```
#### Step 2: Create shadcn/ui Components
**Always use shadcn/ui components**. Install components as needed with:
```bash
pnpm dlx shadcn@latest add <component-name>
```
For concrete install commands and patterns:
- See `docs/SHADCN_INSTALLATION.md` for component install snippets
- See `docs/SHADCN_DASHBOARD_PATTERNS.md` for tables, dialogs, forms, toasts, sheets, command palette, etc.
#### Step 3: Build Page Components
**File: `apps/client/src/pages/DashboardPage.tsx`**
Create feature-rich, modern pages:
```typescript
import { useState } from "react";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { trpc } from "@/lib/trpc";
import { PlusIcon, Loader2 } from "lucide-react";
export default function DashboardPage() {
const [name, setName] = useState("");
const { data: items, isLoading, refetch } = trpc.items.getAll.useQuery();
const createMutation = trpc.items.create.useMutation({
onSuccess: () => {
refetch();
setName("");
},
});
const deleteMutation = trpc.items.delete.useMutation({
onSuccess: () => refetch(),
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (name) {
createMutation.mutate({ name, status: "active" });
}
};
return (
<div className="container mx-auto p-8 max-w-6xl">
<div className="mb-8">
<h1 className="text-4xl font-bold mb-2">Dashboard</h1>
<p className="text-muted-foreground">Manage your items</p>
</div>
<div className="grid gap-6">
{/* Create Form */}
<Card>
<CardHeader>
<CardTitle>Add New Item</CardTitle>
<CardDescription>
Create a new item in your database
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="flex gap-4">
<div className="flex-1">
<Label htmlFor="name">Item Name</Label>
<Input
id="name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter item name..."
required
/>
</div>
<Button
type="submit"
disabled={createMutation.isPending}
className="mt-auto"
>
{createMutation.isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Adding...
</>
) : (
<>
<PlusIcon className="mr-2 h-4 w-4" />
Add Item
</>
)}
</Button>
</form>
</CardContent>
</Card>
{/* Items List */}
<Card>
<CardHeader>
<CardTitle>Your Items</CardTitle>
</CardHeader>
<CardContent>
{isLoading && (
<div className="flex items-center justify-center py-8">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
)}
{items && items.length === 0 && (
<p className="text-center text-muted-foreground py-8">
No items yet. Create your first item above.
</p>
)}
<div className="space-y-3">
{items?.map((item) => (
<div
key={item.id}
className="flex items-center justify-between p-4 border rounded-lg hover:bg-accent transition-colors"
>
<div>
<p className="font-medium">{item.name}</p>
<p className="text-sm text-muted-foreground">
{item.status}
</p>
</div>
<Button
variant="destructive"
size="sm"
onClick={() =>
item.id && deleteMutation.mutate({ id: item.id })
}
disabled={deleteMutation.isPending}
>
Delete
</Button>
</div>
))}
</div>
</CardContent>
</Card>
</div>
</div>
);
}
```
#### Step 4: Update Routing
**File: `apps/client/src/main.tsx`**
Add your new pages to the router:
```typescript
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import App from "./App";
import HomePage from "./pages/HomePage";
import DashboardPage from "./pages/DashboardPage";
const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{ index: true, element: <HomePage /> },
{ path: "dashboard", element: <DashboardPage /> },
],
},
]);
```
**File: `apps/client/src/App.tsx`**
Update navigation:
```typescript
const navItems = [
{ to: "/", label: "Home" },
{ to: "/dashboard", label: "Dashboard" },
];
```
---
### **Phase 4: Polish & Validate**
#### Step 1: Run Type Checking
**ALWAYS run this before considering your work complete:**
```bash
pnpm build
```
Fix all TypeScript errors. Never use `any` unless absolutely necessary.
#### Step 2: Run Linter
```bash
pnpm lint
```
Fix all linting errors.
#### Step 3: Test in Browser
The dev server should be running. Test:
- All CRUD operations work correctly
- Data updates in real-time
- Error states display properly
- Loading states show appropriate feedback
- UI is responsive and looks great
---
## 🎨 Design Guidelines
### Visual Excellence Principles
1. **No Generic Colors**: Never use plain red/blue/green. Use curated HSL palettes.
-`hsl(262 83% 58%)` (vibrant purple)
-`#0000ff` (plain blue)
2. **Premium Aesthetics**: Make it feel high-end
- Use subtle gradients, shadows, and glassmorphism
- Add smooth transitions (`transition-all duration-200`)
- Implement hover states on interactive elements
- Use proper spacing and visual hierarchy
3. **Modern Typography**:
- Import Google Fonts (e.g., Inter, Outfit, Manrope)
- Use varied font weights (400, 500, 600, 700)
- Proper text sizing hierarchy
4. **Micro-Animations**:
- Loading spinners with `lucide-react` icons + `animate-spin`
- Fade-ins on data load
- Smooth transitions on hover
- Button press feedback
5. **Dashboard-First Design**:
- Card-based layouts
- Clear visual grouping
- Stats/metrics prominently displayed
- Intuitive navigation
### Component Structure
**Always follow this pattern:**
```typescript
// 1. Imports (external, then internal)
import { useState } from "react";
import { Card } from "@/components/ui/card";
import { trpc } from "@/lib/trpc";
// 2. Type definitions (if needed)
interface ItemFormProps {
onSuccess: () => void;
}
// 3. Component (arrow function)
export default function ItemForm({ onSuccess }: ItemFormProps) {
// 4. State & hooks
const [name, setName] = useState("");
const createMutation = trpc.items.create.useMutation({ onSuccess });
// 5. Event handlers
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
createMutation.mutate({ name });
};
// 6. Render
return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}
```
---
## 📁 File Organization Best Practices
### Backend Structure
```
apps/server/
├── taylordb/
│ ├── types.ts # Generated types (DO NOT EDIT)
│ └── query-builder.ts # All database operations
├── router.ts # tRPC API routes
├── trpc.ts # tRPC configuration
└── index.ts # Server entry point
```
### Frontend Structure
```
apps/client/src/
├── components/
│ ├── ui/ # shadcn/ui components (auto-generated)
│ └── [custom]/ # Your custom components
├── pages/
│ └── [PageName].tsx # Route pages
├── lib/
│ ├── trpc.ts # tRPC client setup
│ └── utils.ts # Utilities (cn helper, etc.)
├── App.tsx # Layout + navigation
├── main.tsx # Router + app initialization
└── index.css # Global styles + design tokens
```
### Where to Put What
| What | Where |
| ---------------------- | -------------------------------------------- |
| Database queries | `apps/server/taylordb/query-builder.ts` |
| API endpoints | `apps/server/router.ts` |
| Route pages | `apps/client/src/pages/` |
| Reusable UI components | `apps/client/src/components/` |
| shadcn/ui components | `apps/client/src/components/ui/` (auto) |
| Design tokens | `apps/client/src/index.css` |
| TypeScript types | Use generated types from `taylordb/types.ts` |
---
## 🔧 TaylorDB Query Builder Reference
Instead of duplicating examples here, use the dedicated docs:
- `docs/TAYLORDB_QUERY_REFERENCE.md` index for all query builder docs
- `docs/TAYLORDB_BASIC_QUERIES.md` `selectFrom`, filtering, ordering, date filters
- `docs/TAYLORDB_WRITE_OPERATIONS.md` `insertInto`, `update`, `deleteFrom`
- `docs/TAYLORDB_ADVANCED_PATTERNS.md` aggregations, totals, conditional queries, pagination
- `docs/TAYLORDB_FIELD_TYPES.md` field type mapping, nullable handling, enums
- `docs/TAYLORDB_ATTACHMENTS.md` selecting and writing attachment fields
- `docs/TAYLORDB_PITFALLS_BEST_PRACTICES.md` pitfalls and best practices
When writing queries in `apps/server/taylordb/query-builder.ts`, mirror the patterns from these docs and keep everything **strongly typed** using `taylordb/types.ts`.
---
## ✅ Code Style Guidelines
### TypeScript
- **Never use `any`**. Use proper types from `taylordb/types.ts`
- Strict null checks: handle `null` and `undefined` explicitly
- Use type inference where obvious, explicit types for function params/returns
### Naming Conventions
- **Variables/Functions**: `camelCase` (e.g., `getUserData`)
- **Components**: `PascalCase` (e.g., `DashboardPage`)
- **Constants**: `UPPER_CASE` (e.g., `MAX_ITEMS`)
- **Files**: Match component name (e.g., `DashboardPage.tsx`)
### Imports
- Group external imports first, then internal
- Use path aliases: `@/components/...` not `../../components/...`
### Components
- Use arrow functions: `const MyComponent = () => { ... }`
- Props typing: `interface MyComponentProps { ... }`
- Keep components focused (single responsibility)
### Error Handling
- Display error states in UI
- Use tRPC's built-in error handling
- Show user-friendly messages
### Comments
- Use JSDoc for functions: `/** Description */`
- Explain "why", not "what"
- Remove commented-out code
---
## 🎓 Example: Building a Task Manager Dashboard
**User Request**: "Build a task manager with projects and tasks"
### 1. Analyze Schema
Assume TaylorDB has:
- `projects` table: `id`, `name`, `description`, `status`
- `tasks` table: `id`, `title`, `projectId`, `status`, `dueDate`
### 2. Design Decision
- **Color**: Gradient purple/blue theme
- **Style**: Modern with glassmorphism cards
- **Layout**: Projects on left sidebar, tasks on right
### 3. Backend (`apps/server/taylordb/query-builder.ts`)
```typescript
export async function getAllProjects() {
return await queryBuilder
.selectFrom("projects")
.select(["id", "name", "description", "status"])
.execute();
}
export async function getTasksByProject(projectId: number) {
return await queryBuilder
.selectFrom("tasks")
.where("projectId", "=", projectId)
.orderBy("dueDate", "asc")
.execute();
}
```
### 4. API (`apps/server/router.ts`)
```typescript
export const appRouter = router({
projects: {
getAll: publicProcedure.query(() => db.getAllProjects()),
},
tasks: {
getByProject: publicProcedure
.input(z.object({ projectId: z.number() }))
.query(({ input }) => db.getTasksByProject(input.projectId)),
},
});
```
### 5. Frontend (`apps/client/src/pages/TasksPage.tsx`)
Build the UI with cards, proper loading states, and type-safe tRPC calls.
---
## ⚠️ Critical Rules
1. **NEVER use mock data.** Always connect to real TaylorDB.
2. **NEVER ignore TypeScript errors.** Fix them before moving on.
3. **ALWAYS use shadcn/ui components** instead of hand-rolling UI.
4. **NEVER modify generated types** in `taylordb/types.ts`.
5. **ALWAYS run `pnpm build`** to validate your work.
6. **Design must be modern and premium**, not basic MVP.
---
## 🎯 Success Criteria
Your implementation is successful when:
- ✅ All TypeScript errors are resolved (`pnpm build` passes)
- ✅ All lint errors are fixed (`pnpm lint` passes)
- ✅ UI looks modern and premium (not basic/generic)
- ✅ All CRUD operations work correctly with TaylorDB
- ✅ Loading and error states are handled gracefully
- ✅ Code is well-organized and follows best practices
- ✅ Type safety is maintained from database to UI
---
**Remember**: You're building production-quality applications that should impress users from the first glance. Focus on visual excellence, type safety, and solid architecture.