Skip to content

Repository files navigation

Haze API

GoPostgreSQLDockerZero DependenciesCI/CD

Admin scheduling & reminder backend API — built with zero framework dependencies. Pure Go stdlib net/http + pgx only.

🚀 Live:alpardfm.my.id/api/haze 📖 Swagger:alpardfm.my.id/api/haze/swagger


Highlights

  • Zero framework — pure net/http + pgx/v5, no Gin/Echo/Chi
  • Background workers — reminder scheduler + auto status updater
  • Overlap validation — prevents double-booking with time range checks
  • Computed statusscheduled → on_going → done based on real time
  • Unit tested — service layer, handlers, workers all tested with fake stores
  • Production deployed — running on VPS with Docker + CI/CD

Architecture

┌─────────────────────────────────────────────────────────┐
│ HTTP Layer │
│ net/http Router → Auth Middleware → Handler │
├─────────────────────────────────────────────────────────┤
│ Module Layer │
│ auth │ appointment │ publicschedule │ health │
│ Each module: handler → service (interface) → store │
├─────────────────────────────────────────────────────────┤
│ Worker Layer │
│ reminder-worker │ status-worker (one-shot commands) │
├─────────────────────────────────────────────────────────┤
│ Platform Layer │
│ database │ config │ shared/response │
├─────────────────────────────────────────────────────────┤
│ PostgreSQL │
└─────────────────────────────────────────────────────────┘

Design decisions:

  • Interface-based Store pattern — services depend on interfaces, not implementations
  • Dependency injection via struct fields — no DI container, no magic
  • Workers as separate binaries — can run independently or in Docker
  • Computed status — never stored stale, always derived from start_at/end_at vs now()

Tech Stack

LayerTechnology
LanguageGo 1.24
HTTPstdlib net/http (no framework)
DatabasePostgreSQL via pgx/v5
AuthHMAC token (crypto/hmac)
Passwordbcrypt (golang.org/x/crypto)
MigrationsRaw SQL files
ContainerDocker multi-stage build
CI/CDGitHub Actions → VPS deploy

Total direct dependencies: 2 (pgx/v5 + golang.org/x/crypto)


Project Structure

haze-api/
├── cmd/
│ ├── api/ # HTTP server entrypoint
│ ├── migrate/ # Database migration runner
│ ├── seed-admin/ # Initial admin seeder
│ ├── reminder-worker/ # Reminder notification scheduler
│ └── status-worker/ # Auto status updater (scheduled→on_going→done)
├── internal/
│ ├── appointment/ # Core domain: CRUD + overlap + computed status
│ ├── auth/ # Login, token, middleware, password hashing
│ ├── publicschedule/ # Public schedule checker (no sensitive data)
│ ├── worker/ # Reminder + status worker logic
│ ├── notification/ # Notification log model
│ ├── health/ # Health check handler
│ ├── config/ # Environment-based configuration
│ ├── database/ # PostgreSQL connection + migration runner
│ └── shared/response/ # JSON response helpers
├── migrations/ # SQL migration files
├── docs/ # OpenAPI spec + business rules
├── scripts/ # Deploy scripts
├── Dockerfile # Multi-stage build (all 5 binaries)
└── docker-compose.yml

API Endpoints

Auth

MethodPathDescription
POST/auth/loginAdmin login, returns HMAC token

Appointments (Protected)

MethodPathDescription
GET/appointmentsList appointments (filter: date, status)
POST/appointmentsCreate appointment (validates overlap)
GET/appointments/:idGet appointment detail
PUT/appointments/:idUpdate appointment
PATCH/appointments/:id/cancelCancel appointment (idempotent)

Public

MethodPathDescription
GET/public/schedules?date=YYYY-MM-DDOccupied time slots (no sensitive data)

System

MethodPathDescription
GET/healthLiveness + DB ping

Quick Start

Prerequisites

  • Go 1.24+
  • Docker & Docker Compose

1. Clone & Setup

git clone https://github.com/alpardfm/haze-api.git
cd haze-api
cp .env.example .env

2. Start Database

docker compose up -d postgres

3. Run Migrations

go run ./cmd/migrate

4. Seed Admin

go run ./cmd/seed-admin

5. Run API

go run ./cmd/api

API available at http://localhost:8080. Health check: GET /health.

6. Run Workers (optional)

go run ./cmd/reminder-worker # Run once: process due reminders
go run ./cmd/status-worker # Run once: update stale statuses

Testing

go test ./...

Tests use fake store implementations (no database required). Covered:

  • Appointment service: create, update, cancel (idempotent), list with computed status, overlap rejection
  • Auth handler & middleware
  • Public schedule service & handler
  • Worker: reminder slot calculation, anti-double-send
  • Shared response helpers

Business Rules

  • Fixed duration: 120 minutes per appointment (v1)
  • Overlap prevention: Create/update rejected if time range conflicts
  • Computed status:scheduledon_goingdone based on current time vs start_at/end_at
  • Cancel is idempotent: Cancelling an already-cancelled appointment returns success
  • Reminder: Configurable per appointment (reminder_start_at + interval_hours), anti-double-send via notification logs
  • Public checker: Only exposes occupied time slots, never client names or notes

Deployment

Production runs at alpardfm.my.id/api/haze via:

  1. Push/merge to master → GitHub Actions runs tests
  2. Code synced to VPS via rsync
  3. Docker containers rebuilt + restarted
  4. Migrations + admin seed run automatically

Related

  • haze-ui — React + TypeScript frontend for this API

License

MIT License. See LICENSE for details.

About

Admin scheduling & reminder API — zero framework, pure Go stdlib + pgx only.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages