Skip to content

Commit 666bb63

Browse files
committed
docs: update ADR-0002 event naming and add ADR-0003 C4 system
- Expand ADR-0002 with comprehensive canonical event naming standards - Add versioning strategy and metadata requirements - Add ADR-0003 C4 system documentation - Update BFF README to reference new ADR
1 parent c124c8a commit 666bb63

File tree

3 files changed

+574
-20
lines changed

3 files changed

+574
-20
lines changed

boundaries/bff/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
> [!NOTE]
66
> This is a BFF service for web clients
7-
>
7+
>
88
> **HTTP REST API:** Implemented using 'chi' for optimal integration and high performance.
99
1010
### Docs
@@ -19,6 +19,7 @@
1919

2020
- [ADR-0001](./docs/ADR/decisions/0001-init.md) - Init project
2121
- [ADR-0002](./docs/ADR/decisions/0002-use-oapi-codegen.md) - Use `oapi-codegen` to generate API code
22+
- [ADR-0003](./docs/ADR/decisions/0003-c4-system.md) - C4 System
2223

2324
### Architecture
2425

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# 3. C4 System
2+
3+
Date: 2025-11-25
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
The decision to implement the C4 model (Context, Containers, Components, Code) in our BFF service architecture is driven
12+
by the need for a comprehensive, structured, and scalable approach to documenting and communicating
13+
the software architecture. The C4 model is renowned for its effectiveness in providing various levels of abstraction,
14+
which can be understood by different stakeholders ranging from developers to business personnel.
15+
16+
The BFF service is built using **Go (Golang)** and leverages several key technologies:
17+
18+
- **chi router** for HTTP routing and middleware
19+
- **oapi-codegen** for OpenAPI 3.0 code generation
20+
- **Redis** for caching to improve performance
21+
- **Ory Kratos** for authentication
22+
- **SpiceDB** for authorization and permission checks
23+
- **OpenTelemetry** for distributed tracing and observability
24+
- **gRPC** for communication with backend services
25+
26+
Implementing the C4 model will enable us to:
27+
28+
- Clearly define the high-level context of the BFF service, including key system interactions and integrations.
29+
- Break down the service into containers (HTTP API, controllers, etc.), illustrating the overall system architecture.
30+
- Detail out components within each container, clarifying internal architectures.
31+
- Optionally, delve into the code level to understand how components are implemented.
32+
33+
This approach is expected to streamline our documentation process,
34+
improve communication about system architecture within the team, and facilitate onboarding of new team members.
35+
36+
## Decision
37+
38+
We will focus specifically on creating **System Context**, **Container**, and **Component Diagrams** as part of the C4 model implementation.
39+
These diagrams will detail the internal structure and interactions of components within the BFF service,
40+
providing a clear view of how various parts of the system work together.
41+
42+
### System context diagram
43+
44+
```plantuml
45+
@startuml C4_Context_Diagram_for_BFF_Service
46+
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
47+
48+
LAYOUT_WITH_LEGEND()
49+
50+
title System Context Diagram for BFF Service
51+
52+
Person(user, "User", "An end user who interacts with the web application to manage short links.")
53+
System_Ext(web_app, "Web Application", "Next.js/React", "Frontend web application that provides UI for managing short links.")
54+
System_Ext(kratos, "Ory Kratos", "Identity Provider", "Handles user authentication, registration, and identity management.")
55+
System_Ext(spicedb, "SpiceDB", "Authorization Service", "Handles permission checks using Zanzibar-style fine-grained authorization.")
56+
System_Boundary(link_boundary, "Link Boundary Context") {
57+
System(link_service, "Link Service", "Domain Service", "Core service for managing short links and link operations.")
58+
System(metadata_service, "Metadata Service", "Domain Service", "Service for fetching and storing link metadata and screenshots.")
59+
}
60+
System_Boundary(bff_boundary, "BFF Boundary") {
61+
System(bff_service, "BFF Service", "API Gateway", "Backend-for-Frontend service that aggregates and transforms data for the web application.")
62+
}
63+
64+
Rel(user, web_app, "Uses", "HTTPS")
65+
Rel(web_app, bff_service, "Makes API requests", "HTTPS/REST")
66+
Rel(bff_service, kratos, "Validates user sessions", "HTTPS")
67+
Rel(bff_service, spicedb, "Checks user permissions", "gRPC")
68+
Rel(bff_service, link_service, "Proxies link operations", "gRPC")
69+
Rel(bff_service, metadata_service, "Queries metadata", "gRPC")
70+
71+
' Interaction notes
72+
note right of kratos
73+
**Ory Kratos**
74+
Only user session validation
75+
- Validates authentication tokens
76+
- Checks if user is logged in
77+
- Provides user identity information
78+
end note
79+
80+
note right of spicedb
81+
**SpiceDB**
82+
Object-level permissions
83+
- "can read link"
84+
- "can modify link"
85+
- Fine-grained authorization
86+
- Zanzibar-style permissions
87+
end note
88+
89+
' Use Cases
90+
note right of bff_service
91+
Use Cases:
92+
1. Manage links (CRUD operations)
93+
2. CQRS operations for links
94+
3. Sitemap operations
95+
end note
96+
97+
@enduml
98+
```
99+
100+
### Container diagram
101+
102+
```plantuml
103+
@startuml Container_Diagram_for_BFF_Service
104+
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
105+
106+
LAYOUT_WITH_LEGEND()
107+
108+
title Container Diagram for BFF Service
109+
110+
Person(web_client, "Web Client", "A web application user interacting with the system.")
111+
System_Ext(kratos, "Ory Kratos", "Handles user authentication and identity management.")
112+
System_Ext(spicedb, "SpiceDB", "Handles permission checks using Zanzibar-style authorization.")
113+
System_Ext(link_service, "Link Service", "Service for managing short links.")
114+
System_Ext(link_command, "Link Command Service", "CQRS command operations.")
115+
System_Ext(link_query, "Link Query Service", "CQRS query operations.")
116+
System_Ext(sitemap_service, "Sitemap Service", "Handles sitemap operations.")
117+
118+
System_Boundary(bff_system, "BFF System") {
119+
Container(bff_api, "BFF API", "Go/HTTP", "HTTP REST API server using chi router.")
120+
ContainerDb(cache, "Redis Cache", "Redis", "Caches frequently accessed data to improve performance.")
121+
}
122+
123+
Rel(web_client, bff_api, "Makes requests", "HTTPS/REST")
124+
Rel(bff_api, kratos, "Authenticates via", "HTTPS")
125+
Rel(bff_api, spicedb, "Checks permissions via", "gRPC")
126+
Rel(bff_api, cache, "Reads/Writes cached data", "Redis Protocol")
127+
Rel(bff_api, link_service, "Proxies requests to", "gRPC")
128+
Rel(bff_api, link_command, "Sends commands to", "gRPC")
129+
Rel(bff_api, link_query, "Sends queries to", "gRPC")
130+
Rel(bff_api, sitemap_service, "Proxies requests to", "gRPC")
131+
132+
@enduml
133+
```
134+
135+
### Component diagram
136+
137+
```plantuml
138+
@startuml Component_Diagram_for_BFF_Service
139+
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
140+
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
141+
142+
LAYOUT_WITH_LEGEND()
143+
144+
title Component Diagram for BFF Service
145+
146+
Person(web_client, "Web Client", "A web application user.")
147+
System_Ext(kratos, "Ory Kratos", "Handles user authentication and identity management.")
148+
System_Ext(spicedb, "SpiceDB", "Handles permission checks using Zanzibar-style authorization.")
149+
System_Ext(link_service, "Link Service", "Manages short links.")
150+
System_Ext(link_command, "Link Command Service", "CQRS command operations.")
151+
System_Ext(link_query, "Link Query Service", "CQRS query operations.")
152+
System_Ext(sitemap_service, "Sitemap Service", "Handles sitemap operations.")
153+
ContainerDb_Ext(cache, "Redis Cache", "Redis", "Caches frequently accessed data.")
154+
155+
System_Boundary(bff_system, "BFF System") {
156+
Container(bff_api, "BFF API", "Go/HTTP", "HTTP REST API server using chi router.")
157+
158+
Container_Boundary(interface_layer, "Interface Layer") {
159+
Container_Boundary(rest_handlers, "REST Handlers") {
160+
Component(link_controller, "Link Controller", "Go", "Handles link CRUD operations and data transformation.")
161+
Component(cqrs_controller, "CQRS Controller", "Go", "Handles CQRS operations for links with data aggregation.")
162+
Component(sitemap_controller, "Sitemap Controller", "Go", "Handles sitemap operations.")
163+
}
164+
Container_Boundary(middleware, "Middleware Stack") {
165+
Component(tracing_middleware, "Tracing Middleware", "Go", "Handles distributed tracing (1st in pipeline).")
166+
Component(logger_middleware, "Logger Middleware", "Go", "Logs HTTP requests and responses (2nd in pipeline).")
167+
Component(metrics_middleware, "Metrics Middleware", "Go", "Collects metrics and observability data (3rd in pipeline).")
168+
Component(csrf_middleware, "CSRF Middleware", "Go", "Protects against CSRF attacks (4th in pipeline).")
169+
Component(auth_middleware, "Auth Middleware", "Go", "Validates authentication tokens via Ory Kratos (5th in pipeline).")
170+
Component(permission_middleware, "Permission Middleware", "Go", "Checks permissions via SpiceDB (6th in pipeline).")
171+
}
172+
}
173+
174+
Container_Boundary(application_layer, "Application Layer") {
175+
Component(aggregation_service, "Aggregation Service", "Go", "Aggregates data from multiple backend services.")
176+
Component(adapter_service, "Adapter Service", "Go", "Transforms and adapts data between frontend and backend formats.")
177+
}
178+
179+
Container_Boundary(infrastructure_layer, "Infrastructure Layer") {
180+
Component(cache_component, "Redis Client", "Go", "Manages Redis cache operations for performance optimization.")
181+
Component(grpc_link_client, "gRPC Link Client", "Go", "Client for Link Service gRPC communication.")
182+
Component(grpc_command_client, "gRPC Command Client", "Go", "Client for Link Command Service gRPC communication.")
183+
Component(grpc_query_client, "gRPC Query Client", "Go", "Client for Link Query Service gRPC communication.")
184+
Component(grpc_sitemap_client, "gRPC Sitemap Client", "Go", "Client for Sitemap Service gRPC communication.")
185+
Component(error_transformer, "Error Transformer", "Go", "Transforms domain and gRPC errors into structured JSON responses.")
186+
}
187+
188+
Container_Boundary(cross_cutting, "Cross-Cutting Concerns") {
189+
Container_Boundary(observability, "Observability") {
190+
Component(logger_middleware, "Logger Middleware", "Go", "Logs HTTP requests and responses.")
191+
Component(metrics_middleware, "Metrics Middleware", "Go", "Collects metrics and observability data.")
192+
Component(tracing_middleware, "Tracing Middleware", "Go", "Handles distributed tracing.")
193+
Component(profiling_component, "Profiling Component", "Go", "Provides pprof endpoints for performance profiling.")
194+
Component(flight_trace_component, "Flight Trace", "Go", "Records request traces for debugging and analysis.")
195+
}
196+
Component(i18n_component, "i18n Component", "Go", "Provides internationalization support (en-GB, de-DE, fr-CH).")
197+
}
198+
}
199+
200+
Rel(web_client, bff_api, "Makes requests", "HTTPS/REST")
201+
Rel(bff_api, tracing_middleware, "Processes through", "1. Request pipeline")
202+
Rel(tracing_middleware, logger_middleware, "Processes through", "2. Request pipeline")
203+
Rel(logger_middleware, metrics_middleware, "Processes through", "3. Request pipeline")
204+
Rel(metrics_middleware, csrf_middleware, "Processes through", "4. Request pipeline")
205+
Rel(csrf_middleware, auth_middleware, "Processes through", "5. Request pipeline")
206+
Rel(auth_middleware, permission_middleware, "Processes through", "6. Request pipeline")
207+
Rel(permission_middleware, link_controller, "Routes to", "After middleware")
208+
Rel(permission_middleware, cqrs_controller, "Routes to", "After middleware")
209+
Rel(permission_middleware, sitemap_controller, "Routes to", "After middleware")
210+
Rel(auth_middleware, kratos, "Validates tokens", "HTTPS")
211+
Rel(permission_middleware, spicedb, "Checks permissions", "gRPC")
212+
213+
' Middleware order note
214+
note right of middleware
215+
**Middleware Pipeline Order:**
216+
1. Tracing (captures full request context)
217+
2. Logger (includes trace-id in logs)
218+
3. Metrics (includes user-id in metrics)
219+
4. CSRF (security validation)
220+
5. Auth (user session validation)
221+
6. Permission (object-level checks)
222+
223+
This order ensures trace-id and user-id
224+
are available in all observability data.
225+
end note
226+
227+
' Security interaction notes
228+
note right of auth_middleware
229+
**Ory Kratos Interaction:**
230+
Only user session validation
231+
- Validates authentication tokens
232+
- Checks if user is logged in
233+
- Provides user identity information
234+
end note
235+
236+
note right of permission_middleware
237+
**SpiceDB Interaction:**
238+
Object-level permissions
239+
- "can read link"
240+
- "can modify link"
241+
- Fine-grained authorization
242+
- Zanzibar-style permissions
243+
end note
244+
Rel(link_controller, aggregation_service, "Uses for data aggregation")
245+
Rel(cqrs_controller, aggregation_service, "Uses for data aggregation")
246+
Rel(sitemap_controller, adapter_service, "Uses for data transformation")
247+
Rel(aggregation_service, cache_component, "Uses for caching", "Redis Protocol")
248+
Rel(adapter_service, cache_component, "Uses for caching", "Redis Protocol")
249+
Rel(cache_component, cache, "Reads/Writes", "Redis Protocol")
250+
Rel(aggregation_service, grpc_link_client, "Uses", "gRPC")
251+
Rel(aggregation_service, grpc_command_client, "Uses", "gRPC")
252+
Rel(aggregation_service, grpc_query_client, "Uses", "gRPC")
253+
Rel(adapter_service, grpc_sitemap_client, "Uses", "gRPC")
254+
Rel(grpc_link_client, link_service, "Calls", "gRPC")
255+
Rel(grpc_command_client, link_command, "Calls", "gRPC")
256+
Rel(grpc_query_client, link_query, "Calls", "gRPC")
257+
Rel(grpc_sitemap_client, sitemap_service, "Calls", "gRPC")
258+
Rel(link_controller, error_transformer, "Uses for error transformation")
259+
Rel(cqrs_controller, error_transformer, "Uses for error transformation")
260+
Rel(sitemap_controller, error_transformer, "Uses for error transformation")
261+
Rel(bff_api, i18n_component, "Uses for localization")
262+
Rel(bff_api, profiling_component, "Exposes via", "/debug/pprof")
263+
Rel(bff_api, flight_trace_component, "Uses for debugging")
264+
265+
@enduml
266+
```
267+
268+
## Consequences
269+
270+
### Benefits
271+
272+
- **Improved understanding and communication**: Clear visualization of BFF service architecture helps all stakeholders understand the system design.
273+
- **Increased efficiency**: Well-documented architecture reduces time spent on understanding system interactions during development and maintenance.
274+
- **Better integration clarity**: Clear visualization of how the BFF service integrates with Ory Kratos, SpiceDB, and backend services.
275+
- **Enhanced onboarding**: New team members can quickly understand the system structure through visual diagrams.
276+
- **Facilitated discussions**: Architecture diagrams serve as a common reference point for technical discussions and decision-making.
277+
278+
### Technical Details
279+
280+
The diagrams illustrate:
281+
282+
- **Request flow**: From web client through middleware stack to controllers and backend services.
283+
- **Security layers**: Authentication (Ory Kratos) and authorization (SpiceDB) integration points.
284+
- **Performance optimization**: Redis caching strategy for frequently accessed data.
285+
- **Observability**: Metrics, tracing, profiling, and flight trace components for monitoring and debugging.
286+
- **Error handling**: Structured error transformation from domain/gRPC errors to client-friendly JSON responses.
287+
- **Internationalization**: Multi-language support (en-GB, de-DE, fr-CH) for localized responses.

0 commit comments

Comments
 (0)