Files
workspace/AGENTS.md
2026-05-01 15:43:13 -03:00

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: true enabled in tsconfig.json
  • Always use explicit types for function parameters and return values
  • Use interface for objects, type for 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 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
// 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.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
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)