# AGENTS.md - Agent Coding Guidelines This workspace is a monorepo containing data engineering projects and WhatsApp CRM applications. --- ## Project Structure ``` workspace/ ├── apps/ │ ├── whatsapp-crm/ # Next.js CRM with Kanban board │ ├── whatsapp-sync/ # WhatsApp message sync service │ ├── whatsapp-reader/ # WhatsApp message reader │ └── timesfm-forecast/ # Time series forecasting app ├── data-engineering/ # Udacity DE portfolio projects └── skills/ # dbt reference templates ``` --- ## Build / Lint / Test Commands ### whatsapp-crm (primary app) ```bash cd apps/whatsapp-crm # Development npm run dev # Start Next.js dev server on 0.0.0.0:3000 npm run build # Production build npm run start # Production server # Linting npm run lint # ESLint with Next.js config # Testing npm run test # Run all Jest tests npm run test:watch # Run tests in watch mode npm run test:coverage # Run tests with coverage # Single test file npm run test -- tests/kanban.test.ts npm run test -- --testPathPattern=kanban ``` ### whatsapp-sync ```bash cd apps/whatsapp-sync npm run start # node src/index.js npm run dev # node --watch src/index.js npm run sync # node src/sync.js npm run test # Jest npm run test:watch # Jest watch mode ``` ### whatsapp-reader ```bash cd apps/whatsapp-reader # No test script defined ``` --- ## Code Style Guidelines ### TypeScript - `strict: true` enabled in tsconfig.json - Always use explicit types for function parameters and return values - Use `interface` for objects, `type` for unions/aliases ```typescript // Good interface Contact { id: number name: string stage: Stage } function getContactById(id: number): Contact | null // Avoid const contact = { id: 1, name: 'Test' } // implicit any ``` ### Imports - Use path alias `@/*` for internal imports (configured in tsconfig.json) - Order: external → internal → relative - Group by: React imports → other imports → types → components ```typescript import { useState, useMemo } from 'react' import { Stage, STAGES, Contact } from '@/lib/types' import { ContactCard } from '@/components/ContactCard' ``` ### Naming Conventions - **Components**: PascalCase (e.g., `KanbanBoard`, `ContactCard`) - **Files**: PascalCase for components (`.tsx`), camelCase for utilities (`.ts`) - **Interfaces/Types**: PascalCase (e.g., `Contact`, `Task`, `CreateContactInput`) - **Constants**: UPPER_SNAKE_CASE (e.g., `STAGES`, `STAGE_LIST`) - **React hooks**: camelCase with `use` prefix (e.g., `useContacts`, `useTask`) - **Boolean variables**: prefix with `is`, `has`, `should` (e.g., `isLoading`, `hasError`) ### Error Handling - Use Zod for input validation with react-hook-form - Always wrap async operations in try/catch - Return proper HTTP status codes in API routes ```typescript // API route error handling export async function POST(request: Request) { try { const body = await request.json() const validated = CreateContactInput.parse(body) // ... process } catch (error) { if (error instanceof ZodError) { return Response.json({ error: error.errors }, { status: 400 }) } return Response.json({ error: 'Internal server error' }, { status: 500 }) } } ``` ### Component Structure - Use `'use client'` directive for client-side components - Destructure props with explicit typing - Keep components focused and small - Extract reusable logic to custom hooks ```typescript 'use client' interface Props { contacts: Contact[] onContactClick: (contact: Contact) => void } export default function ComponentName({ contacts, onContactClick }: Props) { // hooks first, then effects, then render const [state, setState] = useState(false) return (
{/* JSX */}
) } ``` ### Database (sql.js) - Use Zod schemas for table definitions - Always validate data before insert/update - Use transactions for multi-step operations ### Testing - Test files: `tests/*.test.ts` or `*.test.tsx` - Use `@testing-library/react` for component tests - Use `@testing-library/user-event` for user interactions - Follow AAA pattern: Arrange, Act, Assert ```typescript test('should update contact stage', async () => { const user = userEvent.setup() render() await user.click(screen.getByText('Move to Next Stage')) expect(onStageChange).toHaveBeenCalledWith(1, 'DECIDINDO') }) ``` ### CSS / Styling - This project uses CSS modules or global CSS - Follow BEM-like naming: `block-element--modifier` - Keep styles co-located when possible ### Git Conventions - Use meaningful commit messages - Branch naming: `feature/description` or `fix/description` - Run `npm run lint` and `npm run test` before committing --- ## Important Notes - whatsapp-crm uses Next.js 14 App Router - Database is sql.js (WebAssembly SQLite) - runs in browser - Authentication uses WhatsApp Web.js QR code scanning - STAGES constant defines the Kanban pipeline (defined in `src/lib/types.ts`)