Skip to main content

Prerequisites

Before building BookMe, ensure you have:
  • Go 1.22+ installed
  • PostgreSQL 14+ running
  • Make installed (optional but recommended)
  • Environment variables configured (see .env.example)
The project uses Go 1.25.7 as specified in go.mod:3, but Go 1.22+ is the minimum requirement.

Quick Start

1

Install Dependencies

Download and install all Go dependencies:
make deps
This runs:
  • go mod download - Downloads dependencies
  • go mod tidy - Cleans up unused dependencies
2

Set Up Environment

Copy the example environment file:
cp .env.example .env
Edit .env with your configuration (see Environment Setup).
3

Run Database Migrations

Apply database schema:
goose -dir sql/schema postgres "your-db-url" up
4

Run the Server

Start the development server:
make run
Server starts at http://localhost:8080

Build Commands

Available Make Targets

The Makefile provides convenient commands for common tasks:
# Run with hot reload (requires air)
make dev

# Run without hot reload
make run

Detailed Build Process

Building the Binary

The build command is defined in Makefile:12-15:
make build
This creates a binary at bin/book-me. Run it directly:
./bin/book-me
The binary is self-contained and can be deployed to any Linux/macOS system with the same architecture. Make sure to include your .env file or set environment variables.

Running in Development

Standard Run

make run
Executes go run ./cmd/server, which compiles and runs the application.

Hot Reload Development

For automatic reloading on file changes:
  1. Install Air:
    go install github.com/cosmtrek/air@latest
    
  2. Run with hot reload:
    make dev
    
Air watches for file changes and automatically rebuilds the server.

Code Generation

SQLC - Type-Safe Database Queries

BookMe uses SQLC to generate Go code from SQL queries.

When to Regenerate

Run make sqlc after:
  • Adding new SQL queries in sql/queries/
  • Modifying existing queries
  • Changing database schema in sql/schema/

SQLC Workflow

1

Write SQL Query

Add your query to the appropriate file in sql/queries/:
sql/queries/users.sql
-- name: GetUserByID :one
SELECT * FROM users WHERE id = $1;
2

Generate Go Code

Run the generator:
make sqlc
3

Use Generated Code

SQLC creates type-safe functions in internal/database/:
user, err := db.GetUserByID(ctx, userID)
Generated files are committed to version control. This ensures consistent builds without requiring SQLC to be installed in production environments.

Code Formatting

Format Go Code

make fmt
Runs go fmt ./... to format all Go files according to standard conventions.

Linting

The project uses golangci-lint with strict rules defined in .golangci.yml:1-58. Run the linter:
golangci-lint run

Enabled Linters

The configuration includes:
  • errcheck - Checks for unchecked errors
  • govet - Reports suspicious constructs
  • staticcheck - Advanced analysis
  • gosec - Security issues
  • revive - Style and correctness
  • bodyclose - HTTP response body leaks
  • errorlint - Proper error handling
  • exhaustive - Missing switch cases
Test files have relaxed linting rules (.golangci.yml:51-54) to allow for more flexible testing patterns.

Build Configuration

Binary Output

Build configuration from Makefile:14:
go build -o bin/book-me ./cmd/api
Note: The Makefile references ./cmd/api, but the actual directory is ./cmd/server. If the build fails, update the Makefile to use the correct path.

Application Entry Point

The main function is in cmd/server/main.go:22-26:
func main() {
    if err := run(); err != nil {
        slog.Error("server failed", "error", err)
        os.Exit(1)
    }
}
The run() function handles:
  1. Configuration loading
  2. Logger initialization
  3. Database connection
  4. API setup
  5. HTTP server start
  6. Graceful shutdown

Environment-Specific Builds

Development Build

No special flags needed:
go build -o bin/book-me ./cmd/server

Production Build

Optimize binary size and disable debug info:
go build -ldflags="-s -w" -o bin/book-me ./cmd/server
Flags:
  • -s - Omit symbol table
  • -w - Omit DWARF debug info

Cross-Compilation

Build for different platforms:
# Linux AMD64
GOOS=linux GOARCH=amd64 go build -o bin/book-me-linux ./cmd/server

# macOS ARM64 (M1/M2)
GOOS=darwin GOARCH=arm64 go build -o bin/book-me-mac ./cmd/server

Dependencies

Core Dependencies

From go.mod:5-18:
PackagePurpose
github.com/golang-jwt/jwt/v5JWT authentication
github.com/lib/pqPostgreSQL driver
github.com/joho/godotenvEnvironment variables
github.com/go-playground/validator/v10Input validation
github.com/wneessen/go-mailEmail sending
golang.org/x/oauth2OAuth2 client
google.golang.org/apiGoogle Calendar API
golang.org/x/timeRate limiting
github.com/hashicorp/go-retryablehttpRetry logic
github.com/gorilla/sessionsSession management

Installing Dependencies

All dependencies are defined in go.mod. Install with:
go mod download
Update to latest versions:
go get -u ./...
go mod tidy

Troubleshooting

Common Build Issues

The Makefile references the wrong path. Update Makefile:14:
- go build -o bin/book-me ./cmd/api
+ go build -o bin/book-me ./cmd/server
Check:
  1. PostgreSQL is running
  2. DB_URL in .env is correct
  3. Database exists and migrations are applied
Test connection:
psql "your-db-url"
Ensure SQLC is installed:
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
Verify sqlc.yaml configuration is correct.
The server will fail if required env vars are missing. Check internal/config/config.go for required fields.Copy and configure:
cp .env.example .env

Docker Build (Optional)

While not included in the repository, you can create a Dockerfile:
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -ldflags="-s -w" -o bin/book-me ./cmd/server

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/bin/book-me .
COPY --from=builder /app/.env .
EXPOSE 8080
CMD ["./book-me"]
Build and run:
docker build -t bookme:latest .
docker run -p 8080:8080 bookme:latest

Next Steps

Build docs developers (and LLMs) love