Files
goplt/docs/content/architecture/architecture-modules.md
0x1d 38a251968c docs: Align documentation with true microservices architecture
Transform all documentation from modular monolith to true microservices
architecture where core services are independently deployable.

Key Changes:
- Core Kernel: Infrastructure only (no business logic)
- Core Services: Auth, Identity, Authz, Audit as separate microservices
  - Each service has own entry point (cmd/{service}/)
  - Each service has own gRPC server and database schema
  - Services register with Consul for service discovery
- API Gateway: Moved from Epic 8 to Epic 1 as core infrastructure
  - Single entry point for all external traffic
  - Handles routing, JWT validation, rate limiting, CORS
- Service Discovery: Consul as primary mechanism (ADR-0033)
- Database Pattern: Per-service connections with schema isolation

Documentation Updates:
- Updated all 9 architecture documents
- Updated 4 ADRs and created 2 new ADRs (API Gateway, Service Discovery)
- Rewrote Epic 1: Core Kernel & Infrastructure (infrastructure only)
- Rewrote Epic 2: Core Services (Auth, Identity, Authz, Audit as services)
- Updated Epic 3-8 stories for service architecture
- Updated plan.md, playbook.md, requirements.md, index.md
- Updated all epic READMEs and story files

New ADRs:
- ADR-0032: API Gateway Strategy
- ADR-0033: Service Discovery Implementation (Consul)

New Stories:
- Epic 1.7: Service Client Interfaces
- Epic 1.8: API Gateway Implementation
2025-11-06 08:54:19 +01:00

604 lines
17 KiB
Markdown

# Module Architecture
This document details the architecture of modules (feature services), how they are structured as independent services, how they interact with core services, and how multiple services work together in the microservices architecture.
## Table of Contents
- [Module Structure](#module-structure)
- [Module Interface](#module-interface)
- [Module Lifecycle](#module-lifecycle)
- [Module Dependencies](#module-dependencies)
- [Module Communication](#module-communication)
- [Module Data Isolation](#module-data-isolation)
- [Module Examples](#module-examples)
## Module Structure
Every module follows a consistent structure that separates concerns and enables clean integration with the platform.
```mermaid
graph TD
subgraph "Module Structure"
Manifest[module.yaml<br/>Manifest]
subgraph "Public API (pkg/)"
ModuleInterface[IModule Interface]
ModuleTypes[Public Types]
end
subgraph "Internal Implementation (internal/)"
API[API Handlers]
Service[Domain Services]
Repo[Repositories]
Domain[Domain Models]
end
subgraph "Database Schema"
EntSchema[Ent Schemas]
Migrations[Migrations]
end
end
Manifest --> ModuleInterface
ModuleInterface --> API
API --> Service
Service --> Repo
Repo --> Domain
Repo --> EntSchema
EntSchema --> Migrations
style Manifest fill:#4a90e2,stroke:#2e5c8a,stroke-width:3px,color:#fff
style ModuleInterface fill:#50c878,stroke:#2e7d4e,stroke-width:2px,color:#fff
style Service fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
```
### Service Directory Structure
Each module is an independent service with its own entry point:
```
cmd/blog-service/
└── main.go # Service entry point
services/blog/
├── go.mod # Service dependencies
├── module.yaml # Service manifest
├── api/
│ └── blog.proto # gRPC service definition
├── internal/
│ ├── api/
│ │ └── handler.go # gRPC handlers
│ ├── domain/
│ │ ├── post.go # Domain entities
│ │ └── post_repo.go # Repository interface
│ ├── service/
│ │ └── post_service.go # Business logic
│ └── database/
│ └── client.go # Database connection
└── ent/
├── schema/
│ └── post.go # Ent schema
└── migrate/ # Migrations
```
## Module Interface
All modules must implement the `IModule` interface to integrate with the platform.
```mermaid
classDiagram
class IModule {
<<interface>>
+Name() string
+Version() string
+Dependencies() []string
+Init() fx.Option
+Migrations() []MigrationFunc
+OnStart(ctx) error
+OnStop(ctx) error
}
class BlogModule {
+Name() string
+Version() string
+Dependencies() []string
+Init() fx.Option
+Migrations() []MigrationFunc
}
class BillingModule {
+Name() string
+Version() string
+Dependencies() []string
+Init() fx.Option
+Migrations() []MigrationFunc
}
IModule <|.. BlogModule
IModule <|.. BillingModule
```
### IModule Interface
```go
type IModule interface {
// Name returns a unique, human-readable identifier
Name() string
// Version returns the module version (semantic versioning)
Version() string
// Dependencies returns list of required modules (e.g., ["core >= 1.0.0"])
Dependencies() []string
// Init returns fx.Option that registers all module services
Init() fx.Option
// Migrations returns database migration functions
Migrations() []func(*ent.Client) error
// OnStart is called during application startup (optional)
OnStart(ctx context.Context) error
// OnStop is called during graceful shutdown (optional)
OnStop(ctx context.Context) error
}
```
## Module Lifecycle
Modules go through a well-defined lifecycle from discovery to shutdown.
```mermaid
stateDiagram-v2
[*] --> Discovered: Module found
Discovered --> Validated: Check dependencies
Validated --> Loaded: Load module
Loaded --> Initialized: Call Init()
Initialized --> Migrated: Run migrations
Migrated --> Started: Call OnStart()
Started --> Running: Module active
Running --> Stopping: Shutdown signal
Stopping --> Stopped: Call OnStop()
Stopped --> [*]
Validated --> Rejected: Dependency check fails
Rejected --> [*]
```
### Module Initialization Sequence
```mermaid
sequenceDiagram
participant Main
participant Loader
participant Registry
participant Module
participant DI
participant Router
participant DB
participant Scheduler
Main->>Loader: DiscoverModules()
Loader->>Registry: Scan for modules
Registry-->>Loader: Module list
loop For each module
Loader->>Module: Load module
Module->>Registry: Register module
Registry->>Registry: Validate dependencies
end
Main->>Registry: GetAllModules()
Registry->>Registry: Resolve dependencies (topological sort)
Registry-->>Main: Ordered module list
Main->>DI: Create fx container
loop For each module (in dependency order)
Main->>Module: Init()
Module->>DI: fx.Provide(services)
Module->>Router: Register routes
Module->>Scheduler: Register jobs
Module->>DB: Register migrations
end
Main->>DB: Run migrations (core first)
Main->>DI: Start container
Main->>Module: OnStart() (optional)
Main->>Router: Start HTTP server
```
## Module Dependencies
Modules can depend on other modules, creating a dependency graph that must be resolved.
```mermaid
graph TD
Core[Core Kernel]
Blog[Blog Module]
Billing[Billing Module]
Analytics[Analytics Module]
Notifications[Notification Module]
Blog --> Core
Billing --> Core
Analytics --> Core
Notifications --> Core
Analytics --> Blog
Analytics --> Billing
Billing --> Blog
Notifications --> Blog
Notifications --> Billing
style Core fill:#4a90e2,stroke:#2e5c8a,stroke-width:3px,color:#fff
style Blog fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
style Billing fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
```
### Dependency Resolution
```mermaid
graph LR
subgraph "Module Dependency Graph"
M1[Module A<br/>depends on: Core]
M2[Module B<br/>depends on: Core, Module A]
M3[Module C<br/>depends on: Core, Module B]
Core[Core Kernel]
end
subgraph "Resolved Load Order"
Step1[1. Core Kernel]
Step2[2. Module A]
Step3[3. Module B]
Step4[4. Module C]
end
Core --> M1
M1 --> M2
M2 --> M3
Step1 --> Step2
Step2 --> Step3
Step3 --> Step4
style Core fill:#4a90e2,stroke:#2e5c8a,stroke-width:3px,color:#fff
style Step1 fill:#50c878,stroke:#2e7d4e,stroke-width:2px,color:#fff
```
## Service Communication
Modules are implemented as independent services that communicate through service client interfaces. All inter-service communication uses gRPC (primary) or HTTP (fallback) via service clients. Services discover each other through the service registry (Consul).
### Communication Patterns
```mermaid
graph TB
subgraph "Communication Patterns"
ServiceClients[Service Clients<br/>gRPC/HTTP]
Events[Event Bus<br/>Kafka]
Shared[Shared Infrastructure<br/>Redis, PostgreSQL]
end
subgraph "Blog Service"
BlogService[Blog Service]
BlogHandler[Blog Handler]
end
subgraph "Service Clients"
AuthClient[Auth Service Client]
IdentityClient[Identity Service Client]
AuthzClient[Authz Service Client]
end
subgraph "Core Services"
EventBus[Event Bus]
AuthService[Auth Service<br/>:8081]
IdentityService[Identity Service<br/>:8082]
end
subgraph "Analytics Service"
AnalyticsService[Analytics Service]
end
BlogHandler --> BlogService
BlogService -->|gRPC| AuthClient
BlogService -->|gRPC| IdentityClient
BlogService -->|gRPC| AuthzClient
BlogService -->|gRPC| AuditClient
BlogService -->|Publish| EventBus
EventBus -->|Subscribe| AnalyticsService
AuthClient -->|Discover| Registry
IdentityClient -->|Discover| Registry
AuthzClient -->|Discover| Registry
AuditClient -->|Discover| Registry
Registry --> AuthService
Registry --> IdentityService
Registry --> AuthzService
Registry --> AuditService
AuthClient --> AuthService
IdentityClient --> IdentityService
AuthzClient --> AuthzService
AuditClient --> AuditService
style EventBus fill:#4a90e2,stroke:#2e5c8a,stroke-width:3px,color:#fff
style Registry fill:#50c878,stroke:#2e7d4e,stroke-width:3px,color:#fff
style BlogService fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
style AnalyticsService fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
style ServiceClients fill:#50c878,stroke:#2e7d4e,stroke-width:2px,color:#fff
```
### Event-Driven Communication
```mermaid
sequenceDiagram
participant BlogModule
participant EventBus
participant AnalyticsModule
participant NotificationModule
participant AuditModule
BlogModule->>EventBus: Publish("blog.post.created", event)
EventBus->>AnalyticsModule: Deliver event
EventBus->>NotificationModule: Deliver event
EventBus->>AuditModule: Deliver event
AnalyticsModule->>AnalyticsModule: Track post creation
NotificationModule->>NotificationModule: Send notification
AuditModule->>AuditModule: Log audit entry
```
## Module Data Isolation
Modules can have their own database tables while sharing core tables.
```mermaid
erDiagram
USERS ||--o{ USER_ROLES : has
ROLES ||--o{ USER_ROLES : assigned_to
ROLES ||--o{ ROLE_PERMISSIONS : has
PERMISSIONS ||--o{ ROLE_PERMISSIONS : assigned_to
BLOG_POSTS {
string id PK
string author_id FK
string title
string content
timestamp created_at
}
BILLING_SUBSCRIPTIONS {
string id PK
string user_id FK
string plan
timestamp expires_at
}
USERS ||--o{ BLOG_POSTS : creates
USERS ||--o{ BILLING_SUBSCRIPTIONS : subscribes
AUDIT_LOGS {
string id PK
string actor_id
string action
string target_id
jsonb metadata
}
USERS ||--o{ AUDIT_LOGS : performs
```
### Multi-Tenancy Data Isolation
```mermaid
graph TB
subgraph "Single Database"
subgraph "Core Tables"
Users[users<br/>tenant_id]
Roles[roles<br/>tenant_id]
end
subgraph "Blog Module Tables"
Posts[blog_posts<br/>tenant_id]
Comments[blog_comments<br/>tenant_id]
end
subgraph "Billing Module Tables"
Subscriptions[billing_subscriptions<br/>tenant_id]
Invoices[billing_invoices<br/>tenant_id]
end
end
subgraph "Query Filtering"
EntInterceptor[Ent Interceptor]
TenantFilter[WHERE tenant_id = ?]
end
Users --> EntInterceptor
Posts --> EntInterceptor
Subscriptions --> EntInterceptor
EntInterceptor --> TenantFilter
style EntInterceptor fill:#4a90e2,stroke:#2e5c8a,stroke-width:3px,color:#fff
```
## Module Examples
### Example: Blog Module
```mermaid
graph TB
subgraph "Blog Module"
BlogHandler[Blog Handler<br/>/api/v1/blog/posts]
BlogService[Post Service]
PostRepo[Post Repository]
PostEntity[Post Entity]
end
subgraph "Service Clients"
AuthClient[Auth Service Client<br/>gRPC]
AuthzClient[Authz Service Client<br/>gRPC]
IdentityClient[Identity Service Client<br/>gRPC]
AuditClient[Audit Service Client<br/>gRPC]
end
subgraph "Core Services"
EventBus[Event Bus<br/>Kafka]
CacheService[Cache Service<br/>Redis]
end
subgraph "Database"
PostsTable[(blog_posts)]
end
BlogHandler --> BlogService
BlogService -->|gRPC| AuthClient
BlogService -->|gRPC| AuthzClient
BlogService -->|gRPC| IdentityClient
BlogService -->|gRPC| AuditClient
BlogService --> PostRepo
BlogService --> EventBus
BlogService --> CacheService
PostRepo --> PostsTable
PostRepo --> PostEntity
style BlogModule fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
style AuthService fill:#4a90e2,stroke:#2e5c8a,stroke-width:2px,color:#fff
```
### Module Integration Example
```mermaid
graph LR
subgraph "Request Flow"
Request[HTTP Request<br/>POST /api/v1/blog/posts]
Auth[Auth Middleware]
Authz[Authz Middleware]
Handler[Blog Handler]
Service[Blog Service]
Repo[Blog Repository]
DB[(Database)]
end
subgraph "Service Clients"
AuthClient[Auth Service Client]
IdentityClient[Identity Service Client]
AuthzClient[Authz Service Client]
end
subgraph "Side Effects"
EventBus[Event Bus]
AuditClient[Audit Service Client]
Cache[Cache]
end
Request --> Auth
Auth --> Authz
Authz --> Handler
Handler --> Service
Service --> Repo
Repo --> DB
Service -->|gRPC| AuthClient
Service -->|gRPC| IdentityClient
Service -->|gRPC| AuthzClient
Service -->|gRPC| AuditClient
Service --> EventBus
Service --> Cache
style Request fill:#4a90e2,stroke:#2e5c8a,stroke-width:2px,color:#fff
style Service fill:#7b68ee,stroke:#5a4fcf,stroke-width:2px,color:#fff
style ServiceClients fill:#50c878,stroke:#2e7d4e,stroke-width:2px,color:#fff
```
## Module Registration Flow
```mermaid
flowchart TD
Start([Application Start]) --> LoadManifests["Load module.yaml files"]
LoadManifests --> ValidateDeps["Validate dependencies"]
ValidateDeps -->|Valid| SortModules["Topological sort modules"]
ValidateDeps -->|Invalid| Error([Error: Missing dependencies])
SortModules --> CreateDI["Create DI container"]
CreateDI --> RegisterCore["Register core services"]
RegisterCore --> LoopModules{"More modules?"}
LoopModules -->|Yes| LoadModule["Load module"]
LoadModule --> CallInit["Call module.Init()"]
CallInit --> RegisterServices["Register module services"]
RegisterServices --> RegisterRoutes["Register module routes"]
RegisterRoutes --> RegisterJobs["Register module jobs"]
RegisterJobs --> RegisterMigrations["Register module migrations"]
RegisterMigrations --> LoopModules
LoopModules -->|No| RunMigrations["Run all migrations"]
RunMigrations --> StartModules["Call OnStart() for each module"]
StartModules --> StartServer["Start HTTP server"]
StartServer --> Running([Application Running])
Running --> Shutdown([Shutdown Signal])
Shutdown --> StopServer["Stop HTTP server"]
StopServer --> StopModules["Call OnStop() for each module"]
StopModules --> Cleanup["Cleanup resources"]
Cleanup --> End([Application Stopped])
style Start fill:#50c878,stroke:#2e7d4e,stroke-width:2px,color:#fff
style Running fill:#4a90e2,stroke:#2e5c8a,stroke-width:2px,color:#fff
style Error fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px,color:#fff
```
## Module Permissions Integration
Modules declare permissions that are automatically integrated into the permission system.
```mermaid
graph TB
subgraph "Permission Generation"
Manifest["module.yaml<br/>permissions: array"]
Generator["Permission Generator"]
GeneratedCode["pkg/perm/generated.go"]
end
subgraph "Permission Resolution"
Request["HTTP Request"]
AuthzMiddleware["Authz Middleware"]
PermissionResolver["Permission Resolver"]
UserRoles["User Roles"]
RolePermissions["Role Permissions"]
Response["HTTP Response"]
end
Manifest --> Generator
Generator --> GeneratedCode
GeneratedCode --> PermissionResolver
Request --> AuthzMiddleware
AuthzMiddleware --> PermissionResolver
PermissionResolver --> UserRoles
PermissionResolver --> RolePermissions
UserRoles --> PermissionResolver
RolePermissions --> PermissionResolver
PermissionResolver --> AuthzMiddleware
AuthzMiddleware --> Response
classDef generation fill:#4a90e2,stroke:#2e5c8a,stroke-width:2px,color:#fff
classDef resolution fill:#50c878,stroke:#2e7d4e,stroke-width:2px,color:#fff
class Manifest,Generator,GeneratedCode generation
class PermissionResolver resolution
```
## Next Steps
- [Module Requirements](./module-requirements.md) - Detailed requirements for each module
- [Component Relationships](./component-relationships.md) - How components interact
- [System Architecture](./architecture.md) - Overall system architecture