forge

package module
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 8 Imported by: 0

README

GoForge

GoForge is an opinionated, batteries-included Go application framework for developers who value Laravel, Symfony, Rails, or Spring ergonomics but want the result to remain unmistakably Go.

Its contract is simple:

  • Generate source, do not conceal it. Routes, controllers, requests, configuration, and migrations are ordinary files in the application.
  • Build on the standard library. The HTTP kernel is net/http; persistence is database/sql; dependencies are constructor parameters.
  • Fail at startup. Typed configuration reports all invalid values together.
  • Keep every exit visible. Use a standard http.Handler, *sql.DB, custom middleware, or a hand-built server whenever the defaults stop fitting.
  • Prefer boring production behavior. Request IDs, structured logs, panic recovery, secure headers, body limits, graceful shutdown, and reversible SQL migrations are first-class.

Status

The current checkout is the accepted v0.20.0 personal-API-token release. Fresh format-14 applications intentionally pin the published v0.19.0 runtime without a local replace because the token workflow adds application-owned source and requires no new runtime package. GoForge includes explicit database wiring, parallel JSON and server-rendered authentication, database-backed sessions, CSRF-protected HTML forms, production middleware, embedded migrations, owner-scoped JSON and HTML CRUD generation, a reflection-free typed ORM, a static Go-model parser, deterministic mapping generation, explicit eager-loaded relationships, and ORM-backed fresh scaffolds/resources. Its positioned .forge.html compiler adds static components, strict props and slots, control directives, page-local stacks, explicit form helpers, application-owned functions, and source-mapped diagnostics while emitting ordinary html/template. The API can still change before v1. Durable typed jobs add transactional dispatch, delays, active deduplication, bounded PostgreSQL workers, lease fencing and crash recovery, finite retries, failed-job operations, and structured payload-free lifecycle events without hidden worker startup or handler discovery. Its explicit request boundary adds typed composable validation, exact JSON/form failure semantics, bounded HTTP timeouts and headers, correlated completion logs, validated CORS and security policy, trusted-proxy parsing, and PostgreSQL authentication throttles shared across processes and restarts. Newly generated format-13 and format-14 resources own a typed action/access function shared by their JSON and browser controllers. Owner-only remains the default; application code can explicitly grant all-record access or deny an action, while repositories apply the derived scope in the same SQL statement as every read and mutation. Account integrity now includes JSON and browser password change, transparent hash upgrades, immediate cross-process session revocation, and independently configured idle and absolute session lifetimes. Credential writes are ordinary application-owned compare-and-swap SQL, and stale concurrent requests cannot restore an old password or overwrite a winning rotated browser session. The v0.9 developer-loop milestone is accepted. It adds opinionated, non-mutating forge test and forge build gates while retaining the underlying Go commands as complete escape hatches. The v0.10 development server closes the compiled-view edit loop: forge serve watches application inputs, builds and checks candidate liveness off-port, and promotes only a live replacement while preserving the last-good server through invalid edits. The v0.11 resource generator accepts ordered typed scalar fields and emits a complete owner-scoped JSON and browser CRUD slice as ordinary Go, SQL, and Forge templates. Required and nullable string, text, integer, and boolean semantics remain explicit from transport decoding through PostgreSQL, and new schema-driven resources require optimistic versions on every update. The v0.12 account-recovery workflow adds browser and JSON forgot/reset routes, single-use hashed reset tokens, immediate session revocation, application-owned text and Forge HTML mail, an encrypted durable outbox, and an explicit SMTP adapter. Generated applications own the routes, policy, SQL, templates, jobs, and dependency wiring; every boundary remains replaceable ordinary Go. The v0.13 resource workflow adds repeatable required belongs-to generation across ordinary models, composite owner-safe PostgreSQL constraints, exact JSON and form input, eager-loaded repositories, bounded browser choices, Forge views, and generated tests. Missing and cross-owner targets are deliberately indistinguishable, while direct SQL and handwritten relationship code remain complete escape hatches. The v0.14 runtime adds explicit versioned recurring schedules that atomically materialize typed jobs through PostgreSQL. It defines strict five-field cron, IANA civil time and DST behavior, bounded misfire coalescing, conservative active-job overlap suppression, fail-closed definition fingerprints, competing-process row coordination, read-only inspection, and payload-free observers. Fresh format-11 through format-14 scaffolds own the schedule registry, PostgreSQL migration, isolated configuration, scheduler process, inspection command, and direct Go escape hatches. The v0.16.0 release pinned the immutable public v0.14.2 runtime and demonstrated its cancellation-aware dynamic schedule factory; format 12 pins v0.17.0 because its embedded package uses the new public asset runtime. The v0.14.2 runtime added cancellation-aware dynamic schedule factories, dependency-free validation between generated schedule and worker registries, and deterministic password-recovery equalization acceptance without runtime discovery. The v0.15 CLI composes the watched server, durable worker, and recurring scheduler behind one labelled, truthful development lifecycle. The v0.16 release closes the server-rendered browser loop with a randomized same-origin client and committed-generation SSE while keeping all reload machinery outside generated and production application code. The v0.17 release gives fresh applications an ordinary embedded CSS/JavaScript package, explicit route and Forge asset helper. Direct Go builds contain the exact application-owned bytes; stable URLs use strong ETags and mandatory revalidation without a hidden asset build. Rolling deployments must keep same-path asset changes backward compatible or use stickiness until retained generations provide exact HTML and asset version consistency.

The v0.19 release adds an empty-directory domain-model workflow. Its additive make:model field and belongs-to options turn the existing typed Data Mapper into a complete empty-directory domain-model workflow while keeping format 13, the published runtime contract, and the legacy no-option command compatible.

The v0.20 release gives fresh format-14 applications named, expiring personal API tokens. Session-authenticated users create and revoke them through ordinary JSON controllers or the CSRF-protected account-security page; the raw value is shown once and PostgreSQL retains only its selector and SHA-256 digest. Strict Bearer authentication feeds the existing auth.User, resource policy, and SQL scope without adding token permissions or JWT claims. See the personal API token guide.

Install and try it

Install the released CLI and generate an application:

go install github.com/ShanilKoshitha/goforge/cmd/forge@v0.20.0
forge new myapp --module example.com/myapp
cd myapp
docker compose up -d
forge make:resource Issue
forge migrate
# For plain-HTTP development, set APP_ENV=local and APP_URL=http://localhost:8080 in .env.
forge dev

For framework development from this checkout:

go install ./cmd/forge
forge new myapp --module example.com/myapp --replace /path/to/goforge
cd myapp
docker compose up -d
forge make:resource Issue
forge migrate
forge test
forge build
# For plain-HTTP development, set APP_ENV=local and APP_URL=http://localhost:8080 in .env.
forge dev

Generated projects retain APP_ENV=production in .env, which keeps session cookies HTTPS-only. Change it to APP_ENV=local and set APP_URL=http://localhost:8080 only for local plain-HTTP development, before running forge dev, forge serve, or the worker. Never use APP_ENV=local in a deployed process because it disables secure cookies.

Visit http://localhost:8080/register for the browser workflow or http://localhost:8080/health for liveness. Readiness, including PostgreSQL and expected migration state, is available at http://localhost:8080/ready. Password recovery starts at http://localhost:8080/forgot-password; delivered development mail is visible in Mailpit at http://localhost:8025.

The generated request path

cmd/server/main.go
  -> internal/config.Load()       explicit typed environment
  -> internal/application.New()   explicit dependency construction
  -> routes.Register()            complete searchable route table
  -> controller method            normal Go function
  -> httpx.Context                thin request/response convenience

There is no annotation scanning, reflection-driven container, global application state, hidden route discovery, or ORM query language.

CLI (v0.20.0)

The command surface below describes this checkout. Fresh applications use format 14 while pinning the public v0.19.0 runtime; personal tokens, authorization, and model generation are generated application code and need no new runtime package. Install v0.20.0 for the accepted release, or go install ./cmd/forge when evaluating the current source checkout.

forge new <directory> [--module <path>] [--replace <goforge-path>]
forge dev
forge serve
forge test
forge build
forge assets:check
forge migrate
forge views:compile
forge orm:generate [--check]
forge make:model <name> [--field <name>:<type>[:required|nullable]]... [--belongs-to <name>:<ExistingModel>]...
forge make:resource <name> [--field <name>:<type>[:required|nullable]]... [--belongs-to <name>:<ExistingResource>]...
forge make:controller <name>
forge make:request <name>
forge make:migration <name>
forge make:job <name>
forge make:mail <name>
forge queue:work
forge queue:failed
forge queue:retry <id|--all>
forge queue:forget <id>
forge schedule:list
forge schedule:run
forge schedule:work

The spaced forms (forge make controller Users) also work. Generators never overwrite existing files.

Standalone typed models accept the same repeatable field grammar and can refer to an existing model with --belongs-to. They generate ordinary Go, paired SQL migrations, and the typed store without adding HTTP or authorization policy. See the typed ORM guide for copyable CRUD, relationship, transaction, and handwritten-SQL examples.

Typed resources accept repeated fields in declaration order:

forge make:resource Issue \
  --field title:string \
  --field notes:text:nullable \
  --field priority:integer:required \
  --field active:boolean

The field grammar is <name>:<string|text|integer|boolean>[:required|nullable]. Fields are required by default. Calling make:resource without --field retains the legacy required name:string resource and its versionless-update compatibility. Supplying any explicit field—even --field name:string—selects schema-driven output whose JSON and browser updates require a positive optimistic version. Field descriptions are one-shot generation input; the generated application contains ordinary static Go, SQL, and HTML rather than a runtime schema. Updates replace the complete writable resource: a missing, null, or empty nullable value clears that column to SQL NULL, while numeric 0 and boolean false remain present values.

Format-10 through format-14 applications can generate a required owner-scoped relationship to an existing resource:

forge make:resource Category --field name:string
forge make:resource Issue \
  --field title:string \
  --belongs-to category:Category

The relationship description is also one-shot input. Generated Go owns the protected foreign key, association value, validation, eager loading, browser choices, and presentation; generated SQL owns the composite owner/target constraint. No relationship registry or runtime schema is added.

Format-13 and format-14 resources also own authorization.go. Its AuthorizeFunc receives a typed list, create, view, update, or delete action and returns denied, owner, or all-record access. Authorize is the editable owner-only default, and the same function is visibly injected into both controllers in routes/resources_gen.go. Denied authenticated actions return 403 before repository work. Owner-scoped missing and cross-owner records both return 404. Repository update and delete queries include the validated scope directly, so authorization is not a fetch-then-write race. Edit this ordinary Go file, inject another function, or replace the controller/repository wiring when the closed scope is insufficient.

forge test and forge build are intentionally no-argument defaults for format-4 through format-14 projects. Both non-mutating preflights check the generated ORM first, compiled views second, and format-12-or-newer embedded assets third. Testing then runs exactly go test ./.... Building stages a trimmed ./cmd/server executable and publishes it atomically as bin/app on Unix or bin/app.exe on Windows, so a failed build does not replace the last-good binary.

The exact direct escape hatches are:

forge orm:generate --check
forge views:compile --check
forge assets:check
go test ./...
go build -trimpath -o bin/app ./cmd/server
go build -trimpath -o bin/scheduler ./cmd/scheduler
go run ./cmd/server
go run ./cmd/scheduler --once

Use direct Go commands for custom packages, flags, tags, targets, output paths, or worker and console builds. forge dev is the complete format-11-through-14 development default: it labels and supervises forge serve, the application-owned worker, and the scheduler under one cancellation boundary, and reports ready only after all three startup contracts succeed. Any service exit stops its peers. It does not start PostgreSQL or Mailpit, apply migrations, or change configuration. The supervisor allows 20 seconds for graceful process-tree shutdown by default. If an application configures a longer server or worker drain, export FORGE_DEV_SHUTDOWN_TIMEOUT with a longer Go duration before starting the CLI; this outer timeout must exceed the longest application shutdown timeout.

forge serve remains the HTTP-only watched development command; it compiles application-owned views, stages ordinary server binaries outside the repository, health-checks them on private loopback addresses, and switches its stable public proxy only after success. Invalid view or Go source leaves the last-good server reachable and recovers on the next correction. Eligible full HTML browser navigations receive one randomized same-origin external client and reload automatically only after a replacement is fully committed. The proxy preserves application CSP and cookies and leaves compressed, streamed, ranged, downloadable, no-transform, and non-document responses untouched. Promotion proves /health liveness, not /ready database or migration readiness; run forge migrate explicitly after SQL changes.

PID-verified candidate promotion is batteries-included on Linux, Windows, and macOS. AIX, DragonFly BSD, FreeBSD, illumos, iOS, NetBSD, OpenBSD, and Solaris use the system lsof command for the same check. Where that utility is absent, use the exact one-shot escape hatch go run ./cmd/server.

forge test, forge build, and forge serve never start external services, apply migrations, generate a stale ORM, modify .env, or start workers. forge dev starts only the three application processes; background-process source changes require restarting that one command. Format-12 asset files below resources/assets/files participate in the watched server's last-good rebuild and committed browser reload. Asset transforms, HMR, external publication, and environment diagnosis remain separate milestones.

Framework packages

  • forge: application lifecycle and graceful shutdown
  • asset: bounded immutable embedded files, canonical URLs, strong validators, byte ranges, and deterministic media policy through standard http.Handler
  • httpx: routing, JSON binding, errors, middleware, and net/http adapters
  • config: typed environment and optional dotenv loading
  • validation: fluent validation without reflection
  • cache: cache contracts, typed JSON helpers, and an in-memory store
  • view: .forge.html compilation to inspectable, contextually escaped standard-library templates
  • web: buffered browser sessions, CSRF, flash-safe responses, and redirects
  • session: signed-ID server-side sessions with flash data and swappable storage
  • security/ratelimit: bounded authentication throttling with a replaceable store
  • database: transaction helper over database/sql
  • database/migrate: paired SQL migrations; PostgreSQL runs are advisory-locked and transactionally applied when the migration SQL is transaction-safe. MySQL DDL may commit implicitly and is not promised to be atomic.
  • orm: typed, inspectable PostgreSQL builders, mappings, partial fields, optimistic guards, bulk inserts, and explicit batched relationships over ordinary *sql.DB or *sql.Tx executors
  • orm/postgres: disclosure-safe PostgreSQL constraint and retryable-error classification that preserves native causes
  • job: typed definitions, explicit registries, dispatch policy, at-least-once worker lifecycle, retry semantics, and replaceable store/observer contracts
  • job/postgres: parameterized durable queue storage with database-clock claims, SKIP LOCKED, leases, generation fencing, and failed-job operations

See docs/philosophy.md for design constraints and docs/building-an-app.md for the end-to-end workflow. Developers arriving from full-stack ecosystems can use docs/framework-map.md as a concept-by-concept translation. See docs/jobs.md for the durable-jobs contract and operating workflow.

See CONTRIBUTING.md for code conventions, template ownership, and verification, and docs/CODE_QUALITY.md for the repository quality assessment.

Documentation

Overview

Package forge provides the small application kernel used by GoForge projects. Everything below it is ordinary net/http, database/sql, and explicit Go code.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	Router *httpx.Router
	// contains filtered or unexported fields
}

func New

func New(config Config) *App

func NewChecked

func NewChecked(config Config) (*App, error)

NewChecked validates explicit lifecycle limits before applying defaults. Generated applications use it so invalid environment values fail before the server starts. New remains source-compatible for pre-v0.7 callers.

func (*App) Handler

func (app *App) Handler() http.Handler

func (*App) Run

func (app *App) Run(ctx context.Context) error

Run serves until the context is cancelled. Applications that need different server behavior can ignore Run and pass app.Handler() to their own http.Server.

type Config

type Config struct {
	Address           string
	ShutdownTimeout   time.Duration
	ReadHeaderTimeout time.Duration
	ReadTimeout       time.Duration
	WriteTimeout      time.Duration
	IdleTimeout       time.Duration
	MaxHeaderBytes    int
	Logger            *slog.Logger
}

Directories

Path Synopsis
Package asset serves a bounded set of application assets from an fs.FS.
Package asset serves a bounded set of application assets from an fs.FS.
Package cache defines a deliberately small cache contract and an in-process implementation.
Package cache defines a deliberately small cache contract and an in-process implementation.
cmd
forge command
Package config provides explicit, typed environment configuration without reflection.
Package config provides explicit, typed environment configuration without reflection.
Package database adds small, explicit helpers around database/sql.
Package database adds small, explicit helpers around database/sql.
migrate
Package migrate applies paired .up.sql and .down.sql files using database/sql.
Package migrate applies paired .up.sql and .down.sql files using database/sql.
Package httpx provides error-returning handlers and explicit middleware around the standard library HTTP server and router.
Package httpx provides error-returning handlers and explicit middleware around the standard library HTTP server and router.
internal
cli
job
Package job provides typed, explicit durable job dispatch and worker lifecycle.
Package job provides typed, explicit durable job dispatch and worker lifecycle.
postgres
Package postgres provides an inspectable PostgreSQL job store.
Package postgres provides an inspectable PostgreSQL job store.
Package mail defines immutable outbound messages and a replaceable delivery boundary.
Package mail defines immutable outbound messages and a replaceable delivery boundary.
smtp
Package smtp delivers GoForge mail messages through SMTP.
Package smtp delivers GoForge mail messages through SMTP.
orm
Package orm provides a small, code-generation-oriented data mapper over database/sql.
Package orm provides a small, code-generation-oriented data mapper over database/sql.
postgres
Package postgres adapts PostgreSQL driver errors to GoForge ORM errors.
Package postgres adapts PostgreSQL driver errors to GoForge ORM errors.
Package schedule provides explicit recurring job definitions and scheduler lifecycle.
Package schedule provides explicit recurring job definitions and scheduler lifecycle.
postgres
Package postgres provides the inspectable PostgreSQL schedule store.
Package postgres provides the inspectable PostgreSQL schedule store.
security
csrf
Package csrf provides session-bound synchronizer tokens.
Package csrf provides session-bound synchronizer tokens.
password
Package password hashes and verifies user passwords with the standard-library PBKDF2 implementation.
Package password hashes and verifies user passwords with the standard-library PBKDF2 implementation.
ratelimit
Package ratelimit provides explicit fixed-window request throttling with a replaceable persistence contract.
Package ratelimit provides explicit fixed-window request throttling with a replaceable persistence contract.
ratelimit/postgres
Package postgres provides an inspectable durable PostgreSQL rate-limit store.
Package postgres provides an inspectable durable PostgreSQL rate-limit store.
token
Package token issues and verifies opaque, database-backed security tokens.
Package token issues and verifies opaque, database-backed security tokens.
Package session provides signed-ID, server-side HTTP sessions.
Package session provides signed-ID, server-side HTTP sessions.
Package validation contains composable, typed validation rules without reflection.
Package validation contains composable, typed validation rules without reflection.
Package view renders html/template files to a buffer before committing an HTTP response.
Package view renders html/template files to a buffer before committing an HTTP response.
Package web provides the buffered request lifecycle used by browser routes.
Package web provides the buffered request lifecycle used by browser routes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL