@@ -13,39 +13,7 @@ This page explains how Forge's core components are structured, how they interact
1313
1414A Forge application is composed of several interconnected components, all owned and orchestrated by the ` App ` instance:
1515
16- ```
17- ┌──────────────────────────────────────────────────────────┐
18- │ App │
19- │ │
20- │ ┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ │
21- │ │ Container │ │ Router │ │ ConfigManager │ │
22- │ │ (Vessel) │ │ │ │ (confy) │ │
23- │ │ │ │ Routes │ │ │ │
24- │ │ Singletons │ │ Groups │ │ YAML files │ │
25- │ │ Transients │ │ Middleware │ │ Env vars │ │
26- │ │ Scoped │ │ WebSocket │ │ Watch/Bind │ │
27- │ └─────────────┘ │ SSE │ └──────────────────┘ │
28- │ └─────────────┘ │
29- │ ┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ │
30- │ │ Logger │ │ Metrics │ │ HealthManager │ │
31- │ │ │ │ │ │ │ │
32- │ │ Structured │ │ Counters │ │ Checks │ │
33- │ │ Leveled │ │ Gauges │ │ Liveness │ │
34- │ │ Beautiful │ │ Histograms │ │ Readiness │ │
35- │ └─────────────┘ └─────────────┘ └──────────────────┘ │
36- │ │
37- │ ┌────────────────────────────────────────────────────┐ │
38- │ │ LifecycleManager │ │
39- │ │ BeforeStart → AfterRegister → AfterStart → │ │
40- │ │ BeforeRun → AfterRun → BeforeStop → AfterStop │ │
41- │ └────────────────────────────────────────────────────┘ │
42- │ │
43- │ ┌────────────────────────────────────────────────────┐ │
44- │ │ Extensions │ │
45- │ │ Database | Kafka | gRPC | GraphQL | Auth | ... │ │
46- │ └────────────────────────────────────────────────────┘ │
47- └──────────────────────────────────────────────────────────┘
48- ```
16+ <Mermaid chart={"block-beta\n columns 3\n block:app[\"App\"]:3\n columns 3\n block:container[\"Container (Vessel)\"]\n columns 1\n Singletons\n Transients\n Scoped\n end\n block:router[\"Router\"]\n columns 1\n Routes\n Groups\n Middleware\n WebSocket\n SSE\n end\n block:config[\"ConfigManager (confy)\"]\n columns 1\n YAMLFiles[\"YAML files\"]\n EnvVars[\"Env vars\"]\n WatchBind[\"Watch / Bind\"]\n end\n block:logger[\"Logger\"]\n columns 1\n Structured\n Leveled\n end\n block:metrics[\"Metrics\"]\n columns 1\n Counters\n Gauges\n Histograms\n end\n block:health[\"HealthManager\"]\n columns 1\n Checks\n Liveness\n Readiness\n end\n block:lifecycle[\"LifecycleManager\"]:3\n columns 1\n Phases[\"BeforeStart → AfterRegister → AfterStart → BeforeRun → AfterRun → BeforeStop → AfterStop\"]\n end\n block:extensions[\"Extensions\"]:3\n columns 1\n ExtList[\"Database · Kafka · gRPC · GraphQL · Auth · ...\"]\n end\n end\n style app fill:transparent,stroke:#666\n style container fill:transparent,stroke:#888\n style router fill:transparent,stroke:#888\n style config fill:transparent,stroke:#888\n style logger fill:transparent,stroke:#888\n style metrics fill:transparent,stroke:#888\n style health fill:transparent,stroke:#888\n style lifecycle fill:transparent,stroke:#888\n style extensions fill:transparent,stroke:#888"} />
4917
5018## Core Components
5119
@@ -153,52 +121,7 @@ Orchestrates hook execution across seven ordered phases. Hooks are sorted by pri
153121
154122When an HTTP request arrives, it passes through this pipeline:
155123
156- ```
157- Client Request
158- │
159- ▼
160- ┌─────────────┐
161- │ HTTP Server │ (net/http)
162- └─────┬───────┘
163- │
164- ▼
165- ┌─────────────┐
166- │ Global │ Applied via router.UseGlobal()
167- │ Middleware │ Includes extension-provided middleware
168- └─────┬───────┘
169- │
170- ▼
171- ┌─────────────┐
172- │ Group │ Applied via router.Group() options
173- │ Middleware │ or group.Use()
174- └─────┬───────┘
175- │
176- ▼
177- ┌─────────────┐
178- │ Route │ Applied via forge.WithMiddleware()
179- │ Middleware │ on individual route registrations
180- └─────┬───────┘
181- │
182- ▼
183- ┌─────────────┐
184- │ Handler │ func(ctx forge.Context) error
185- │ │
186- │ - Reads request (ctx.Bind, ctx.Param, ctx.Query)
187- │ - Calls business logic
188- │ - Writes response (ctx.JSON, ctx.String, ctx.NoContent)
189- │ - Returns nil or error
190- └─────┬───────┘
191- │
192- ▼
193- ┌─────────────┐
194- │ Error │ Converts returned errors to HTTP responses
195- │ Handler │ HTTPError → status code + JSON body
196- │ │ Plain error → 500 Internal Server Error
197- └─────┬───────┘
198- │
199- ▼
200- Response
201- ```
124+ <Mermaid chart = { " flowchart TD\n A[Client Request] --> B[\" HTTP Server\n (net/http)\" ]\n B --> C[\" Global Middleware\n router.UseGlobal()\n extension-provided middleware\" ]\n C --> D[\" Group Middleware\n router.Group() options\n group.Use()\" ]\n D --> E[\" Route Middleware\n forge.WithMiddleware()\n per-route registration\" ]\n E --> F[\" Handler\n func(ctx forge.Context) error\n ─────────────────────\n • ctx.Bind, ctx.Param, ctx.Query\n • Business logic\n • ctx.JSON, ctx.String, ctx.NoContent\n • Returns nil or error\" ]\n F --> G[\" Error Handler\n ─────────────────────\n HTTPError → status code + JSON body\n Plain error → 500 Internal Server Error\" ]\n G --> H[Response]" } />
202125
203126## Extension System
204127
@@ -220,6 +143,8 @@ type Extension interface {
220143
221144Extensions go through a managed lifecycle:
222145
146+ <Mermaid chart = { " flowchart LR\n A[\" Dependency Resolution\n Topological sort\" ] --> B[\" Register Phase\n ext.Register(app)\n DI + Routes\" ]\n B --> C[\" Start Phase\n ext.Start(ctx)\n Dependency order\" ]\n C --> D[\" Stop Phase\n ext.Stop(ctx)\n Reverse order\" ]\n style A fill:#f0f0ff,stroke:#666\n style B fill:#f0fff0,stroke:#666\n style C fill:#fffff0,stroke:#666\n style D fill:#fff0f0,stroke:#666" } />
147+
2231481 . ** Dependency resolution** : Extensions are topologically sorted based on their declared dependencies.
2241492 . ** Register phase** : Each extension calls ` Register(app) ` to add services to the DI container and configure routes.
2251503 . ** Start phase** : Each extension starts in dependency order. A dependency is fully registered and started before its dependents begin.
@@ -245,6 +170,10 @@ Every Forge application automatically registers these endpoints:
245170
246171When you call ` app.Run() ` , the following happens in order:
247172
173+ <Mermaid chart={"flowchart TD\n subgraph startup[\"Startup — app.Run()\"]\n direction TB\n S1[\"app.Start()\"] --> S2[\"⚡ PhaseBeforeStart hooks\"]\n S2 --> S3[\"Topological sort extensions\"]\n S3 --> S4[\"For each extension:\next.Register(app)\next.Start(ctx)\"]\n S4 --> S5[\"⚡ PhaseAfterRegister hooks\"]\n S5 --> S6[\"Apply extension middleware globally\"]\n S6 --> S7[\"Finalize DI container\"]\n S7 --> S8[\"Wire health manager\"]\n S8 --> S9[\"Register observability endpoints\"]\n S9 --> S10[\"⚡ PhaseAfterStart hooks\"]\n S10 --> S11[\"Create HTTP server\"]\n S11 --> S12[\"Print startup banner\"]\n S12 --> S13[\"⚡ PhaseBeforeRun hooks\"]\n S13 --> S14[\"HTTP server starts listening\"]\n S14 --> S15[\"⚡ PhaseAfterRun hooks (background)\"]\n S15 --> S16[\"Block — await SIGINT / SIGTERM\"]\n end\n subgraph shutdown[\"Shutdown\"]\n direction TB\n D1[\"Stop accepting connections\"] --> D2[\"Drain in-flight requests\"]\n D2 --> D3[\"⚡ PhaseBeforeStop hooks\"]\n D3 --> D4[\"Stop health manager\"]\n D4 --> D5[\"Stop extensions (reverse order)\"]\n D5 --> D6[\"Stop DI container services\"]\n D6 --> D7[\"⚡ PhaseAfterStop hooks\"]\n end\n S16 -->|signal received| D1"} />
174+
175+ ** Startup steps:**
176+
2481771 . ` app.Start() ` is called
2491782 . ** PhaseBeforeStart** hooks execute
2501793 . Extensions are topologically sorted by dependency
@@ -264,7 +193,7 @@ When you call `app.Run()`, the following happens in order:
26419315 . ** PhaseAfterRun** hooks execute (in background)
26519416 . Server blocks, waiting for shutdown signal (SIGINT/SIGTERM)
266195
267- On shutdown:
196+ ** Shutdown steps: **
268197
2691981 . HTTP server stops accepting new connections
2701992 . In-flight requests drain (up to ` ShutdownTimeout ` )
0 commit comments