586 lines
16 KiB
Markdown
586 lines
16 KiB
Markdown
# Module Architecture
|
|
|
|
This document details the architecture of modules, how they are structured, how they interact with the core platform, and how multiple modules work together.
|
|
|
|
## 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
|
|
```
|
|
|
|
### Module Directory Structure
|
|
|
|
```
|
|
modules/blog/
|
|
├── go.mod # Module dependencies
|
|
├── module.yaml # Module manifest
|
|
├── pkg/
|
|
│ └── module.go # IModule implementation
|
|
├── internal/
|
|
│ ├── api/
|
|
│ │ └── handler.go # HTTP handlers
|
|
│ ├── domain/
|
|
│ │ ├── post.go # Domain entities
|
|
│ │ └── post_repo.go # Repository interface
|
|
│ ├── service/
|
|
│ │ └── post_service.go # Business logic
|
|
│ └── ent/
|
|
│ ├── schema/
|
|
│ │ └── post.go # Ent schema
|
|
│ └── migrate/ # Migrations
|
|
└── tests/
|
|
└── integration_test.go
|
|
```
|
|
|
|
## 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
|
|
```
|
|
|
|
## Module Communication
|
|
|
|
Modules (services) communicate through service client interfaces. All inter-service communication uses gRPC (primary) or HTTP (fallback).
|
|
|
|
### 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 -->|Publish| EventBus
|
|
EventBus -->|Subscribe| AnalyticsService
|
|
|
|
AuthClient --> AuthService
|
|
IdentityClient --> IdentityService
|
|
AuthzClient --> IdentityService
|
|
|
|
style EventBus fill:#4a90e2,stroke:#2e5c8a,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
|
|
|