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
604 lines
17 KiB
Markdown
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
|
|
|