go-first/docs/DEVELOPMENT.md

596 lines
12 KiB
Markdown
Raw Permalink Normal View History

2026-10-07 15:21:47 +02:00
# Development Guide — go-first / URPI
This guide covers local development setup, workflows, and best practices.
---
## 🛠️ Prerequisites
### Required Tools
| Tool | Version | Install |
|------|---------|---------|
| Go | 1.23+ | `brew install go` / `apt install golang` |
| Node.js | 20+ | `nvm install 20` / `fnm install 20` |
| Docker | 24+ | [docker.com](https://docker.com) |
| Git | 2.40+ | `brew install git` / `apt install git` |
### Recommended Tools
- **IDE**: VS Code with Go + TypeScript extensions
- **API Client**: HTTPie, Postman, or VS Code REST Client
- **Database**: TablePlus, DBeaver, or pgAdmin
- **Terminal**: Warp, Ghostty, or Kitty
---
## 🚀 Getting Started
### 1. Clone & Setup
```bash
git clone https://github.com/dnoulet/go-first.git
cd go-first
# Install all dependencies
make install
# This runs:
# - go mod download
# - cd web && npm ci
```
### 2. Start Development Databases
```bash
# Start PostgreSQL + Redis only
docker compose up -d postgres redis
# Verify
docker compose ps
docker compose exec postgres pg_isready -U postgres
docker compose exec redis redis-cli ping
```
### 3. Configure Local Environment
```bash
cp .env.local.example .env.local
# Edit if needed (defaults work for Docker databases)
vim .env.local
```
### 4. Run Development Servers
```bash
# Option A: Both together (recommended)
make dev
# Option B: Separate terminals
# Terminal 1 - Backend
make dev-backend
# Terminal 2 - Frontend
make dev-frontend
```
### 5. Verify
| Service | URL |
|---------|-----|
| Frontend | http://localhost:5173 |
| Backend API | http://localhost:8080/api/v1 |
| Health Check | http://localhost:8080/api/v1/health |
| PostgreSQL | localhost:5432 |
| Redis | localhost:6379 |
---
## 🔄 Development Workflow
### Backend Development
```bash
# Hot reload with air (already configured in .air.toml)
make dev-backend
# Or manually:
go run ./cmd/server
```
#### Adding a New Endpoint
1. **Model** — Add types in `internal/model/models.go`
2. **Service** — Create service in `internal/service/`
3. **Handler** — Add handler in `internal/handler/handler.go`
4. **Routes** — Register in `handler.RegisterRoutes()`
5. **Tests** — Add tests in `*_test.go` files
### Frontend Development
```bash
# Hot module replacement (Vite)
make dev-frontend
# Or manually:
cd web && npm run dev
```
#### Adding a New Page/Section
1. **Types** — Add to `web/src/types/index.ts`
2. **API** — Add endpoint to `web/src/services/api.ts`
3. **Hook** — Create custom hook in `web/src/hooks/`
4. **Component** — Create in `web/src/components/sections/`
5. **Register** — Import and add to `web/src/App.tsx`
### Code Generation
```bash
# Generate mocks for testing
make generate
# This runs: go generate ./...
# Uses: github.com/golang/mock/mockgen
```
---
## 🧪 Testing
### Backend Tests
```bash
# Run all tests with coverage
make test-backend
# Run specific package
go test -v ./internal/service/...
# Run with race detector
go test -race ./...
# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
```
### Frontend Tests
```bash
# Run tests
make test-frontend
# Or manually:
cd web && npm test
# With UI
cd web && npm test -- --ui
# Coverage
cd web && npm test -- --coverage
```
### E2E Tests (Optional)
```bash
# Install Playwright
cd web && npx playwright install
# Run E2E tests
cd web && npm run test:e2e
```
---
## 🔍 Code Quality
### Linting
```bash
# All linters
make lint
# Backend only
make lint-backend
# Runs: golangci-lint run ./...
# Frontend only
make lint-frontend
# Runs: eslint + prettier check
```
### Formatting
```bash
# Format all code
make fmt
# Backend
go fmt ./...
goimports -w .
# Frontend
cd web && npm run format
```
### Pre-commit Hooks
```bash
# Install pre-commit
pip install pre-commit
pre-commit install
# Run manually
pre-commit run --all-files
```
#### `.pre-commit-config.yaml`
```yaml
repos:
- repo: https://github.com/golangci/golangci-lint
rev: v1.56.0
hooks:
- id: golangci-lint
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
types: [typescript, json, yaml, markdown]
- repo: local
hooks:
- id: go-fmt
name: go fmt
entry: go fmt ./...
language: system
types: [go]
```
---
## 🗃️ Database Migrations
### Creating Migrations
```bash
# Create new migration
make db-migrate-create name=add_users_table
# This creates:
# migrations/000001_add_users_table.up.sql
# migrations/000001_add_users_table.down.sql
```
### Running Migrations
```bash
# Apply all pending
make db-migrate-up
# Rollback last
make db-migrate-down
# Check status
migrate -path ./migrations -database "$DSN" version
```
### Migration Best Practices
- **Up migrations**: Add columns, tables, indexes
- **Down migrations**: Reverse exactly (drop what you added)
- **Never modify** applied migrations
- **Test** both up and down locally
- **Name clearly**: `add_user_email_index`, not `fix_db`
---
## 🐳 Docker Development
### Build Locally
```bash
# Build production image
make docker-build
# Run production image locally
make docker-run
# Or with docker-compose (includes DB)
docker compose up -d --build
```
### Debugging in Container
```bash
# Run with shell
docker run -it --rm -p 8080:8080 ghcr.io/dnoulet/go-first:latest sh
# Or attach to running
docker exec -it go-first-app sh
```
### Development with Docker Compose Override
Create `docker-compose.override.yml`:
```yaml
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/web/node_modules
command: air -c .air.toml
environment:
- SERVER_MODE=debug
```
---
## 🎨 Frontend Architecture
### Component Structure
```
web/src/components/
├── ui/ # Reusable primitives (Button, Card, Input, Badge)
├── layout/ # Page structure (Header, Footer)
├── sections/ # Page sections (Hero, Services, Projects, etc.)
└── forms/ # Form-specific components
```
### State Management
- **Server state**: `useApi` hook (React Query pattern)
- **Local state**: `useState`, `useReducer`
- **Forms**: Controlled components with validation
- **No global store** (Redux/Zustand) — keep it simple
### Styling
- **Tailwind CSS** utility-first
- **Custom design system** in `tailwind.config.js`
- **CSS variables** for theming (dark mode ready)
- **Component variants** via `clsx` + `tailwind-merge`
### Adding Icons
```bash
# Use lucide-react (already installed)
import { IconName } from 'lucide-react'
# Or add to public/ and use <img>
```
---
## 🔧 Backend Architecture
### Clean Architecture Layers
```
cmd/server/ # Entry point, wiring
internal/
├── config/ # Configuration (YAML + env)
├── handler/ # HTTP layer (Gin)
├── middleware/ # Cross-cutting concerns
├── model/ # Domain models, DTOs
└── service/ # Business logic
```
### Dependency Injection
Services are instantiated in `main.go` and passed to handlers:
```go
skillService := service.NewSkillService()
h := handler.NewHandler(skillService, ...)
```
### Adding Database Support
1. Add DB config to `config.yaml`
2. Create `internal/repository/` package
3. Implement interfaces in `service/`
4. Use `database/sql` or `sqlx` or `gorm`
5. Add migrations
### Middleware Chain
```go
router.Use(
middleware.Recovery(), // Panic recovery
middleware.Logger(), // Request logging
middleware.SecurityHeaders(), // Security headers
middleware.CORS(...), // CORS
)
```
---
## 📝 Git Workflow
### Branch Naming
| Type | Pattern | Example |
|------|---------|---------|
| Feature | `feat/short-description` | `feat/contact-form-validation` |
| Fix | `fix/short-description` | `fix/cors-header-missing` |
| Docs | `docs/short-description` | `docs/update-api-docs` |
| Refactor | `refactor/short-description` | `refactor/service-layer` |
| Chore | `chore/short-description` | `chore/update-dependencies` |
### Commit Messages
Follow [Conventional Commits](https://www.conventionalcommits.org/):
```
feat: add contact form validation
fix: resolve CORS issue on production
docs: update API documentation
refactor: extract service interfaces
chore: update Go dependencies
```
### Pull Requests
1. Create feature branch from `main`
2. Make changes with tests
3. Run `make lint && make test`
4. Push and open PR
5. Require: CI passing, 1 approval
6. Squash merge to `main`
---
## 🐛 Debugging
### Backend Debugging
```bash
# Delve debugger
dlv debug ./cmd/server
# VS Code launch.json
{
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/server",
"env": {
"SERVER_MODE": "debug"
}
}
```
### Frontend Debugging
```bash
# React DevTools (browser extension)
# Redux DevTools (if using)
# VS Code debug config:
{
"type": "chrome",
"request": "launch",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/web/src"
}
```
### Database Debugging
```bash
# Connect to PostgreSQL
docker compose exec postgres psql -U postgres -d go_first
# Common queries
\dt # List tables
\d users # Describe table
SELECT * FROM skills; # Query data
```
---
## 📦 Dependency Management
### Go Dependencies
```bash
# Add dependency
go get github.com/new/package
# Update all
go get -u ./...
go mod tidy
# Check outdated
make check-deps
```
### Frontend Dependencies
```bash
# Add dependency
cd web && npm install package-name
# Add dev dependency
cd web && npm install -D package-name
# Update
cd web && npm update
# Audit
cd web && npm audit
```
---
## 🚀 Performance Tips
### Backend
- Use connection pooling (configured in config)
- Add Redis caching for expensive queries
- Enable gzip compression (NGINX)
- Use `pprof` for profiling: `import _ "net/http/pprof"`
### Frontend
- Code splitting (Vite does this automatically)
- Lazy load sections: `const Section = lazy(() => import('./Section'))`
- Optimize images (WebP, proper sizing)
- Use `React.memo` for expensive components
---
## 🔐 Environment Variables
### Required for Development
| Variable | Description | Default |
|----------|-------------|---------|
| `SERVER_MODE` | `debug` or `release` | `debug` |
| `DATABASE_HOST` | PostgreSQL host | `localhost` |
| `DATABASE_PASSWORD` | PostgreSQL password | `postgres` |
| `JWT_SECRET` | JWT signing key | `dev-secret` |
| `CORS_ALLOWED_ORIGINS` | Comma-separated origins | `http://localhost:3000,http://localhost:5173` |
### Optional
| Variable | Description |
|----------|-------------|
| `EMAIL_SMTP_*` | SMTP config for contact form emails |
| `LOGGING_LEVEL` | `debug`, `info`, `warn`, `error` |
| `REDIS_*` | Redis connection (for caching/sessions) |
---
## 📚 Resources
- [Go Project Layout](https://github.com/golang-standards/project-layout)
- [Effective Go](https://go.dev/doc/effective_go)
- [React Beta Docs](https://react.dev)
- [Tailwind CSS Docs](https://tailwindcss.com/docs)
- [Gin Framework](https://gin-gonic.com/docs/)
- [Zerolog](https://github.com/rs/zerolog)
- [Vite Guide](https://vitejs.dev/guide/)
---
## ❓ FAQ
**Q: How do I add a new API field?**
A: Update model → service → handler → frontend types → component
**Q: Why is my frontend not updating?**
A: Check Vite HMR, clear browser cache, check console for errors
**Q: How do I test email sending locally?**
A: Use mock email service (default) or configure Mailhog/SMTP
**Q: Can I use a different database?**
A: Yes, implement repository interface in `internal/repository/`
**Q: How do I deploy a preview environment?**
A: Use `make deploy-staging` or create PR preview with GitHub Actions