Skip to content

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.mod exists; and config.yaml or config.example.yaml exists.
  • Warning: an optional directory is missing, or no config file is found.
  • Error: a required directory is missing, or go.mod is missing.

2. Main file (verifyMainFile)

Inspects main.go at the repo root.

  • Pass: main.go declares package main; uses the fountain bootstrap pattern (.WithAppInstances, fountain.New(), or Serving()); initializes a server instance (server.NewServer() / server.New); and calls .Serving().
  • Warning: no server.NewServer() pattern is found.
  • Error: main.go is missing or unreadable; missing package main; missing the bootstrap pattern; or missing the Serving() call.

3. Server structure (verifyServerStructure)

Parses server/server.go and checks the server lifecycle.

  • Pass: the file has a blank import _ ".../biz"; defines a server struct; has func NewServer(); implements the lifecycle methods Initialize(), 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.go is missing/unparseable; missing blank biz import; missing server struct; missing NewServer(); 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.go is missing; or any of the above patterns (initHTTPHandle, api/v*, route groups, handler references) is not found.
  • Error: server/route.go exists but cannot be read.

5. Biz layer (verifyBizLayer)

Parses biz/biz.go and scans biz/core/.

  • Pass: biz.go has blank imports for controller packages (biz/core/*); the biz/core/ directory exists; and one or more controller domains are found.
  • Warning: no blank controller imports in biz.go; no domains under biz/core/; or more domains than blank imports (a possible missing import).
  • Error: biz/biz.go is missing/unparseable; or biz/core/ is missing/unreadable.

6. Controllers (verifyControllers)

Scans each domain under biz/core/ for the CoreController contract.

  • Pass (per domain): RegisterCoreController() is called; sync.Once is used for the singleton; InstallController() is implemented; and RegisterCallback() is implemented (found either in controller.go or another file in the domain).
  • Warning: no controller.go / RegisterCoreController file found in a domain; sync.Once not used; or no controller domains found at all.
  • Error: missing RegisterCoreController(), InstallController(), or RegisterCallback() for a domain; or biz/core/ is missing/unreadable.

7. Controller file contents (verifyControllerFileContents)

Asserts each biz/core/*/controller.go contains only CoreController plumbing.

  • Pass: controller.go declares only InstallController(), RegisterCallback(), AfterInstalledDone(), init(), and a Get<Name>ControllerInstance() accessor.
  • Warning: biz/core/ is missing; a controller.go cannot be parsed; or no controller.go files 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.go file exists; its constructor New*API() exists; the constructor receives []core.CoreController; one or more <group>.<op>_handler.go files exist; and the impl file is named <domain>_impl.go.
  • Warning: missing *_impl.go; no New*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.go and 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.go file contains no method taking *fiber.Ctx.
  • Warning: an *_impl.go file cannot be parsed; or no *_impl.go files found.
  • Error: a method in *_impl.go takes *fiber.Ctx — route handlers must live in a *_handler.go file, not in *_impl.go.

11. DAO layer (verifyDAOLayer)

Inspects biz/dal/ and the DAO directory structure.

  • Pass: biz/dal/dao/ exists; dao/managers.go exists; it has cache/db/storage constants (*_CACHE/*_DB/*_STO); a func init(); uses the RegisterDAO pattern; DAO type sub-directories are detected; biz/dal/models/ exists; and model files are present.
  • Warning: biz/dal/, biz/dal/dao/, or biz/dal/models/ missing; managers.go missing; or managers.go lacks constants, init(), or the RegisterDAO pattern.
  • 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 false and 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.go file.
  • Warning: biz/core/ or biz/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); or biz/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 with DAO, Cache, or STO.
  • Warning: biz/core/ is missing; or no InstallController() was found to check.
  • Error: a GetDAO[...] type parameter does not end in DAO, Cache, or STO.

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 no fmt.Print* or log.* calls used as logging.
  • Warning: none.
  • Error: any forbidden logging import (non-blank), any fmt.Print/Println/Printf, or any log.* call (Print/Fatal/Panic family) outside comments — only flog is 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 in DAO/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.go file 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 plain error.
  • Warning: biz/core/ does not exist (check skipped).
  • Error: an exported function/method returns the plain error type — 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/*/ (excluding controller.go) takes an interface{} or any parameter.
  • Warning: biz/core/ is missing; or no controller files (besides controller.go) were found.
  • Error: a controller function (outside controller.go) takes an empty-interface parameter; or biz/core/ is unreadable. controller.go is exempt because RegisterCallback(cb any) is part of the CoreController interface.

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.go exists.
  • Warning: pkg/ is missing; the client library directory is missing; or client.go inside 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.