diff --git a/README.md b/README.md index 60e5982..21e4ee7 100644 --- a/README.md +++ b/README.md @@ -1,167 +1,234 @@ -# Casera API (Go) +# Casera API -Go implementation of the Casera property management API, built with Echo, GORM, and GoAdmin. +Go REST API for the Casera (MyCrib) property management platform. Powers iOS and Android mobile apps built with Kotlin Multiplatform. ## Tech Stack +- **Language**: Go 1.24 - **HTTP Framework**: [Echo v4](https://github.com/labstack/echo) - **ORM**: [GORM](https://gorm.io/) with PostgreSQL -- **Push Notifications**: Direct APNs (via [apns2](https://github.com/sideshow/apns2)) + FCM HTTP API -- **Admin Panel**: [GoAdmin](https://github.com/GoAdminGroup/go-admin) -- **Background Jobs**: [Asynq](https://github.com/hibiken/asynq) +- **Background Jobs**: [Asynq](https://github.com/hibiken/asynq) (Redis-backed) +- **Push Notifications**: APNs ([apns2](https://github.com/sideshow/apns2)) + FCM HTTP API - **Caching**: Redis - **Logging**: [zerolog](https://github.com/rs/zerolog) - **Configuration**: [Viper](https://github.com/spf13/viper) +- **Admin Panel**: Next.js (separate build target) -## Quick Start +## Prerequisites -### Prerequisites +- **Go 1.24+** — [install](https://go.dev/dl/) +- **PostgreSQL 16+** — via Docker (recommended) or [native install](https://www.postgresql.org/download/) +- **Redis 7+** — via Docker (recommended) or [native install](https://redis.io/docs/getting-started/) +- **Docker & Docker Compose** — [install](https://docs.docker.com/get-docker/) (recommended for local development) +- **Make** — pre-installed on macOS; `apt install make` on Linux -- Go 1.21+ -- PostgreSQL 15+ -- Redis 7+ +## Getting Started on a New Machine -### Development Setup +### Option A: Docker (Recommended) + +This starts PostgreSQL, Redis, the API server, background worker, and admin panel in containers. ```bash -# Install dependencies -make deps +# 1. Clone the repo +git clone +cd myCribAPI-go -# Copy environment file +# 2. Create your environment file cp .env.example .env -# Edit .env with your configuration +# Edit .env — at minimum set SECRET_KEY to a random 32+ char string -# Run the API server -make run -``` - -### Docker Setup - -```bash -# Start all services +# 3. Start all services make docker-up -# View logs -make docker-logs +# 4. Seed the database with lookup data (required) +docker exec -i casera-db psql -U casera -d casera < seeds/001_lookups.sql -# Stop services -make docker-down +# 5. (Optional) Seed test data — creates test users, residences, tasks +docker exec -i casera-db psql -U casera -d casera < seeds/002_test_data.sql +docker exec -i casera-db psql -U casera -d casera < seeds/003_task_templates.sql + +# 6. Verify the API is running +curl http://localhost:8000/api/health/ ``` +The API is now available at `http://localhost:8000`. + +### Option B: Run Locally (No Docker for the API) + +Use Docker for PostgreSQL and Redis, but run the Go server natively for faster iteration. + +```bash +# 1. Clone and enter the repo +git clone +cd myCribAPI-go + +# 2. Install Go dependencies +make deps + +# 3. Start PostgreSQL and Redis via Docker +docker compose up -d db redis + +# 4. Create your environment file +cp .env.example .env +# Edit .env: +# - Set SECRET_KEY to a random 32+ char string +# - Set DB_HOST=localhost +# - Set DB_PORT=5433 (docker-compose maps 5433 externally) +# - Set REDIS_URL=redis://localhost:6379/0 + +# 5. Seed the database +psql -h localhost -p 5433 -U casera -d casera < seeds/001_lookups.sql +psql -h localhost -p 5433 -U casera -d casera < seeds/002_test_data.sql +psql -h localhost -p 5433 -U casera -d casera < seeds/003_task_templates.sql + +# 6. Run the API server +make run + +# 7. (Optional) Run the background worker in a separate terminal +make run-worker +``` + +### Option C: Fully Native (No Docker) + +Install PostgreSQL and Redis natively on your machine. + +```bash +# macOS with Homebrew +brew install postgresql@16 redis + +# Start services +brew services start postgresql@16 +brew services start redis + +# Create the database +createdb casera + +# Then follow Option B steps 2-7, using: +# DB_HOST=localhost, DB_PORT=5432, POSTGRES_USER=, POSTGRES_PASSWORD= +``` + +## Environment Variables + +Copy `.env.example` to `.env` and configure: + +| Variable | Description | Default | Required | +|----------|-------------|---------|----------| +| `PORT` | Server port | `8000` | No | +| `DEBUG` | Enable debug logging | `true` | No | +| `SECRET_KEY` | JWT signing secret (32+ chars) | — | **Yes** | +| `POSTGRES_DB` | Database name | `casera` | Yes | +| `POSTGRES_USER` | Database user | `postgres` | Yes | +| `POSTGRES_PASSWORD` | Database password | — | Yes | +| `DB_HOST` | Database host | `localhost` | Yes | +| `DB_PORT` | Database port | `5432` | Yes | +| `REDIS_URL` | Redis connection URL | `redis://localhost:6379/0` | Yes | +| `EMAIL_HOST` | SMTP server | `smtp.gmail.com` | For email | +| `EMAIL_HOST_USER` | SMTP username | — | For email | +| `EMAIL_HOST_PASSWORD` | SMTP app password | — | For email | +| `APNS_AUTH_KEY_PATH` | Path to APNs `.p8` key file | — | For iOS push | +| `APNS_AUTH_KEY_ID` | APNs key ID | — | For iOS push | +| `APNS_TEAM_ID` | Apple Team ID | — | For iOS push | +| `FCM_SERVER_KEY` | Firebase server key | — | For Android push | + ## Project Structure ``` myCribAPI-go/ ├── cmd/ -│ ├── api/main.go # API server entry point -│ ├── worker/main.go # Background worker entry point -│ └── admin/main.go # GoAdmin server entry point +│ ├── api/main.go # API server entry point +│ └── worker/main.go # Background worker entry point ├── internal/ -│ ├── config/ # Configuration management -│ ├── models/ # GORM models -│ ├── database/ # Database connection -│ ├── repositories/ # Data access layer -│ ├── services/ # Business logic -│ ├── handlers/ # HTTP handlers -│ ├── middleware/ # Gin middleware -│ ├── dto/ # Request/Response DTOs -│ ├── router/ # Route setup -│ ├── push/ # APNs/FCM push notifications -│ ├── worker/ # Asynq jobs -│ └── admin/ # GoAdmin tables -├── pkg/ -│ ├── utils/ # Utilities -│ └── errors/ # Error types -├── migrations/ # SQL migrations -├── templates/emails/ # Email templates -├── docker/ # Docker files -├── go.mod -└── Makefile +│ ├── config/ # Viper configuration +│ ├── database/ # PostgreSQL connection setup +│ ├── models/ # GORM models (map to PostgreSQL tables) +│ ├── repositories/ # Data access layer +│ ├── services/ # Business logic +│ ├── handlers/ # HTTP handlers (Echo) +│ ├── middleware/ # Auth, timezone, logging middleware +│ ├── router/ # Route registration +│ ├── dto/ # Request/Response DTOs +│ │ ├── requests/ # Incoming request structs +│ │ └── responses/ # Outgoing response structs +│ ├── task/ # Centralized task logic +│ │ ├── predicates/ # IsCompleted, IsOverdue, etc. +│ │ ├── scopes/ # GORM query scopes +│ │ └── categorization/ # Kanban column assignment +│ ├── apperrors/ # Structured error types +│ ├── push/ # APNs + FCM push notification clients +│ ├── worker/ # Asynq background jobs +│ ├── i18n/ # Internationalization (en, es, fr) +│ ├── validator/ # Input validation +│ ├── monitoring/ # Health checks +│ └── integration/ # Integration + contract tests +├── admin/ # Next.js admin panel +├── migrations/ # SQL migration files +├── seeds/ # Seed data (lookups, test users) +├── templates/emails/ # Email templates +├── docs/ # API docs, OpenAPI spec +├── docker-compose.yml # Production-like Docker setup +├── docker-compose.dev.yml # Development overrides +├── Dockerfile # Multi-stage build (api, worker, admin) +├── Makefile # Build, test, Docker commands +└── .env.example # Environment variable template ``` -## API Endpoints - -The API maintains 100% compatibility with the Django version. - -### Public Endpoints (No Auth) - -- `GET /api/health/` - Health check -- `POST /api/auth/login/` - Login -- `POST /api/auth/register/` - Register -- `GET /api/static_data/` - Cached lookups - -### Protected Endpoints (Token Auth) - -- `GET /api/residences/` - List residences -- `GET /api/tasks/` - List tasks -- `GET /api/tasks/by-residence/:id/` - Kanban board -- See full API documentation in the Django project - -## Configuration - -Environment variables (see `.env.example`): - -| Variable | Description | Default | -|----------|-------------|---------| -| `PORT` | Server port | 8000 | -| `DEBUG` | Debug mode | false | -| `SECRET_KEY` | JWT secret | required | -| `POSTGRES_*` | Database config | - | -| `REDIS_URL` | Redis URL | redis://localhost:6379/0 | -| `APNS_*` | iOS push config | - | -| `FCM_SERVER_KEY` | Android push key | - | - ## Development -```bash -# Run tests -make test - -# Run tests with coverage -make test-coverage - -# Run linter -make lint - -# Format code -make fmt -``` - -## Database - -This Go version uses the same PostgreSQL database as the Django version. GORM models are mapped to Django's table names: - -- `auth_user` - Django's User model -- `user_authtoken` - Auth tokens -- `residence_residence` - Residences -- `task_task` - Tasks - -## Seeding Data - -Seed files are located in `seeds/`: -- `001_lookups.sql` - Lookup tables (residence types, task categories, priorities, etc.) -- `002_test_data.sql` - Test users, residences, tasks, contractors, etc. - -### Local Development +### Common Commands ```bash -# Seed lookup tables -./dev.sh seed - -# Seed test data -./dev.sh seed-test +make run # Run API server +make run-worker # Run background worker +make deps # Install/tidy Go dependencies +make build # Build API binary +make build-all # Build API + worker + admin binaries +make fmt # Format code +make vet # Vet code +make lint # Run golangci-lint +make clean # Remove build artifacts ``` -### Production (Dokku) +### Testing ```bash -# Seed lookup tables (required) -cat seeds/001_lookups.sql | dokku postgres:connect casera-db +make test # Run all tests with race detection + coverage +make test-coverage # Run tests and generate HTML coverage report +make contract-test # Run route + KMP contract validation tests -# Seed test data -cat seeds/002_test_data.sql | dokku postgres:connect casera-db +# Run specific packages +go test ./internal/handlers -v +go test -run TestTaskHandler_CreateTask ./internal/handlers ``` +### Docker + +```bash +make docker-up # Start all containers +make docker-down # Stop all containers +make docker-logs # Tail container logs +make docker-restart # Restart all containers +make docker-dev # Start in dev mode (source mounted, debug on) +``` + +### Database Migrations + +```bash +make migrate-up # Apply pending migrations +make migrate-down # Roll back last migration +make migrate-create name=add_column # Create a new migration pair +``` + +## Seed Data + +Seed files in `seeds/`: + +| File | Purpose | Required | +|------|---------|----------| +| `001_lookups.sql` | Residence types, task categories, priorities, frequencies, contractor specialties | **Yes** | +| `002_test_data.sql` | Test users, residences, tasks, contractors, documents, notifications | Dev only | +| `003_task_templates.sql` | Pre-built task templates for onboarding | Dev only | +| `003_admin_user.sql` | Admin panel user | If using admin | + ### Test Users All test users have password: `password123` @@ -170,21 +237,37 @@ All test users have password: `password123` |----------|-------|------|-------| | admin | admin@example.com | Pro | Admin user | | john | john@example.com | Pro | Owns 2 residences | -| jane | jane@example.com | Free | Owns 1 residence, shared access to residence 1 | +| jane | jane@example.com | Free | Owns 1 residence, shared access | | bob | bob@example.com | Free | Owns 1 residence | -### Test Data Includes +## API Documentation -- 4 residences (house, beach house, apartment, condo) -- 4 contractors with specialties -- 10 tasks across residences -- Documents/warranties -- Notifications +- **OpenAPI spec**: `docs/openapi.yaml` (81 paths, 104 operations, 81 schemas) +- **Health check**: `GET /api/health/` +- **Auth**: `POST /api/auth/login/`, `POST /api/auth/register/` +- **Static data**: `GET /api/static_data/` (ETag-cached lookups) -## Migration from Django +All protected endpoints require an `Authorization: Token ` header. -This is a full rewrite that maintains API compatibility. The mobile clients (KMM) work with both versions without changes. +## Production Deployment (Dokku) + +```bash +# Push to Dokku +git push dokku main + +# Seed lookup data +cat seeds/001_lookups.sql | dokku postgres:connect casera-db + +# Check logs +dokku logs casera-api -t +``` + +## Related Projects + +- **Mobile App (KMM)**: `../MyCribKMM` — Kotlin Multiplatform iOS/Android client +- **Task Logic Docs**: `docs/TASK_LOGIC_ARCHITECTURE.md` — required reading before task-related work +- **Push Notification Docs**: `docs/PUSH_NOTIFICATIONS.md` ## License -Proprietary - Casera +Proprietary — Casera