5.3 KiB
5.3 KiB
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 (primary app)
│ ├── 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)
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
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
npm run test:coverage # Jest with coverage
whatsapp-reader
cd apps/whatsapp-reader
# No test script defined
node index.js # Run main script
node sync.js # Run sync script
timesfm-forecast (Python/uv)
cd apps/timesfm-forecast
uv venv && source .venv/bin/activate # Create & activate venv
uv pip install -e . # Install package
timesfm-app # Run Streamlit app
Code Style Guidelines
TypeScript
strict: trueenabled in tsconfig.json- Always use explicit types for function parameters and return values
- Use
interfacefor objects,typefor unions/aliases
// 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
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
useprefix (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
// API route error handling
export async function POST(request: Request) {
try {
const body = await request.json()
const validated = CreateContactInput.parse(body)
} 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
'use client'
interface Props {
contacts: Contact[]
onContactClick: (contact: Contact) => void
}
export default function ComponentName({ contacts, onContactClick }: Props) {
const [state, setState] = useState(false)
return <div>{/* JSX */}</div>
}
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.tsor*.test.tsx - Use
@testing-library/reactfor component tests - Use
@testing-library/user-eventfor user interactions - Follow AAA pattern: Arrange, Act, Assert
test('should update contact stage', async () => {
const user = userEvent.setup()
render(<KanbanBoard {...props} />)
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/descriptionorfix/description - Run
npm run lintandnpm run testbefore 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)