Skip to content

Commit 202690d

Browse files
committed
docs: add versioned bilingual website
1 parent 83d489f commit 202690d

77 files changed

Lines changed: 10306 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/docs-pages.yml‎

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Documentation
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "website/**"
9+
- ".github/workflows/docs-pages.yml"
10+
pull_request:
11+
branches:
12+
- main
13+
paths:
14+
- "website/**"
15+
- ".github/workflows/docs-pages.yml"
16+
workflow_dispatch:
17+
18+
permissions:
19+
contents: read
20+
21+
concurrency:
22+
group: pages-${{ github.ref }}
23+
cancel-in-progress: true
24+
25+
jobs:
26+
build:
27+
name: Build documentation
28+
runs-on: ubuntu-latest
29+
timeout-minutes: 20
30+
permissions:
31+
contents: read
32+
pages: read
33+
defaults:
34+
run:
35+
working-directory: website
36+
steps:
37+
- name: Check out repository
38+
uses: actions/checkout@v7
39+
40+
- name: Set up Node.js
41+
uses: actions/setup-node@v7
42+
with:
43+
node-version: 22
44+
cache: npm
45+
cache-dependency-path: website/package-lock.json
46+
47+
- name: Install documentation dependencies
48+
run: npm ci
49+
50+
- name: Check formatting
51+
run: npm run format:check
52+
53+
- name: Check types and documentation parity
54+
run: npm run check
55+
56+
- name: Configure GitHub Pages
57+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
58+
uses: actions/configure-pages@v6
59+
60+
- name: Build website
61+
run: npm run build
62+
env:
63+
DOCS_BASE: /Boot/
64+
DOCS_ORIGIN: https://a3s-lab.github.io
65+
66+
- name: Check built routes and assets
67+
run: npm run check:site
68+
69+
- name: Upload GitHub Pages artifact
70+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
71+
uses: actions/upload-pages-artifact@v5
72+
with:
73+
path: website/doc_build
74+
75+
deploy:
76+
name: Deploy documentation
77+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
78+
needs: build
79+
runs-on: ubuntu-latest
80+
timeout-minutes: 10
81+
permissions:
82+
pages: write
83+
id-token: write
84+
environment:
85+
name: github-pages
86+
url: ${{ steps.deployment.outputs.page_url }}
87+
steps:
88+
- name: Deploy to GitHub Pages
89+
id: deployment
90+
uses: actions/deploy-pages@v5

‎README.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</p>
1010

1111
<p align="center">
12+
<a href="https://a3s-lab.github.io/Boot/">Documentation</a> •
1213
<a href="#overview">Overview</a> •
1314
<a href="#features">Features</a> •
1415
<a href="#quick-start">Quick Start</a> •
@@ -32,6 +33,10 @@ belong to the framework core; Axum is the bundled default HTTP adapter. Rust
3233
attribute macros generate ordinary Boot definitions at compile time rather than
3334
relying on runtime decorator metadata.
3435

36+
The [documentation website](https://a3s-lab.github.io/Boot/) provides complete
37+
Chinese and English guides for v0.2.0 and v0.1.4, including same-page language
38+
and version switching.
39+
3540
### Basic usage
3641

3742
```rust,no_run
@@ -449,6 +454,16 @@ corresponding services or environment configuration.
449454

450455
See [Roadmap](ROADMAP.md) for the Nest compatibility plan and remaining work.
451456

457+
The versioned bilingual documentation site lives in `website/`:
458+
459+
```bash
460+
cd website
461+
npm ci
462+
npm run check
463+
npm run build
464+
npm run check:site
465+
```
466+
452467
## License
453468

454469
MIT

‎ROADMAP.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Official Nest.js areas used as reference:
2828

2929
Implemented today:
3030

31+
- A versioned documentation website with complete Chinese and English guides,
32+
default Chinese routing, same-page locale switching, and v0.2.0/v0.1.4
33+
version switching.
3134
- `Module` with imports, providers, controllers, direct routes, module route
3235
prefixes, and lifecycle hooks.
3336
- `BootFactory` with NestFactory-style `create`, `create_application_context`,

‎website/.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.generated-docs/
2+
/doc_build/
3+
/node_modules/

‎website/.prettierignore‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.generated-docs/
2+
doc_build/
3+
node_modules/
4+
package-lock.json

‎website/.prettierrc‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "all"
4+
}

‎website/content/en/_meta.json‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[
2+
{
3+
"type": "section-header",
4+
"label": "Get started"
5+
},
6+
{
7+
"type": "dir",
8+
"name": "getting-started",
9+
"label": "Get started"
10+
},
11+
{
12+
"type": "dir",
13+
"name": "core",
14+
"label": "Framework core"
15+
},
16+
{
17+
"type": "dir",
18+
"name": "capabilities",
19+
"label": "Application capabilities"
20+
},
21+
{
22+
"type": "dir",
23+
"name": "protocols",
24+
"label": "Protocols and workers"
25+
},
26+
{
27+
"type": "dir",
28+
"name": "reference",
29+
"label": "Reference"
30+
}
31+
]

‎website/content/en/_nav.json‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[
2+
{
3+
"text": "Guides",
4+
"link": "/getting-started/overview",
5+
"activeMatch": "^/(getting-started|core|capabilities|protocols)/"
6+
},
7+
{
8+
"text": "API reference",
9+
"link": "/reference/features-and-api",
10+
"activeMatch": "^/reference/"
11+
},
12+
{
13+
"text": "Resources",
14+
"items": [
15+
{
16+
"text": "GitHub",
17+
"link": "https://github.com/A3S-Lab/Boot"
18+
},
19+
{
20+
"text": "docs.rs",
21+
"link": "https://docs.rs/a3s-boot"
22+
},
23+
{
24+
"text": "Releases",
25+
"link": "https://github.com/A3S-Lab/Boot/releases"
26+
}
27+
]
28+
}
29+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
"security-auth-and-sessions",
3+
"openapi-and-http",
4+
"cqrs-events-and-scheduling",
5+
"operations-modules"
6+
]
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
title: CQRS, events, and scheduling
3+
description: Organize background collaboration with typed commands, queries, events, A3S Event providers, and lifecycle-managed schedulers.
4+
---
5+
6+
# CQRS, events, and scheduling
7+
8+
Boot provides three related but distinct in-application collaboration models. `cqrs` dispatches types to handlers, `events` supplies named events and a provider boundary, and `schedule` triggers work by time. Each model registers through a module and uses the same provider graph.
9+
10+
## CQRS buses
11+
12+
Commands and queries declare their output type. Each command or query type has one handler, while an event can have multiple handlers.
13+
14+
```rust
15+
use a3s_boot::{Command, CqrsContext, CqrsModule};
16+
17+
#[derive(Debug)]
18+
struct RenameUser {
19+
id: u64,
20+
name: String,
21+
}
22+
23+
impl Command for RenameUser {
24+
type Output = String;
25+
}
26+
27+
let module = CqrsModule::new("users-cqrs")
28+
.command_handler::<RenameUser, _>(
29+
|command: RenameUser, context: CqrsContext| async move {
30+
let users = context.get::<UserRepository>()?;
31+
users.rename(command.id, command.name).await
32+
},
33+
);
34+
```
35+
36+
`CommandBus::execute` and `QueryBus::execute` return the declared output. `EventBus::publish` calls all matching handlers and returns the call count. Duplicate command or query handlers fail during registration. A missing handler returns an error at dispatch.
37+
38+
`CqrsContext` resolves providers from the declaring module scope, so handlers do not need a global service locator. Register buses at a business boundary and use `.global()` only when they genuinely span modules.
39+
40+
## Application events
41+
42+
With `events`, `EventModule` exports `EventEmitter` and an A3S Event bus. Event names use dot-separated lowercase form, such as `user.profile.updated`.
43+
44+
```rust
45+
#[derive(Debug)]
46+
struct UserEventHandlers;
47+
48+
#[a3s_boot::event_listener]
49+
impl UserEventHandlers {
50+
#[a3s_boot::on_event("user.created")]
51+
async fn created(&self, payload: UserCreated, context: EventContext) -> Result<()> {
52+
let audit = context.get::<AuditWriter>()?;
53+
audit.record(payload.id).await
54+
}
55+
}
56+
```
57+
58+
A listener can receive a typed payload or a complete `EventEnvelope`, and `user.*` wildcard patterns are supported. Registration order is call order. `EventModule::in_process` uses the memory provider. Use `from_provider` to attach another A3S Event provider.
59+
60+
In-process event dispatch is not automatically durable cross-service messaging. Persistence, replay, deduplication, and cross-process delivery depend on the selected event provider.
61+
62+
## Scheduling
63+
64+
`ScheduleModule` supports one-shot timeouts, fixed intervals, and cron:
65+
66+
```rust
67+
let module = ScheduleModule::in_process("schedule")
68+
.interval("cache.refresh", Duration::from_secs(30), |context| async move {
69+
let cache = context.module_ref.get::<CatalogCache>()?;
70+
cache.refresh().await
71+
})
72+
.timeout("startup.warm", Duration::from_secs(2), |_| async move {
73+
Ok(())
74+
});
75+
```
76+
77+
The `#[schedule]` macro combines with `#[cron]`, `#[interval]`, and `#[timeout]` to generate the same `ScheduledJob` definitions. `ScheduleContext` contains the job name, trigger, run count, and `ModuleRef`.
78+
79+
The scheduler starts during application bootstrap and stops during shutdown. The in-process scheduler does not elect a leader or catch up work missed while a process was stopped. Every instance runs the same job unless the application applies an external lease, leader election, or shared backend.
80+
81+
## Select a model
82+
83+
| Need | Select |
84+
| ------------------------------------------------------ | --------------------------------------------- |
85+
| One typed operation with one result | Command |
86+
| A typed read with a result | Query |
87+
| Several listeners responding to an in-process fact | CQRS Event or `events` |
88+
| A3S Event providers, named wildcards, or event queries | `events` |
89+
| Work triggered by time | `schedule` |
90+
| Retry, priority, persistence, and workers | [Queue](/protocols/queues-and-ilink) |
91+
| Delivery through a cross-service protocol | [Message transport](/protocols/microservices) |
92+
93+
## Reliability boundaries
94+
95+
- Handlers and listeners should return contextual errors and never panic for production input.
96+
- Design idempotency for event, schedule, and queue side effects that may repeat.
97+
- Put long work on a queue instead of blocking scheduler control paths.
98+
- Define timezone, overlapping-run policy, and shutdown behavior for every cron job.
99+
- Use stable schemas and compatibility rules for events that cross an external boundary.

0 commit comments

Comments
 (0)