feat(go-crm): full auth, routing, middleware, and supporting infra
- Add auth handlers (signup, login, logout, account management) with bcrypt - Add client, customer, service, scheduling, payment, question, answer handlers - Add dashboard, monthly report, and lead pipeline pages - Add UTF-8 middleware to force charset on HTML responses - Add config package with env-based overrides for DB path, secrets, endpoints - Add parser package for WhatsApp message ingestion - Add clean-arch layers: pkg/domain, pkg/repo, pkg/usecase for leads - Add cmd/migrate utility for DB migrations - Add Makefile, README, run-tests.sh, and dev scripts - Update docker-compose.yml with memory limits - Update .air.toml to exclude DB files and stop on errors - Update whatsapp-sync dependencies and add src/index.js entrypoint - Add whatsme standalone WhatsApp reader app (source only) - Untrack .opencode-sandbox/data/go-crm.db from git history - Expand root .gitignore: ngrok, tmp dirs, sandbox DBs, compiled binaries
This commit is contained in:
219
AGENTS.md
219
AGENTS.md
@@ -1,206 +1,111 @@
|
||||
# AGENTS.md - Agent Coding Guidelines
|
||||
|
||||
Monorepo: data engineering projects + WhatsApp CRM apps.
|
||||
|
||||
---
|
||||
# AGENTS.md
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
workspace/
|
||||
├── apps/
|
||||
│ ├── go-crm/ # Go CRM, Chi router (primary)
|
||||
│ ├── whatsapp-crm/ # Next.js CRM, Kanban board
|
||||
│ ├── whatsapp-sync/ # WhatsApp message sync
|
||||
│ ├── whatsapp-reader/ # WhatsApp message reader
|
||||
│ └── timesfm-forecast/ # Time series forecast (Python/uv)
|
||||
├── data/ # SQLite files
|
||||
│ ├── go-crm.db
|
||||
│ └── whatsapp.db
|
||||
├── data-engineering/ # Udacity DE portfolio
|
||||
│ ├── go-crm/ # Go server (Chi), HTML templates, hot-reload via air
|
||||
│ ├── whatsapp-crm/ # Next.js 14 App Router, sql.js (browser SQLite), Kanban
|
||||
│ ├── whatsapp-sync/ # Node.js WhatsApp sync service
|
||||
│ ├── whatsapp-reader/ # Standalone message reader
|
||||
│ └── timesfm-forecast/ # Streamlit + TimesFM (Python/uv)
|
||||
├── data/ # SQLite DBs: go-crm.db, whatsapp.db
|
||||
├── data-engineering/ # Udacity DE portfolio (standalone, no unified build)
|
||||
└── skills/ # dbt reference templates
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build / Lint / Test Commands
|
||||
## Developer Commands
|
||||
|
||||
### go-crm (primary)
|
||||
```bash
|
||||
cd apps/go-crm
|
||||
go run main.go # plain dev (no hot-reload)
|
||||
air # hot-reload dev (uses .air.toml)
|
||||
go build -o go-crm main.go # binary
|
||||
./go-crm # run binary
|
||||
|
||||
go run main.go # dev
|
||||
go build -o go-crm main.go # build binary
|
||||
./go-crm # run binary
|
||||
go mod tidy # clean go.mod/go.sum
|
||||
|
||||
go mod download # deps
|
||||
go mod tidy # clean go.mod/go.sum
|
||||
|
||||
# DB: /workspace/data/go-crm.db
|
||||
# DB: /workspace/data/go-crm.db (hardcoded path — do not change)
|
||||
# WhatsApp session: /workspace/data/whatsapp.db (hardcoded path)
|
||||
```
|
||||
|
||||
### whatsapp-crm (Next.js)
|
||||
### whatsapp-crm
|
||||
```bash
|
||||
cd apps/whatsapp-crm
|
||||
|
||||
npm run dev # dev server 0.0.0.0:3000
|
||||
npm run build # production build
|
||||
npm run start # production server
|
||||
|
||||
npm run lint # ESLint
|
||||
|
||||
npm run test # all Jest tests
|
||||
npm run test:watch # watch mode
|
||||
npm run test:coverage # coverage
|
||||
|
||||
npm run test -- tests/kanban.test.ts
|
||||
npm run test -- --testPathPattern=kanban
|
||||
npm run dev # Next.js dev server 0.0.0.0:3000
|
||||
npm run build # production build
|
||||
npm run lint # ESLint
|
||||
npm run test # Jest (uses tests/setup.ts)
|
||||
```
|
||||
|
||||
### 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
|
||||
npm run test:coverage
|
||||
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 (mocks qrcode-terminal + whatsapp-web.js)
|
||||
```
|
||||
|
||||
### whatsapp-reader
|
||||
```bash
|
||||
cd apps/whatsapp-reader
|
||||
|
||||
node index.js # main script
|
||||
node sync.js # sync script
|
||||
node index.js # main script
|
||||
node sync.js # sync script
|
||||
# no test script
|
||||
```
|
||||
|
||||
### timesfm-forecast
|
||||
```bash
|
||||
cd apps/timesfm-forecast
|
||||
uv venv && source .venv/bin/activate
|
||||
uv pip install -e .
|
||||
ruff check . # lint (dev dep)
|
||||
timesfm-app # run Streamlit app
|
||||
|
||||
uv venv && source .venv/bin/activate # create + activate venv
|
||||
uv pip install -e . # install package
|
||||
timesfm-app # run Streamlit app
|
||||
# See apps/timesfm-forecast/README.md for CUDA/CPU wheel guidance
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Style Guidelines
|
||||
## Important Quirks
|
||||
|
||||
### TypeScript
|
||||
### WhatsApp auth sessions
|
||||
- `.wwebjs_auth/` directories store session state — do not commit these
|
||||
- `whatsapp-sync` uses `better-sqlite3` for persistence
|
||||
- `whatsapp-crm` browser-side uses `sql.js` (WebAssembly, no native deps)
|
||||
|
||||
### go-crm auth
|
||||
- `X-Internal-Secret` header required on requests (value: `internal-secret`)
|
||||
- WhatsApp connector init URL: `http://localhost:8080`
|
||||
|
||||
### Docker
|
||||
```bash
|
||||
docker compose up whatsapp-crm # CRM only
|
||||
docker compose --profile sync up # CRM + sync
|
||||
docker compose --profile test up # test runner
|
||||
```
|
||||
|
||||
### go-crm hot-reload
|
||||
- Uses `air` (not `go run`) — configured in `.air.toml`
|
||||
- Build excludes `_test.go` and `vendor/`, `tmp/`, `assets/`
|
||||
|
||||
### TypeScript config (whatsapp-crm, whatsapp-sync)
|
||||
- `strict: true` in tsconfig.json
|
||||
- Explicit types for params + return values
|
||||
- `interface` for objects, `type` for unions/aliases
|
||||
- Path alias `@/*` maps to `src/*`
|
||||
|
||||
```typescript
|
||||
interface Contact {
|
||||
id: number
|
||||
name: string
|
||||
stage: Stage
|
||||
}
|
||||
|
||||
function getContactById(id: number): Contact | null
|
||||
```
|
||||
|
||||
### Imports
|
||||
- Path alias `@/*` (tsconfig.json)
|
||||
- Order: external → internal → relative
|
||||
- Group: 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
|
||||
- **Components**: PascalCase (`KanbanBoard`, `ContactCard`)
|
||||
- **Files**: PascalCase (`.tsx`), camelCase (`.ts`)
|
||||
- **Interfaces/Types**: PascalCase
|
||||
- **Constants**: UPPER_SNAKE_CASE
|
||||
- **Hooks**: camelCase + `use` prefix
|
||||
- **Booleans**: `is`/`has`/`should` prefix
|
||||
|
||||
### Error Handling
|
||||
- Zod for input validation + react-hook-form
|
||||
- Wrap async in try/catch
|
||||
- Return proper HTTP status codes
|
||||
|
||||
```typescript
|
||||
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 client'` directive for client-side
|
||||
- Destructure props, explicit typing
|
||||
- Keep components focused, 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) {
|
||||
const [state, setState] = useState(false)
|
||||
|
||||
return <div>{/* JSX */}</div>
|
||||
}
|
||||
```
|
||||
|
||||
### Database (sql.js)
|
||||
- Zod schemas for table definitions
|
||||
- Validate data before insert/update
|
||||
- Use transactions for multi-step ops
|
||||
|
||||
### Testing
|
||||
- Test files: `tests/*.test.ts` or `*.test.tsx`
|
||||
- `@testing-library/react` for component tests
|
||||
- `@testing-library/user-event` for interactions
|
||||
- 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
|
||||
- CSS modules or global CSS
|
||||
- BEM-like: `block-element--modifier`
|
||||
- Co-locate styles when possible
|
||||
|
||||
### Git
|
||||
- Meaningful commit messages
|
||||
- Branch naming: `feature/description` or `fix/description`
|
||||
- Run `npm run lint` + `npm run test` before commit
|
||||
### Testing mocks
|
||||
- `whatsapp-sync` has manual mocks for `qrcode-terminal` and `whatsapp-web.js` in `tests/__mocks__/`
|
||||
|
||||
---
|
||||
|
||||
## Important Notes
|
||||
## What to Avoid
|
||||
|
||||
- whatsapp-crm: Next.js 14 App Router
|
||||
- Database: sql.js (WebAssembly SQLite), runs in browser
|
||||
- Auth: WhatsApp Web.js QR code scanning
|
||||
- STAGES constant: Kanban pipeline (defined in `src/lib/types.ts`)
|
||||
- Do not use `go run main.go` for development — use `air`
|
||||
- Do not commit `.wwebjs_auth/` or `.wwebjs_cache/` directories
|
||||
- Do not change hardcoded DB paths in `main.go`
|
||||
- The `data-engineering/` projects are standalone — no shared build or test commands
|
||||
Reference in New Issue
Block a user