192 lines
5.0 KiB
Markdown
192 lines
5.0 KiB
Markdown
# 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 (
|
|
<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.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(<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/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`)
|