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:
2026-05-23 16:55:55 -03:00
parent 57920d45d6
commit 744868caa1
52 changed files with 4868 additions and 1068 deletions

125
apps/go-crm/README.md Normal file
View File

@@ -0,0 +1,125 @@
# go-crm (lightweight local dev)
This service is intentionally small so junior Go developers can understand it end-to-end without Docker, hot reloads, or other heavy tooling. The goal: `go run main.go` with a single SQLite file in `.dev-data/`.
## Local development (junior-friendly)
1. Ensure Go 1.25+ is installed and `go` is in your `PATH`.
2. Run the helper script (no Docker):
```bash
./scripts/dev.sh
```
3. The server boots on [http://localhost:8080](http://localhost:8080).
4. The database and WhatsApp store live under `.dev-data/` (auto-created).
There are no file watchers or `air` hot reloads—just the plain Go toolchain so newcomers can focus on code, not tooling.
## Project layout (modern, clean layers)
```
go-crm/
├── cmd/ # optional commands (e.g. migrations)
│ └── migrate/ # lightweight migration CLI (future)
├── config/ # templated configs (kept simple)
├── data/ # production data path (gitignored)
├── internal/ # HTTP handlers (usecases wired to HTTP)
│ ├── handlers/
│ ├── middleware/
│ └── templates/
├── pkg/ # reusable application packages
│ ├── domain/ # entities + repository interfaces
│ ├── usecase/ # application services / business logic
│ └── repo/ # persistence adapters (SQLite, etc.)
├── scripts/ # helper scripts (dev runner, migrations)
├── main.go # application entrypoint (wire handlers → usecases)
├── go.mod
└── go.sum
```
## Recommended architecture / interfaces
### `pkg/domain/lead.go`
```go
package domain
// Lead is the core business entity.
type Lead struct {
LeadID int64
ClientID int64
Name string
PhoneRaw string
PhoneNormalized string
ServiceInterest string
Status string
PaymentStatus string
}
// LeadRepository abstracts persistence.
type LeadRepository interface {
FindAll(ctx context.Context, clientID int64) ([]Lead, error)
FindByID(ctx context.Context, clientID, leadID int64) (*Lead, error)
Update(ctx context.Context, lead Lead) error
}
```
### `pkg/usecase/lead_service.go`
```go
package usecase
import (
"context"
"go-crm/pkg/domain"
)
// LeadService orchestrates business logic.
type LeadService struct {
Repo domain.LeadRepository
}
func (s *LeadService) ListAll(ctx context.Context, clientID int64) ([]domain.Lead, error) {
return s.Repo.FindAll(ctx, clientID)
}
```
### `pkg/repo/sqlite_lead_repo.go`
```go
package repo
import (
"context"
"database/sql"
"go-crm/pkg/domain"
)
// SQLiteLeadRepository implements LeadRepository using sqlite.
type SQLiteLeadRepository struct {
DB *sql.DB
}
func (r *SQLiteLeadRepository) FindAll(ctx context.Context, clientID int64) ([]domain.Lead, error) {
// query leads table, scan rows, return []domain.Lead
}
```
Handlers in `internal/handlers` should accept a clear service layer (`usecase.LeadService`), not raw DB logic. Keep controllers thin: parse request, call service, write HTML/JSON.
## Migration strategy
- Do not scan/clean the entire `leads` table on every startup (that was causing RAM blowups).
- Run the lightweight CLI with `make migrate` (which builds and runs the migration binary) whenever you need to refresh the schema or re-decode legacy Latin-1 data. To target non-default files, run the migration binary directly:
```bash
go build -o migrate cmd/migrate/main.go && ./migrate --db /path/to/go-crm.db
```
## Running tests
```bash
go test ./...
```
## Summary
- No Docker or `air` watchers—just `go run main.go`.
- Clean package boundaries (domain/usecase/repo) improve readability and testability.
- Scripts under `scripts/` orchestrate database setup or helper tasks.
- Use the architecture sketch above to guide future refactors.