Building a Fountain Service
A Fountain service is a runnable microservice scaffolded and validated against a fixed set of conventions. Those conventions are not just style preferences — they are machine-checked by ftkit verify, which walks the repository and reports every deviation as a warning or error. Building "to the Fountain standard" means structuring your code so that this verification passes.
What "Fountain standard" means
A standard-compliant service follows a layered architecture with a fixed directory structure. ftkit verify enforces it: it checks that the required directories exist, that main.go and server/server.go follow the expected bootstrap and lifecycle patterns, that controllers register themselves correctly, that handlers and DAOs obey their placement and naming rules, and that the codebase uses flog for logging. A repo that fails verification is, by definition, not a Fountain-standard service.
The required directories are server, biz, biz/core, and biz/dal. Everything else (biz/dal/dao, biz/dal/models, biz/dal/do, pkg, cmd, docs, scripts, …) is optional and verified only when present.
The layers
A Fountain service is organized into layers, each with a single responsibility, wired together from the entry point down to storage:
main.go → server/ → biz/core/ → biz/dal/ → pkg/ → <service>_client/
(servers) (controllers) (dao, (shared (generated
models, do) packages) client lib)main.go— the entry point. It bootstraps the framework withfountain.WithAppInstances(...)(orfountain.New()), constructs the server viaserver.NewServer(), and starts it with.Serving().server/— the transport and lifecycle layer. It defines theserverstruct, itsNewServer()constructor, the lifecycle methods (Initialize,Serving,Destroy,Info), route wiring (server/route.go), and the HTTP/gRPC handlers that translate requests into controller calls. It blank-imports_ ".../biz"so the business layer registers itself.biz/core/— the controllers, one package per business domain. Each controller implementscore.CoreController(InstallController(),RegisterCallback(...)), registers itself withRegisterCoreController(...), and holds the business logic for its domain. This is the only layer that should contain business rules.biz/dal/— the data access layer. It splits intodao/(data access objects and theirmanagers.goregistry),models/(persistence models for databases), anddo/(data objects used by the cache/Redis layer). DAOs are the only code that talks to a database, cache, or storage backend directly.pkg/— shared, reusable packages internal to the service that do not belong to any single layer (helpers, shared types, integrations).<service>_client/— a client library other services import to call this service. It exposes a typed client (client.go) so callers never hand-build requests.
Lifecycle & install order
The server struct implements the four lifecycle methods that the framework drives:
Initialize()— wires up every dependency the service needs (blocking, one-time).Serving()— runs the server; this is the blocking call that keeps the process up.Destroy()— releases resources on shutdown.Info()— returns metadata describing the server instance.
Inside Initialize(), dependencies must be installed in a specific order so that each step's prerequisites already exist. ftkit verify checks this order (only InstallCoreControllers — the controllers step — is strictly required; the rest are verified when present):
- logger —
Install logger - caches —
Install caches - databases —
Install databases - dao —
Install dao - clients —
Install clients - servers —
Install servers - controllers —
InstallCoreControllers(required) - handlers —
Install handlers
The logic is bottom-up: the logger comes first so everything can log; caches and databases come next; DAOs depend on those backends; clients and servers depend on DAOs; controllers are installed once their DAOs and clients exist; and handlers are wired last because they depend on the controllers they invoke.
Related
- Project Layout — the annotated directory tree.
- Standards Checklist — what
ftkit verifychecks. - ftkit CLI — the tool that scaffolds and verifies a service.