diff --git a/docs/book/art/openers/ch04b.svg b/docs/book/art/openers/ch04b.svg
new file mode 100644
index 00000000..92d7179c
--- /dev/null
+++ b/docs/book/art/openers/ch04b.svg
@@ -0,0 +1 @@
+
diff --git a/docs/book/art/openers/ch06.svg b/docs/book/art/openers/ch06.svg
index 37243295..286de8d0 100644
--- a/docs/book/art/openers/ch06.svg
+++ b/docs/book/art/openers/ch06.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch06a.svg b/docs/book/art/openers/ch06a.svg
new file mode 100644
index 00000000..f9a0daa5
--- /dev/null
+++ b/docs/book/art/openers/ch06a.svg
@@ -0,0 +1 @@
+
diff --git a/docs/book/art/openers/ch07.svg b/docs/book/art/openers/ch07.svg
index 79e3d346..6c9002b9 100644
--- a/docs/book/art/openers/ch07.svg
+++ b/docs/book/art/openers/ch07.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch08.svg b/docs/book/art/openers/ch08.svg
index a90477f1..c85da559 100644
--- a/docs/book/art/openers/ch08.svg
+++ b/docs/book/art/openers/ch08.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch09.svg b/docs/book/art/openers/ch09.svg
index 05aefda8..169b4e78 100644
--- a/docs/book/art/openers/ch09.svg
+++ b/docs/book/art/openers/ch09.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch10.svg b/docs/book/art/openers/ch10.svg
index 8d865c44..2eb69202 100644
--- a/docs/book/art/openers/ch10.svg
+++ b/docs/book/art/openers/ch10.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch11.svg b/docs/book/art/openers/ch11.svg
index 263b9c59..257a4d70 100644
--- a/docs/book/art/openers/ch11.svg
+++ b/docs/book/art/openers/ch11.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch12.svg b/docs/book/art/openers/ch12.svg
index 94c4d713..50971fc9 100644
--- a/docs/book/art/openers/ch12.svg
+++ b/docs/book/art/openers/ch12.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch13.svg b/docs/book/art/openers/ch13.svg
index eae8adf0..ea12185f 100644
--- a/docs/book/art/openers/ch13.svg
+++ b/docs/book/art/openers/ch13.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch14.svg b/docs/book/art/openers/ch14.svg
index 31ed3183..810718ff 100644
--- a/docs/book/art/openers/ch14.svg
+++ b/docs/book/art/openers/ch14.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch15.svg b/docs/book/art/openers/ch15.svg
index fecf1837..bd160ef1 100644
--- a/docs/book/art/openers/ch15.svg
+++ b/docs/book/art/openers/ch15.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch16.svg b/docs/book/art/openers/ch16.svg
index 09ffe404..ab6c30a6 100644
--- a/docs/book/art/openers/ch16.svg
+++ b/docs/book/art/openers/ch16.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch17.svg b/docs/book/art/openers/ch17.svg
index 0e69d557..dc4c15a7 100644
--- a/docs/book/art/openers/ch17.svg
+++ b/docs/book/art/openers/ch17.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch18.svg b/docs/book/art/openers/ch18.svg
index 8894968d..5207fd8a 100644
--- a/docs/book/art/openers/ch18.svg
+++ b/docs/book/art/openers/ch18.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch19.svg b/docs/book/art/openers/ch19.svg
index 5a521703..7850e316 100644
--- a/docs/book/art/openers/ch19.svg
+++ b/docs/book/art/openers/ch19.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch20.svg b/docs/book/art/openers/ch20.svg
index 5c5d11fc..3b9ec410 100644
--- a/docs/book/art/openers/ch20.svg
+++ b/docs/book/art/openers/ch20.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch21.svg b/docs/book/art/openers/ch21.svg
index 7d937107..7718249a 100644
--- a/docs/book/art/openers/ch21.svg
+++ b/docs/book/art/openers/ch21.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch22.svg b/docs/book/art/openers/ch22.svg
index 1546a3cb..1490829a 100644
--- a/docs/book/art/openers/ch22.svg
+++ b/docs/book/art/openers/ch22.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/art/openers/ch22b.svg b/docs/book/art/openers/ch22b.svg
new file mode 100644
index 00000000..d389d7f7
--- /dev/null
+++ b/docs/book/art/openers/ch22b.svg
@@ -0,0 +1 @@
+
diff --git a/docs/book/art/openers/ch23.svg b/docs/book/art/openers/ch23.svg
index f79ab6d4..45dec7c1 100644
--- a/docs/book/art/openers/ch23.svg
+++ b/docs/book/art/openers/ch23.svg
@@ -1 +1 @@
-
+
diff --git a/docs/book/book.yaml b/docs/book/book.yaml
index 5e6bb155..5577d700 100644
--- a/docs/book/book.yaml
+++ b/docs/book/book.yaml
@@ -31,32 +31,35 @@ parts:
- {id: ch03, file: 03-configuration.md, num: 3, title: "Configuration, Profiles & Secrets", opener: art/openers/ch03.svg}
- {id: ch04, file: 04a-dependency-injection.md, num: 4, title: "Dependency Injection & the Application Context", opener: art/openers/ch04.svg}
- {id: ch05, file: 04-dependency-wiring.md, num: 5, title: "Dependency Wiring & Composition", opener: art/openers/ch05.svg}
- - {id: ch06, file: 05-reactive-model.md, num: 6, title: "The Reactive Model — Mono & Flux", opener: art/openers/ch06.svg}
+ - {id: ch04b, file: 04b-bootstrap.md, num: 6, title: "Application Bootstrap", opener: art/openers/ch04b.svg}
+ - {id: ch06, file: 05-reactive-model.md, num: 7, title: "The Reactive Model — Mono & Flux", opener: art/openers/ch06.svg}
- title: "Part II — Modeling & Persisting the Domain"
chapters:
- - {id: ch07, file: 06-first-http-api.md, num: 7, title: "Your First HTTP API", opener: art/openers/ch07.svg}
- - {id: ch08, file: 07-persistence.md, num: 8, title: "Persistence & Reactive Repositories", opener: art/openers/ch08.svg}
- - {id: ch09, file: 08-domain-driven-design.md, num: 9, title: "Domain-Driven Design", opener: art/openers/ch09.svg}
- - {id: ch10, file: 09-cqrs.md, num: 10, title: "CQRS: Commands & Queries", opener: art/openers/ch10.svg}
+ - {id: ch07, file: 06-first-http-api.md, num: 8, title: "Your First HTTP API", opener: art/openers/ch07.svg}
+ - {id: ch06a, file: 06a-openapi.md, num: 9, title: "OpenAPI & API Documentation", opener: art/openers/ch06a.svg}
+ - {id: ch08, file: 07-persistence.md, num: 10, title: "Persistence & Reactive Repositories", opener: art/openers/ch08.svg}
+ - {id: ch09, file: 08-domain-driven-design.md, num: 11, title: "Domain-Driven Design", opener: art/openers/ch09.svg}
+ - {id: ch10, file: 09-cqrs.md, num: 12, title: "CQRS: Commands & Queries", opener: art/openers/ch10.svg}
- title: "Part III — Event-Driven Architecture"
chapters:
- - {id: ch11, file: 10-eda-messaging.md, num: 11, title: "Event-Driven Architecture & Messaging", opener: art/openers/ch11.svg}
- - {id: ch12, file: 11-event-sourcing.md, num: 12, title: "Event Sourcing the Ledger", opener: art/openers/ch12.svg}
+ - {id: ch11, file: 10-eda-messaging.md, num: 13, title: "Event-Driven Architecture & Messaging", opener: art/openers/ch11.svg}
+ - {id: ch12, file: 11-event-sourcing.md, num: 14, title: "Event Sourcing the Ledger", opener: art/openers/ch12.svg}
- title: "Part IV — Into Microservices"
chapters:
- - {id: ch13, file: 13-http-clients.md, num: 13, title: "HTTP Clients & Calling Other Services", opener: art/openers/ch13.svg}
- - {id: ch14, file: 20a-experience-tier.md, num: 14, title: "The Experience Tier: Composing a BFF", opener: art/openers/ch14.svg}
- - {id: ch15, file: 12-sagas.md, num: 15, title: "Distributed Transactions: Sagas, Workflows & TCC", opener: art/openers/ch15.svg}
+ - {id: ch13, file: 13-http-clients.md, num: 15, title: "HTTP Clients & Calling Other Services", opener: art/openers/ch13.svg}
+ - {id: ch14, file: 20a-experience-tier.md, num: 16, title: "The Experience Tier: Composing a BFF", opener: art/openers/ch14.svg}
+ - {id: ch15, file: 12-sagas.md, num: 17, title: "Distributed Transactions: Sagas, Workflows & TCC", opener: art/openers/ch15.svg}
+ - {id: ch22b, file: 22-layered-microservices.md, num: 18, title: "Layered Microservices", opener: art/openers/ch22b.svg}
- title: "Part V — Secure, Observe & Ship"
chapters:
- - {id: ch16, file: 14-security.md, num: 16, title: "Security, Sessions & Identity", opener: art/openers/ch16.svg}
- - {id: ch17, file: 15-observability.md, num: 17, title: "Observability & Health", opener: art/openers/ch17.svg}
- - {id: ch18, file: 17-caching.md, num: 18, title: "Caching & Resilience", opener: art/openers/ch18.svg}
- - {id: ch19, file: 16-scheduling-notifications.md, num: 19, title: "Scheduling, Notifications & Webhooks", opener: art/openers/ch19.svg}
- - {id: ch20, file: 21-declarative-macros.md, num: 20, title: "Declarative Services with Macros", opener: art/openers/ch20.svg}
- - {id: ch21, file: 18-testing.md, num: 21, title: "Testing Firefly Applications", opener: art/openers/ch21.svg}
- - {id: ch22, file: 19-cli.md, num: 22, title: "The firefly CLI", opener: art/openers/ch22.svg}
- - {id: ch23, file: 20-production.md, num: 23, title: "Extending Firefly & Going to Production", opener: art/openers/ch23.svg}
+ - {id: ch16, file: 14-security.md, num: 19, title: "Security, Sessions & Identity", opener: art/openers/ch16.svg}
+ - {id: ch17, file: 15-observability.md, num: 20, title: "Observability & Health", opener: art/openers/ch17.svg}
+ - {id: ch18, file: 17-caching.md, num: 21, title: "Caching & Resilience", opener: art/openers/ch18.svg}
+ - {id: ch19, file: 16-scheduling-notifications.md, num: 22, title: "Scheduling, Notifications & Webhooks", opener: art/openers/ch19.svg}
+ - {id: ch20, file: 21-declarative-macros.md, num: 23, title: "Declarative Services with Macros", opener: art/openers/ch20.svg}
+ - {id: ch21, file: 18-testing.md, num: 24, title: "Testing Firefly Applications", opener: art/openers/ch21.svg}
+ - {id: ch22, file: 19-cli.md, num: 25, title: "The firefly CLI", opener: art/openers/ch22.svg}
+ - {id: ch23, file: 20-production.md, num: 26, title: "Extending Firefly & Going to Production", opener: art/openers/ch23.svg}
- title: "Appendices"
chapters:
- {id: appb, file: 91-appendix-modules.md, num: "A", title: "Crate & Module Index", opener: art/openers/appb.svg}
diff --git a/docs/book/build/gen_openers.py b/docs/book/build/gen_openers.py
index 832fda39..b9cfe471 100644
--- a/docs/book/build/gen_openers.py
+++ b/docs/book/build/gen_openers.py
@@ -420,14 +420,59 @@ def s_appb():
return rows
+def s_bootstrap():
+ # FireflyApplication::new("lumen").run() ignites the whole stack: one call
+ # on the left fans out into the services the framework discovers & wires.
+ call = (card(48, 132, 150, "new().run()", "url(#grh)", RUST_D, "#16110c", 14)
+ + spark(60, 90, 5, AMBER, 0.85) + spark(178, 102, 4, AMBER_B, 0.8))
+ fans = (arrow(202, 142, 270, 78) + arrow(202, 150, 274, 150) + arrow(202, 158, 270, 222))
+ pieces = (chip(280, 64, "web + CQRS") + chip(284, 136, "scan beans")
+ + chip(280, 208, "admin + docs"))
+ return call + fans + pieces
+
+
+def s_openapi():
+ # routes + DTOs are harvested into one generated spec, served as Swagger/ReDoc.
+ sources = (chip(40, 70, "#[rest_controller]") + chip(40, 196, "#[derive(Schema)]"))
+ funnel = (arrow(196, 92, 256, 132) + arrow(196, 210, 256, 156))
+ doc = (f''
+ f''
+ f''
+ # a little "spec" sheet: title bar + lines
+ f''
+ + "".join(f'' for r in range(4))
+ + f'')
+ out = (f'openapi.json')
+ return sources + funnel + doc + out + chip(290, 70, "Swagger · ReDoc", AMBER)
+
+
+def s_layered():
+ # five separately-compiled crates stacked like a multi-module project.
+ crates = ["…-interfaces", "…-models", "…-core", "…-web", "…-sdk"]
+ rows = []
+ for i, c in enumerate(crates):
+ y = 60 + i * 38
+ fill = "url(#grh)" if i == 4 else NODE
+ stroke = RUST_D if i == 4 else RUST
+ tcol = "#16110c" if i == 4 else INK
+ # slight left inset per layer to read as a stack
+ rows.append(card(44 + i * 6, y, 300 - i * 12, c, fill, stroke, tcol, 13))
+ return "".join(rows) + spark(420, 96, 5, AMBER, 0.8) + spark(404, 196, 4, AMBER_B, 0.7)
+
+
SCENES = {
"ch01": ("Why Firefly — infinite choice becomes cohesion", "WHY FIREFLY", s_choice),
"ch02": ("Quickstart — cargo new to a running service", "QUICKSTART", s_quickstart),
"ch03": ("Configuration — layered defaults, profiles, secrets", "CONFIGURATION", s_config),
"ch04": ("Dependency Injection — the application context", "DEPENDENCY INJECTION", s_di),
"ch05": ("Dependency Wiring — composing the core", "WIRING", s_wiring),
+ "ch04b": ("Application Bootstrap — one call ignites the stack", "BOOTSTRAP", s_bootstrap),
"ch06": ("The Reactive Model — Mono and Flux", "MONO & FLUX", s_reactive),
"ch07": ("Your first HTTP API — routes and handlers", "HTTP API", s_http),
+ "ch06a": ("OpenAPI — routes and DTOs become a served spec", "OPENAPI", s_openapi),
"ch08": ("Persistence — reactive repositories", "PERSISTENCE", s_persist),
"ch09": ("Domain-Driven Design — aggregates and value objects", "DOMAIN MODEL", s_ddd),
"ch10": ("CQRS — commands and queries on a bus", "CQRS", s_cqrs),
@@ -436,6 +481,7 @@ def s_appb():
"ch13": ("HTTP clients — calling other services", "HTTP CLIENTS", s_clients),
"ch14": ("The experience tier — composing a BFF", "EXPERIENCE TIER", s_bff),
"ch15": ("Sagas, workflows and TCC — and compensation", "SAGAS", s_saga),
+ "ch22b": ("Layered microservices — separately-compiled crates", "LAYERED SERVICES", s_layered),
"ch16": ("Security, sessions and identity", "SECURITY", s_security),
"ch17": ("Observability and health", "OBSERVABILITY", s_observe),
"ch18": ("Caching and resilience", "CACHING", s_cache),
@@ -448,8 +494,18 @@ def s_appb():
"appb": ("Crate and module index", "MODULE INDEX", s_appb),
}
-# kicker numbers shown top-left, keyed by opener id
-NUMS = {f"ch{i:02d}": f"CHAPTER {i}" for i in range(1, 24)}
+# kicker numbers shown top-left, keyed by opener id. The order below is the
+# book's reading order and the display number must match book.yaml's `num:`.
+# Inserting 04b-bootstrap, 06a-openapi and 22-layered renumbers everything that
+# follows, so this is an EXPLICIT ordered list rather than a range() formula.
+_CH_ORDER = [
+ "ch01", "ch02", "ch03", "ch04", "ch05", "ch04b", "ch06", # Part I (1..7)
+ "ch07", "ch06a", "ch08", "ch09", "ch10", # Part II (8..12)
+ "ch11", "ch12", # Part III (13..14)
+ "ch13", "ch14", "ch15", "ch22b", # Part IV (15..18)
+ "ch16", "ch17", "ch18", "ch19", "ch20", "ch21", "ch22", "ch23", # Part V (19..26)
+]
+NUMS = {oid: f"CHAPTER {i}" for i, oid in enumerate(_CH_ORDER, start=1)}
NUMS["appa"] = "APPENDIX A"
# book.yaml maps the module-index appendix (opener id appb) to "Appendix A".
NUMS["appb"] = "APPENDIX A"
diff --git a/docs/book/dist/firefly-rust-by-example.epub b/docs/book/dist/firefly-rust-by-example.epub
index 320a8a24..68305668 100644
Binary files a/docs/book/dist/firefly-rust-by-example.epub and b/docs/book/dist/firefly-rust-by-example.epub differ
diff --git a/docs/book/dist/firefly-rust-by-example.pdf b/docs/book/dist/firefly-rust-by-example.pdf
index 7f5ead7c..a11e89ac 100644
Binary files a/docs/book/dist/firefly-rust-by-example.pdf and b/docs/book/dist/firefly-rust-by-example.pdf differ