32 KiB
1.1 Development Environment Setup - Detailed Implementation Plan
Overview
| Attribute | Value |
|---|---|
| Priority | CRITICAL |
| Duration | 2-3 days |
| Dependencies | None (first step) |
| Team Size | 1 developer |
Objectives
- Establish a reproducible development environment for all team members
- Configure Go multi-module monorepo structure
- Set up frontend workspace with proper tooling
- Create containerized local infrastructure (PostgreSQL, Redis, Zitadel)
- Implement consistent linting and formatting standards
- Document onboarding process
Task Breakdown
Task 1: Initialize Go Workspace (go.work)
Duration: 2-3 hours
1.1.1 Create Root go.work File
Create the Go workspace file at repository root to manage multiple modules.
File: /go.work
go 1.25
use (
./backend/services/game-session-service
./backend/services/question-bank-service
./backend/services/user-service
./backend/services/leaderboard-service
./backend/services/admin-service
./backend/services/gateway-service
./backend/shared
)
1.1.2 Initialize Each Service Module
For each service, create the go.mod file:
Directory Structure to Create:
backend/
├── go.work
├── services/
│ ├── game-session-service/
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── cmd/
│ │ └── main.go
│ ├── question-bank-service/
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── cmd/
│ │ └── main.go
│ ├── user-service/
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── cmd/
│ │ └── main.go
│ ├── leaderboard-service/
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── cmd/
│ │ └── main.go
│ ├── admin-service/
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── cmd/
│ │ └── main.go
│ └── gateway-service/
│ ├── go.mod
│ ├── go.sum
│ └── cmd/
│ └── main.go
└── shared/
├── go.mod
├── go.sum
└── .gitkeep
Example go.mod for game-session-service:
module knowfoolery/backend/services/game-session-service
go 1.25
require (
github.com/gofiber/fiber/v3 v3.0.0
knowfoolery/backend/shared v0.0.0
)
replace knowfoolery/backend/shared => ../../shared
Example go.mod for shared package:
module knowfoolery/backend/shared
go 1.25
require (
github.com/rs/zerolog v1.31.0
github.com/go-playground/validator/v10 v10.16.0
github.com/prometheus/client_golang v1.17.0
go.opentelemetry.io/otel v1.21.0
)
1.1.3 Create Stub Main Files
File: backend/services/game-session-service/cmd/main.go
package main
import (
"log"
"github.com/gofiber/fiber/v3"
)
func main() {
app := fiber.New(fiber.Config{
AppName: "Know Foolery - Game Session Service",
})
app.Get("/health", func(c fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "healthy", "service": "game-session"})
})
log.Fatal(app.Listen(":8080"))
}
Repeat for each service with appropriate port:
| Service | Port |
|---|---|
| game-session-service | 8080 |
| question-bank-service | 8081 |
| user-service | 8082 |
| leaderboard-service | 8083 |
| admin-service | 8085 |
| gateway-service | 8086 |
Verification Steps:
cd backend
go work sync
go build ./...
Task 2: Set Up Shared Packages Structure
Duration: 2-3 hours
1.2.1 Create Shared Package Directory Structure
backend/shared/
├── go.mod
├── go.sum
├── domain/
│ ├── errors/
│ │ ├── errors.go # Base error types
│ │ └── codes.go # Error code constants
│ ├── events/
│ │ ├── event.go # Event interface
│ │ └── contracts.go # Event type definitions
│ ├── types/
│ │ ├── id.go # ID type wrappers
│ │ ├── pagination.go # Pagination types
│ │ └── enums.go # Common enums
│ └── valueobjects/
│ ├── player_name.go # PlayerName value object
│ └── score.go # Score value object
└── infra/
├── auth/
│ ├── zitadel/
│ │ ├── client.go # Zitadel client
│ │ └── middleware.go # JWT middleware
│ └── rbac/
│ └── roles.go # Role definitions
├── database/
│ ├── postgres/
│ │ └── client.go # PostgreSQL connection factory
│ └── redis/
│ └── client.go # Redis connection factory
├── observability/
│ ├── logging/
│ │ └── logger.go # Zerolog setup
│ ├── tracing/
│ │ └── tracer.go # OpenTelemetry setup
│ └── metrics/
│ └── prometheus.go # Prometheus registration
├── security/
│ └── sanitize.go # Input sanitization
└── utils/
├── httputil/
│ ├── errors.go # HTTP error responses
│ ├── response.go # Standard response format
│ └── pagination.go # Pagination helpers
└── validation/
└── validator.go # Validation helpers
1.2.2 Create Placeholder Files
Create minimal placeholder implementations for each file to establish the structure.
File: backend/shared/domain/errors/errors.go
package errors
import "fmt"
// DomainError represents a domain-level error
type DomainError struct {
Code string
Message string
Err error
}
func (e *DomainError) Error() string {
if e.Err != nil {
return fmt.Sprintf("[%s] %s: %v", e.Code, e.Message, e.Err)
}
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}
func (e *DomainError) Unwrap() error {
return e.Err
}
// Common domain errors
var (
ErrNotFound = &DomainError{Code: "NOT_FOUND", Message: "Resource not found"}
ErrValidation = &DomainError{Code: "VALIDATION", Message: "Validation failed"}
ErrUnauthorized = &DomainError{Code: "UNAUTHORIZED", Message: "Unauthorized access"}
ErrConflict = &DomainError{Code: "CONFLICT", Message: "Resource conflict"}
ErrInternalServer = &DomainError{Code: "INTERNAL", Message: "Internal server error"}
)
File: backend/shared/infra/observability/logging/logger.go
package logging
import (
"os"
"time"
"github.com/rs/zerolog"
)
// NewLogger creates a new zerolog logger
func NewLogger(serviceName, environment string) zerolog.Logger {
zerolog.TimeFieldFormat = time.RFC3339Nano
var logger zerolog.Logger
if environment == "development" {
logger = zerolog.New(zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: "15:04:05",
}).With().Timestamp().Logger()
} else {
logger = zerolog.New(os.Stdout).With().Timestamp().Logger()
}
return logger.With().
Str("service", serviceName).
Str("environment", environment).
Logger()
}
Verification Steps:
cd backend/shared
go mod tidy
go build ./...
Task 3: Configure Linting (golangci-lint, ESLint)
Duration: 2-3 hours
1.3.1 Backend Linting (golangci-lint)
File: backend/.golangci.yml
run:
timeout: 5m
tests: true
go: "1.25"
linters:
enable:
- gofmt
- goimports
- govet
- errcheck
- staticcheck
- unused
- gosimple
- ineffassign
- typecheck
- gosec
- misspell
- lll
- unconvert
- dupl
- goconst
- gocyclo
- prealloc
- bodyclose
- noctx
- exhaustive
linters-settings:
lll:
line-length: 120
gocyclo:
min-complexity: 15
dupl:
threshold: 150
goconst:
min-len: 3
min-occurrences: 3
misspell:
locale: US
gosec:
excludes:
- G104 # Unhandled errors (we use errcheck)
issues:
exclude-rules:
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- path: cmd/main\.go
linters:
- gocyclo
max-issues-per-linter: 50
max-same-issues: 10
1.3.2 Frontend Linting (ESLint)
File: frontend/.eslintrc.json
{
"root": true,
"env": {
"browser": true,
"es2022": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:solid/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"solid"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-explicit-any": "warn",
"prefer-const": "error",
"no-var": "error",
"object-shorthand": "error",
"prefer-template": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }]
},
"ignorePatterns": [
"dist",
"node_modules",
"*.config.js",
"*.config.ts"
]
}
File: frontend/.prettierrc
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true
}
1.3.3 Editor Configuration
File: .editorconfig (repository root)
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.go]
indent_style = tab
indent_size = 4
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
Verification Steps:
# Backend
cd backend
golangci-lint run ./...
# Frontend
cd frontend
npx eslint . --ext .ts,.tsx
npx prettier --check .
Task 4: Create Docker Compose for Local Development
Duration: 3-4 hours
1.4.1 Development Docker Compose
File: infrastructure/dev/docker-compose.yml
version: "3.9"
services:
# PostgreSQL Database
postgres:
image: postgres:15-alpine
container_name: knowfoolery-postgres
environment:
POSTGRES_USER: knowfoolery
POSTGRES_PASSWORD: devpassword
POSTGRES_DB: knowfoolery
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U knowfoolery -d knowfoolery"]
interval: 10s
timeout: 5s
retries: 5
networks:
- knowfoolery-network
# Redis Cache
redis:
image: redis:7-alpine
container_name: knowfoolery-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- knowfoolery-network
# Zitadel Authentication (optional for initial setup)
zitadel:
image: ghcr.io/zitadel/zitadel:latest
container_name: knowfoolery-zitadel
command: start-from-init --masterkeyFromEnv --tlsMode disabled
environment:
ZITADEL_MASTERKEY: "MasterkeyNeedsToHave32Characters"
ZITADEL_DATABASE_COCKROACH_HOST: crdb
ZITADEL_EXTERNALSECURE: false
ZITADEL_FIRSTINSTANCE_ORG_NAME: "KnowFoolery"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME: "admin"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: "AdminPassword123!"
ports:
- "8080:8080"
depends_on:
crdb:
condition: service_healthy
networks:
- knowfoolery-network
profiles:
- auth
# CockroachDB for Zitadel
crdb:
image: cockroachdb/cockroach:latest
container_name: knowfoolery-crdb
command: start-single-node --insecure --http-addr :9090
ports:
- "26257:26257"
- "9090:9090"
volumes:
- crdb_data:/cockroach/cockroach-data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9090/health?ready=1"]
interval: 10s
timeout: 5s
retries: 10
networks:
- knowfoolery-network
profiles:
- auth
# Prometheus Metrics
prometheus:
image: prom/prometheus:latest
container_name: knowfoolery-prometheus
ports:
- "9091:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
networks:
- knowfoolery-network
profiles:
- observability
# Grafana Dashboards
grafana:
image: grafana/grafana:latest
container_name: knowfoolery-grafana
ports:
- "3001:3000"
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: admin
GF_USERS_ALLOW_SIGN_UP: false
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
depends_on:
- prometheus
networks:
- knowfoolery-network
profiles:
- observability
# Jaeger Tracing
jaeger:
image: jaegertracing/all-in-one:latest
container_name: knowfoolery-jaeger
ports:
- "16686:16686" # UI
- "14268:14268" # Collector HTTP
- "6831:6831/udp" # Agent
environment:
COLLECTOR_ZIPKIN_HOST_PORT: ":9411"
networks:
- knowfoolery-network
profiles:
- observability
volumes:
postgres_data:
redis_data:
crdb_data:
prometheus_data:
grafana_data:
networks:
knowfoolery-network:
driver: bridge
1.4.2 Database Initialization Script
File: infrastructure/dev/init-scripts/01-create-databases.sql
-- Create separate databases for each service
CREATE DATABASE IF NOT EXISTS game_sessions;
CREATE DATABASE IF NOT EXISTS questions;
CREATE DATABASE IF NOT EXISTS users;
CREATE DATABASE IF NOT EXISTS leaderboards;
CREATE DATABASE IF NOT EXISTS admin;
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE game_sessions TO knowfoolery;
GRANT ALL PRIVILEGES ON DATABASE questions TO knowfoolery;
GRANT ALL PRIVILEGES ON DATABASE users TO knowfoolery;
GRANT ALL PRIVILEGES ON DATABASE leaderboards TO knowfoolery;
GRANT ALL PRIVILEGES ON DATABASE admin TO knowfoolery;
1.4.3 Prometheus Configuration
File: infrastructure/dev/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'game-session-service'
static_configs:
- targets: ['host.docker.internal:8080']
metrics_path: /metrics
- job_name: 'question-bank-service'
static_configs:
- targets: ['host.docker.internal:8081']
metrics_path: /metrics
- job_name: 'user-service'
static_configs:
- targets: ['host.docker.internal:8082']
metrics_path: /metrics
- job_name: 'leaderboard-service'
static_configs:
- targets: ['host.docker.internal:8083']
metrics_path: /metrics
- job_name: 'gateway-service'
static_configs:
- targets: ['host.docker.internal:8086']
metrics_path: /metrics
1.4.4 Environment Variables
File: infrastructure/dev/.env
# Database
POSTGRES_USER=knowfoolery
POSTGRES_PASSWORD=devpassword
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=knowfoolery
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
# Zitadel (when auth profile is enabled)
ZITADEL_URL=http://localhost:8080
ZITADEL_PROJECT_ID=your-project-id
ZITADEL_CLIENT_ID=your-client-id
# Environment
ENVIRONMENT=development
LOG_LEVEL=debug
# Service Ports
GAME_SESSION_PORT=8080
QUESTION_BANK_PORT=8081
USER_SERVICE_PORT=8082
LEADERBOARD_PORT=8083
ADMIN_SERVICE_PORT=8085
GATEWAY_PORT=8086
Verification Steps:
cd infrastructure/dev
docker-compose up -d postgres redis
docker-compose ps
docker-compose logs postgres
Task 5: Initialize Frontend Workspace (Yarn Workspaces)
Duration: 2-3 hours
1.5.1 Root Package Configuration
File: frontend/package.json
{
"name": "knowfoolery-frontend",
"private": true,
"workspaces": [
"shared/*",
"apps/*"
],
"scripts": {
"dev": "yarn workspace @knowfoolery/web dev",
"build": "yarn workspaces foreach -A run build",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"format": "prettier --write .",
"format:check": "prettier --check .",
"test": "yarn workspaces foreach -A run test",
"clean": "yarn workspaces foreach -A run clean"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.0.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-solid": "^0.13.0",
"prettier": "^3.0.0",
"typescript": "^5.0.0"
},
"packageManager": "yarn@4.0.0"
}
1.5.2 Web Application Package
File: frontend/apps/web/package.json
{
"name": "@knowfoolery/web",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"test": "vitest",
"clean": "rm -rf dist node_modules/.vite"
},
"dependencies": {
"solid-js": "^1.9.0",
"@solidjs/router": "^0.10.0",
"@suid/material": "^0.16.0",
"@suid/icons-material": "^0.7.0"
},
"devDependencies": {
"vite": "^5.0.0",
"vite-plugin-solid": "^2.8.0",
"vitest": "^1.0.0",
"@solidjs/testing-library": "^0.8.0"
}
}
File: frontend/apps/web/vite.config.ts
import { defineConfig } from 'vite'
import solid from 'vite-plugin-solid'
export default defineConfig({
plugins: [solid()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8086',
changeOrigin: true,
},
},
},
build: {
target: 'esnext',
},
})
File: frontend/apps/web/tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["../../shared/*"]
}
},
"include": ["src"]
}
File: frontend/apps/web/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Know Foolery - Quiz Game</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
File: frontend/apps/web/src/main.tsx
import { render } from 'solid-js/web'
import App from './App'
import './styles/global.css'
const root = document.getElementById('root')
if (!root) {
throw new Error('Root element not found')
}
render(() => <App />, root)
File: frontend/apps/web/src/App.tsx
import type { Component } from 'solid-js'
const App: Component = () => {
return (
<div>
<h1>Know Foolery</h1>
<p>Quiz game coming soon...</p>
</div>
)
}
export default App
File: frontend/apps/web/src/styles/global.css
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
}
1.5.3 Shared UI Components Package
File: frontend/shared/ui-components/package.json
{
"name": "@knowfoolery/ui-components",
"private": true,
"version": "0.0.1",
"type": "module",
"main": "src/index.ts",
"scripts": {
"test": "vitest",
"build": "echo 'No build needed for shared package'",
"clean": "echo 'Nothing to clean'"
},
"dependencies": {
"solid-js": "^1.9.0",
"@suid/material": "^0.16.0"
},
"devDependencies": {
"vitest": "^1.0.0"
},
"peerDependencies": {
"solid-js": "^1.9.0"
}
}
File: frontend/shared/ui-components/src/index.ts
// UI Components barrel export
// Components will be added as they are developed
export {}
Verification Steps:
cd frontend
yarn install
yarn dev
# Open http://localhost:3000
Task 6: Create Makefile for Development Commands
Duration: 1-2 hours
File: Makefile (repository root)
.PHONY: help dev dev-full dev-auth dev-obs stop clean \
backend-lint backend-test backend-build \
frontend-lint frontend-test frontend-build \
db-up db-down db-logs db-shell redis-shell \
lint test build
# Default target
help:
@echo "KnowFoolery Development Commands"
@echo ""
@echo "Development Environment:"
@echo " make dev - Start core infrastructure (PostgreSQL, Redis)"
@echo " make dev-full - Start all infrastructure including observability"
@echo " make dev-auth - Start infrastructure with Zitadel auth"
@echo " make stop - Stop all containers"
@echo " make clean - Stop containers and remove volumes"
@echo ""
@echo "Backend:"
@echo " make backend-lint - Run Go linters"
@echo " make backend-test - Run Go tests"
@echo " make backend-build - Build all services"
@echo ""
@echo "Frontend:"
@echo " make frontend-dev - Start frontend dev server"
@echo " make frontend-lint - Run ESLint and Prettier"
@echo " make frontend-test - Run frontend tests"
@echo " make frontend-build - Build frontend for production"
@echo ""
@echo "Database:"
@echo " make db-logs - Show PostgreSQL logs"
@echo " make db-shell - Open PostgreSQL shell"
@echo " make redis-shell - Open Redis CLI"
@echo ""
@echo "All:"
@echo " make lint - Run all linters"
@echo " make test - Run all tests"
@echo " make build - Build everything"
# =============================================================================
# Development Environment
# =============================================================================
dev:
@echo "Starting core infrastructure..."
cd infrastructure/dev && docker-compose up -d postgres redis
@echo "Waiting for services to be healthy..."
@sleep 5
@echo ""
@echo "Infrastructure ready:"
@echo " PostgreSQL: localhost:5432 (user: knowfoolery, password: devpassword)"
@echo " Redis: localhost:6379"
dev-full: dev
@echo "Starting observability stack..."
cd infrastructure/dev && docker-compose --profile observability up -d
@echo ""
@echo "Observability ready:"
@echo " Prometheus: http://localhost:9091"
@echo " Grafana: http://localhost:3001 (admin/admin)"
@echo " Jaeger: http://localhost:16686"
dev-auth:
@echo "Starting full stack with authentication..."
cd infrastructure/dev && docker-compose --profile auth up -d
@echo ""
@echo "Zitadel ready at http://localhost:8080"
@echo "Admin credentials: admin / AdminPassword123!"
stop:
@echo "Stopping all containers..."
cd infrastructure/dev && docker-compose --profile auth --profile observability down
clean:
@echo "Stopping containers and removing volumes..."
cd infrastructure/dev && docker-compose --profile auth --profile observability down -v
# =============================================================================
# Backend
# =============================================================================
backend-lint:
@echo "Running Go linters..."
cd backend && golangci-lint run ./...
backend-test:
@echo "Running Go tests..."
cd backend && go test -v -race -cover ./...
backend-build:
@echo "Building all services..."
cd backend && go build ./...
# =============================================================================
# Frontend
# =============================================================================
frontend-dev:
@echo "Starting frontend development server..."
cd frontend && yarn dev
frontend-lint:
@echo "Running frontend linters..."
cd frontend && yarn lint && yarn format:check
frontend-test:
@echo "Running frontend tests..."
cd frontend && yarn test
frontend-build:
@echo "Building frontend..."
cd frontend && yarn build
# =============================================================================
# Database Utilities
# =============================================================================
db-logs:
cd infrastructure/dev && docker-compose logs -f postgres
db-shell:
docker exec -it knowfoolery-postgres psql -U knowfoolery -d knowfoolery
redis-shell:
docker exec -it knowfoolery-redis redis-cli
# =============================================================================
# Combined Commands
# =============================================================================
lint: backend-lint frontend-lint
@echo "All linters passed!"
test: backend-test frontend-test
@echo "All tests passed!"
build: backend-build frontend-build
@echo "Build complete!"
Task 7: Create Developer Onboarding Documentation
Duration: 1-2 hours
File: docs/DEVELOPMENT.md
# KnowFoolery Development Guide
## Prerequisites
Before you begin, ensure you have the following installed:
| Tool | Version | Installation |
|------|---------|--------------|
| Go | 1.25+ | https://go.dev/dl/ |
| Node.js | 20+ | https://nodejs.org/ or use nvm |
| Yarn | 4.x | `corepack enable` |
| Docker | 24+ | https://docs.docker.com/get-docker/ |
| Docker Compose | 2.x | Included with Docker Desktop |
| golangci-lint | latest | `go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest` |
## Quick Start
### 1. Clone the Repository
```bash
git clone https://gitea.paas.celticinfo.fr/oabrivard/knowfoolery.git
cd knowfoolery
2. Start Infrastructure
# Start PostgreSQL and Redis
make dev
# Or start everything including observability
make dev-full
3. Install Dependencies
# Backend
cd backend
go mod download
# Frontend
cd frontend
yarn install
4. Start Development Servers
Backend Services (run each in a separate terminal):
cd backend/services/game-session-service && go run cmd/main.go
cd backend/services/question-bank-service && go run cmd/main.go
# ... repeat for other services
Frontend:
cd frontend
yarn dev
5. Access the Application
- Web App: http://localhost:3000
- API Gateway: http://localhost:8086
- Prometheus (if running): http://localhost:9091
- Grafana (if running): http://localhost:3001
- Jaeger (if running): http://localhost:16686
Project Structure
knowfoolery/
├── backend/
│ ├── go.work # Go workspace file
│ ├── shared/ # Shared packages
│ └── services/ # Microservices
├── frontend/
│ ├── package.json # Yarn workspace root
│ ├── apps/ # Applications (web, cross-platform)
│ └── shared/ # Shared components
├── infrastructure/
│ └── dev/ # Docker Compose for local dev
├── docs/ # Documentation
└── Makefile # Development commands
Common Commands
| Command | Description |
|---|---|
make help |
Show all available commands |
make dev |
Start core infrastructure |
make dev-full |
Start infrastructure + observability |
make lint |
Run all linters |
make test |
Run all tests |
make stop |
Stop all containers |
make clean |
Stop containers and remove data |
Environment Variables
Copy the example environment file:
cp infrastructure/dev/.env.example infrastructure/dev/.env
Database Access
PostgreSQL
# Via make command
make db-shell
# Or directly
docker exec -it knowfoolery-postgres psql -U knowfoolery -d knowfoolery
Redis
# Via make command
make redis-shell
# Or directly
docker exec -it knowfoolery-redis redis-cli
Troubleshooting
Port Conflicts
If you get port conflict errors:
- Check what's using the port:
lsof -i :5432 - Stop the conflicting service or change ports in docker-compose.yml
Docker Memory Issues
If containers are slow or crashing:
- Increase Docker Desktop memory allocation (Settings > Resources)
- Recommended: 4GB+ RAM
Go Module Issues
cd backend
go work sync
go mod tidy
Frontend Build Issues
cd frontend
rm -rf node_modules
yarn cache clean
yarn install
IDE Setup
VS Code
Recommended extensions:
- Go (golang.go)
- ESLint
- Prettier
- Docker
- YAML
GoLand/IntelliJ
- Open the
backendfolder as your Go project - Enable "Go Modules integration"
- Set GOROOT to your Go 1.25+ installation
Contributing
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run linters:
make lint - Run tests:
make test - Commit with conventional commits:
git commit -m "feat: add new feature" - Push and create a PR
---
## Deliverables Checklist
| Deliverable | Status | Notes |
|-------------|--------|-------|
| Go workspace (go.work) | [ ] | Multi-module monorepo |
| Service module stubs | [ ] | 6 services with health endpoints |
| Shared packages structure | [ ] | domain/ and infra/ directories |
| golangci-lint config | [ ] | .golangci.yml |
| ESLint + Prettier config | [ ] | .eslintrc.json, .prettierrc |
| EditorConfig | [ ] | .editorconfig |
| Docker Compose (dev) | [ ] | PostgreSQL, Redis, optional stacks |
| Makefile | [ ] | Development commands |
| Developer documentation | [ ] | DEVELOPMENT.md |
---
## Verification Checklist
### Backend Verification
```bash
# 1. Go workspace builds
cd backend && go build ./...
# 2. Linter runs without config errors
cd backend && golangci-lint run ./...
# 3. All modules resolve correctly
cd backend && go work sync
Frontend Verification
# 1. Dependencies install
cd frontend && yarn install
# 2. Dev server starts
cd frontend && yarn dev
# 3. Linters pass
cd frontend && yarn lint
Infrastructure Verification
# 1. Docker Compose starts
cd infrastructure/dev && docker-compose up -d postgres redis
# 2. PostgreSQL is accessible
docker exec knowfoolery-postgres pg_isready -U knowfoolery
# 3. Redis is accessible
docker exec knowfoolery-redis redis-cli ping
Estimated Time Breakdown
| Task | Duration | Cumulative |
|---|---|---|
| Task 1: Go Workspace | 2-3 hours | 3 hours |
| Task 2: Shared Packages | 2-3 hours | 6 hours |
| Task 3: Linting Config | 2-3 hours | 9 hours |
| Task 4: Docker Compose | 3-4 hours | 13 hours |
| Task 5: Frontend Workspace | 2-3 hours | 16 hours |
| Task 6: Makefile | 1-2 hours | 18 hours |
| Task 7: Documentation | 1-2 hours | 20 hours |
| Buffer & Testing | 4 hours | 24 hours (3 days) |
Next Steps After Completion
Once this phase is complete, proceed to:
- Phase 1.2: Implement shared backend packages (errors, logging, metrics, tracing)
- Begin development of Question Bank Service (Phase 2.1)