initial commit
This commit is contained in:
commit
e7987e88a7
70 changed files with 13661 additions and 0 deletions
596
docs/DEVELOPMENT.md
Normal file
596
docs/DEVELOPMENT.md
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
# 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue