Standards Checklist
This checklist mirrors exactly what the ftkit CLI runs when you execute ftkit verify (alias ftkit v) at the root of a service repository. The command walks the repo, runs each check below in order, and prints a ✓ pass, a ⚠ warning, or a ✗ error for every assertion. It then exits non-zero if any check produces an error, so it can be wired into CI as a quality gate.
The verifier performs 20 checks in a fixed order. Each section below corresponds to one check, named with a human label and the underlying verifier function in parentheses, and lists what triggers a pass, a warning, or an error.
Checks
1. Project structure (verifyProjectStructure)
- Pass: each required directory exists (
server,biz,biz/core,biz/dal); each optional directory exists (biz/dal/dao,biz/dal/models,biz/dal/do,pkg,cmd,docs,scripts);go.modexists; andconfig.yamlorconfig.example.yamlexists. - Warning: an optional directory is missing, or no config file is found.
- Error: a required directory is missing, or
go.modis missing.
2. Main file (verifyMainFile)
Inspects main.go at the repo root.
- Pass:
main.godeclarespackage main; uses the fountain bootstrap pattern (.WithAppInstances,fountain.New(), orServing()); initializes a server instance (server.NewServer()/server.New); and calls.Serving(). - Warning: no
server.NewServer()pattern is found. - Error:
main.gois missing or unreadable; missingpackage main; missing the bootstrap pattern; or missing theServing()call.
3. Server structure (verifyServerStructure)
Parses server/server.go and checks the server lifecycle.
- Pass: the file has a blank import
_ ".../biz"; defines aserverstruct; hasfunc NewServer(); implements the lifecycle methodsInitialize(),Serving(),Destroy(),Info(); and a recognizable initialize order is detected. - Warning: the install order in
Initialize()is out of sequence relative to the recommended order (logger → caches → databases → dao → clients → servers → controllers → handlers). - Error:
server/server.gois missing/unparseable; missing blankbizimport; missingserverstruct; missingNewServer(); or any lifecycle method missing.
4. Route file (verifyRouteFile)
Inspects server/route.go.
- Pass:
initHTTPHandle()exists; API versioning (api/v*) is configured; one or more route groups (.Group() are present; and handler references (s.<Name>Handler.<method>) are found. - Warning:
server/route.gois missing; or any of the above patterns (initHTTPHandle,api/v*, route groups, handler references) is not found. - Error:
server/route.goexists but cannot be read.
5. Biz layer (verifyBizLayer)
Parses biz/biz.go and scans biz/core/.
- Pass:
biz.gohas blank imports for controller packages (biz/core/*); thebiz/core/directory exists; and one or more controller domains are found. - Warning: no blank controller imports in
biz.go; no domains underbiz/core/; or more domains than blank imports (a possible missing import). - Error:
biz/biz.gois missing/unparseable; orbiz/core/is missing/unreadable.
6. Controllers (verifyControllers)
Scans each domain under biz/core/ for the CoreController contract.
- Pass (per domain):
RegisterCoreController()is called;sync.Onceis used for the singleton;InstallController()is implemented; andRegisterCallback()is implemented (found either incontroller.goor another file in the domain). - Warning: no
controller.go/RegisterCoreControllerfile found in a domain;sync.Oncenot used; or no controller domains found at all. - Error: missing
RegisterCoreController(),InstallController(), orRegisterCallback()for a domain; orbiz/core/is missing/unreadable.
7. Controller file contents (verifyControllerFileContents)
Asserts each biz/core/*/controller.go contains only CoreController plumbing.
- Pass:
controller.godeclares onlyInstallController(),RegisterCallback(),AfterInstalledDone(),init(), and aGet<Name>ControllerInstance()accessor. - Warning:
biz/core/is missing; acontroller.gocannot be parsed; or nocontroller.gofiles are found to check. - Error: any other function or method is declared in
controller.go— business methods must be moved to a separate file.
8. Handlers (verifyHandlers)
Scans each domain under server/ for the handler layout.
- Pass (per domain): an
*_impl.gofile exists; its constructorNew*API()exists; the constructor receives[]core.CoreController; one or more<group>.<op>_handler.gofiles exist; and the impl file is named<domain>_impl.go. - Warning: missing
*_impl.go; noNew*API()constructor; constructor does not receive[]core.CoreController; no standard handler files; impl misnamed; or no handler domains found. - Error:
server/directory is missing/unreadable.
9. Handler single function (verifyHandlerSingleFunc)
Checks every *_handler.go file naming and that it holds exactly one handler.
- Pass: filename matches
{group}.{camelCase}_handler.goand the file contains exactly one receiver method (one handler). - Warning: the group segment does not match the directory name; a file cannot be parsed; a file has zero handler methods; or no handler files were found.
- Error: filename does not follow
{group}.{camelCase}_handler.go; the operation segment is not camelCase; or the file contains more than one handler method.
10. No route handlers in impl (verifyNoRouteHandlersInImpl)
Ensures *_impl.go files contain no route handlers (methods taking *fiber.Ctx).
- Pass: an
*_impl.gofile contains no method taking*fiber.Ctx. - Warning: an
*_impl.gofile cannot be parsed; or no*_impl.gofiles found. - Error: a method in
*_impl.gotakes*fiber.Ctx— route handlers must live in a*_handler.gofile, not in*_impl.go.
11. DAO layer (verifyDAOLayer)
Inspects biz/dal/ and the DAO directory structure.
- Pass:
biz/dal/dao/exists;dao/managers.goexists; it has cache/db/storage constants (*_CACHE/*_DB/*_STO); afunc init(); uses theRegisterDAOpattern; DAO type sub-directories are detected;biz/dal/models/exists; and model files are present. - Warning:
biz/dal/,biz/dal/dao/, orbiz/dal/models/missing;managers.gomissing; ormanagers.golacks constants,init(), or theRegisterDAOpattern. - Error: none (this check only passes or warns).
12. DAO import rules (verifyDAOImportRules)
Intended to enforce that DB DAOs import only models while cache DAOs may import both models and do.
- Pass:
biz/dal/dao/exists (the check is currently a no-op — see note). - Warning:
biz/dal/dao/does not exist, so the check is skipped. - Error: none. Note: the import-rule enforcement body is guarded by
if falseand is temporarily disabled, because some repos do not yet comply; it will be re-enabled after gradual migration. Today this check effectively does nothing beyond the directory-existence warning.
13. DAO ownership (verifyDAOOwnership)
Verifies each DAO type belongs to a single controller and is touched in a single file.
- Pass: a DAO type is referenced (as a struct field) by exactly one controller domain; and within a domain a DAO type is used in at most one non-
controller.gofile. - Warning:
biz/core/orbiz/dal/dao/is missing (check skipped); or no DAO types were found to check. - Error: a DAO type is used by more than one controller; or a domain interacts with a DAO across more than one file (besides
controller.go); orbiz/core/unreadable.
14. DAO type suffix in InstallController (verifyDAOTypeSuffixInInstallController)
Checks every dao.GetDAO[...] / f_dao.GetDAO[...] type argument inside InstallController().
- Pass: all
GetDAO[...]type parameters end withDAO,Cache, orSTO. - Warning:
biz/core/is missing; or noInstallController()was found to check. - Error: a
GetDAO[...]type parameter does not end inDAO,Cache, orSTO.
15. Logging usage (verifyLoggingUsage)
Walks biz/ and server/ to ensure only flog is used for logging.
- Pass: no forbidden logging imports (
log,log/slog,logrus,zap,zerolog,go-logging) and nofmt.Print*orlog.*calls used as logging. - Warning: none.
- Error: any forbidden logging import (non-blank), any
fmt.Print/Println/Printf, or anylog.*call (Print/Fatal/Panic family) outside comments — onlyflogis allowed.
16. No data structs in controller/DAO/handler (verifyNoDataStructs)
Ensures data structs live in biz/dal/do, not in controller, DAO, or handler files.
- Pass: no disallowed struct declarations. Allowed: in controller files, names ending in
Controller/DAO/Dao/Callback/Observer/API/Handler/Impl; in DAO files, names ending inDAO/Dao/Cache. - Warning: none.
- Error: a controller file declares a struct not matching the allowed suffixes; a DAO file declares a struct not matching
DAO/Cache; or a*_handler.gofile declares any struct (handler files must declare none).
17. Controller error returns (verifyControllerErrors)
Requires every exported controller function/method to return *froto.RpcError rather than the plain error type.
- Pass: no exported function/method under
biz/core/returns a plainerror. - Warning:
biz/core/does not exist (check skipped). - Error: an exported function/method returns the plain
errortype — it must return*froto.RpcError. (biz/core/unreadable is also an error.)
18. No interface params in controllers (verifyNoInterfaceParamsInControllers)
Forbids interface{} / any parameters in controller files, except controller.go.
- Pass: no function in
biz/core/*/(excludingcontroller.go) takes aninterface{}oranyparameter. - Warning:
biz/core/is missing; or no controller files (besidescontroller.go) were found. - Error: a controller function (outside
controller.go) takes an empty-interface parameter; orbiz/core/is unreadable.controller.gois exempt becauseRegisterCallback(cb any)is part of theCoreControllerinterface.
19. Pkg directory and client library (verifyPkgDirectory)
Inspects pkg/ and the generated client library <service>_client/.
- Pass:
pkg/exists; its packages are listed; the<service>_client/directory exists; and<service>_client/client.goexists. - Warning:
pkg/is missing; the client library directory is missing; orclient.goinside it is missing. - Error: none.
20. Go file headers (verifyGoFileHeaders)
Walks all non-generated .go files (skipping hidden dirs, vendor, bin, node_modules, docs, *.pb.go, *_test.go, and Code generated ... DO NOT EDIT files) and reports header coverage.
- Pass: reports how many files were checked and the percentage that carry the standard
/* !! ... * File:header. - Warning: lists files missing the header (capped at 10 names) and suggests running
ftkit header; also warns if no Go files were found. - Error: an error occurred while walking the Go files.
Result semantics
After running all checks, ftkit verify prints a summary with the number of passes, warnings, and errors, then decides the outcome:
- Errors > 0 → fail. The command prints the numbered list of errors to fix, prints "Repo chưa đạt chuẩn Fountain" (the repo is not standard-compliant), and exits with status code
1. This is what fails a CI gate. - Warnings only (no errors) → pass with caveats. The command reports that the repo is standard-compliant but has warnings worth reviewing, and exits
0. - No errors and no warnings → fully compliant. The command reports the repo is fully standard-compliant and exits
0.