Skip to content

Projects · Used at work · 2026

svcgen

A CLI that scaffolds a production-shaped Go service in one command and keeps extending it: fx wiring, Fiber router, optional Postgres, Redis and partner clients, Dockerfile, GitLab CI and Sonar config. Used at Icon Plus to start new integrator services.

Go · Fiber · fx · GitLab CI

Source

Problem

Every new integrator service at work started as a copy of the last one. Folder layout drifted, CI files diverged, and the first day of a new service went to boilerplate instead of the integration itself.

What I built

svcgen generates a service with the structure the team already runs in production, then adds to it over time: `svcgen new` for the project, `svcgen add external` for a partner client, `svcgen add feature` for a router + controller + usecase + DTO wired into fx.

Architecture

  • cmd/svcgenCLI entrypoint with interactive prompts that can also be piped for CI
  • internal/generator/templatestext/template files embedded in the binary; generated Go is gofmt-ed
  • Generated servicefx modules for router, controller, usecase, repository; Fiber HTTP; config from YAML + env
  • external/<partner>HTTP client with SUCCESS / PENDING / FAILED classification and timeout mapping
  • /healthzliveness probe outside /api/v1 with version and uptime, for Kubernetes

Decisions and trade-offs

  1. 01

    Generate the shape of production, not a toy

    The templates mirror a service already running at work (Dockerfile, .gitlab-ci.yml, sonar-project.properties, request filter for signature headers), so a generated repo is deployable on day one instead of being a starting point to rewrite.

  2. 02

    Leave no trace in the generated repo

    The generated project has no svcgen markers. `svcgen add` inserts code by recognising stable anchors in the existing structure (`fx.Provide(`, `var serviceCodeByPath`), which keeps the output readable for people who never use the tool, at the cost of a few names that must not be renamed.

  3. 03

    Opt-in dependencies at generation time

    Postgres, Redis and partner clients are questions, not defaults. A service that does not need a database runs without one, and data sources can still be switched on later through env, so the generator never forces infrastructure a service does not use.

  4. 04

    Classify partner responses explicitly

    Every generated partner client maps responses to SUCCESS, PENDING or FAILED and turns timeouts into a typed error. Payment-style integrations are mostly about handling the ambiguous middle, so the client makes that state visible instead of hiding it in an HTTP status.

Evidence

  • Template changes are verified by `go test ./...` plus generating a throwaway service and building it.
  • Prompts accept piped answers (`printf 'y\nn\ny' | svcgen new my-svc`) so CI can generate services unattended.
  • Used at Icon Plus for new integrator services; the README documents the private module path the generated code depends on.

Status · Actively used and extended