Skip to content

Development Guide

This guide covers how to build features inside CoreAPI. All development happens in one of two places — a domain package or a shared package — and everything is wired together in main.go.


Top-level Structure

CoreAPI/
├── domain/       ← feature domains (your work goes here)
├── pkg/          ← shared packages used across domains
├── public/       ← static files served by Fiber
├── internal/     ← platform-level db models (do not modify)
├── main.go       ← wires everything together
└── setup.go      ← wires the ticketing stack (johorzoo domains)

main.go and setup.go are the only files that call db.GetDB() or db.GetZooDB(). Domains never reach out for a database connection themselves — it is always passed in.


Domains

Each feature lives in its own package under domain/. A domain owns its models, handlers, routes, and config. Domains do not import each other.

domain/
├── media/           ← reference domain — new pattern ✅
├── distribution/    ← reference domain — new pattern ✅
├── playback/        ← new pattern ✅
├── advertising/     ← being migrated
├── catalogue/       ← being migrated
├── spatial/         ← flat (old pattern)
├── provisioning/    ← flat (old pattern)
└── ...

When building something new, follow media or distribution. Do not copy from flat domains like spatial or provisioning.

Domain folder structure

domain/your-domain/
├── models.go              — GORM structs, TableName()
├── config.go              — env vars, read once via ConfigFromEnv()
├── validation.go          — input validation helpers (optional)
├── helper.go              — domain utilities (optional)
├── handlers/
│   ├── handler.go         — Handler struct + NewHandler()
│   └── handler_xxx.go     — HTTP methods on Handler
└── routes/
    ├── wire.go            — Setup() — the only function main.go calls
    └── routes.go          — registerRoutes() — internal

Shared Packages

Shared logic that is used across multiple domains lives in pkg/.

Package Purpose
pkg/db Database connections — GetDB(), GetZooDB(), RegisterModels()
pkg/middleware Protected(jwtService), HasRole(), HasAnyRole()
pkg/response Standard response envelope — OK, Error, Paginated
pkg/seed Dev seed data — one file per domain, called from Run()
pkg/storage SeaweedFS/S3 client
pkg/StreamerClient HTTP client for Castis Streamer nodes
pkg/jwt JWT service used by middleware

Key Rules

You develop inside a domain or pkg. Nothing else.

main.go wires your domain. You call your domain's Setup() from main.go and pass the database in. Your domain never fetches it.

Your domain's models.go drives the migration. Register your models in main.go via db.RegisterModels() before db.Init(). db.RunMigrationMain() picks them up on startup.

Seed data goes in pkg/seed. Add a file for your domain, add the seed call inside Run().

Middleware goes in routes/routes.go. Not in handlers. jwtService is passed through wire.go into registerRoutes.


How To

Question Page
How does AutoMigrate create my tables on startup? Migrations
How do I seed initial data for my domain? Seeding
How do I connect a new domain to CoreAPI? Domain Setup
How do I init the database and assign it to my domain? Database
How do I use middleware in my domain? Middleware
What are the recommended patterns? Patterns