Architecture
June 8, 2026 · View on GitHub
This project is designed with Clean Architecture and DDD, or Domain-Driven Design, as references.
The overall architecture follows DIP, the Dependency Inversion Principle: the domain layer defines ports, outer modules provide implementations, and the composition root performs dependency injection.
The monorepo is organized with pnpm workspace.
Directory Tree
fastgpt-plugin/
├── apps/
│ ├── cli/ # CLI for plugin development, build, packaging, and debugging
│ ├── server/ # FastGPT Plugin HTTP service
│ └── debug-runtime-monitor/ # Local runtime monitoring and debugging panel
├── packages/
│ ├── domain/ # Domain entities, value objects, and port definitions
│ ├── usecase/ # Application use cases that orchestrate domain objects and ports
│ ├── interface-adapter/ # HTTP contracts, DTOs, and auth adapters
│ ├── infrastructure/ # Hono, Mongo, S3, Redis, runtime, logging, metrics, and other implementations
│ └── shared/ # Cross-layer pure utilities
├── sdk/
│ ├── client/ # Client SDK for calling the FastGPT Plugin service
│ └── factory/ # Plugin author SDK for declaring plugins, tools, and runtime channels
├── test/ # Cross-package test utilities and fixtures
├── docs/ # Project documentation
├── scripts/ # Project scripts
├── pnpm-workspace.yaml # Workspace and catalog version declarations
├── tsconfig.json # Global TypeScript config and path aliases
└── vitest.config.ts # Global test config
Layered Architecture
flowchart TB
subgraph Apps["Application Entrypoints apps/*"]
Server["apps/server\nHTTP API"]
CLI["apps/cli\nDeveloper CLI"]
Monitor["apps/debug-runtime-monitor\nRuntime Monitor"]
end
subgraph Adapter["Interface Adapter packages/interface-adapter"]
Contracts["OpenAPI Contracts / DTO"]
Auth["Auth Adapter"]
end
subgraph Usecase["Application Layer packages/usecase"]
PluginUC["Plugin Use Cases"]
ToolUC["Tool Use Cases"]
RuntimeUC["Runtime Use Cases"]
ModelUC["Model Use Cases"]
end
subgraph Domain["Domain Layer packages/domain"]
Entities["Entities"]
ValueObjects["Value Objects"]
Ports["Port Interfaces"]
end
subgraph Infra["Infrastructure Layer packages/infrastructure"]
Hono["Hono App / Response"]
Mongo["Mongo Repo"]
S3["S3 Storage"]
Redis["Redis Client"]
Runtime["Plugin Runtime"]
Metrics["Logger / Metrics"]
end
subgraph SDK["SDK sdk/*"]
ClientSDK["sdk/client"]
FactorySDK["sdk/factory"]
end
Server --> Adapter
Server --> Usecase
Server --> Infra
CLI --> FactorySDK
Monitor --> Server
Adapter --> Domain
Usecase --> Domain
Infra --> Domain
Infra --> Adapter
ClientSDK --> Server
ClientSDK --> Adapter
ClientSDK --> Domain
FactorySDK --> Domain
FactorySDK --> Infra
Core dependency direction:
domaindefines business concepts and ports. It is the innermost layer and does not depend on application entrypoints or infrastructure.usecaseorchestrates business flows and depends ondomainentities, value objects, and ports.interface-adapterdefines HTTP contracts, DTOs, and auth inputs/outputs. It converts external protocols into structures the application can understand.infrastructureimplements ports and runtime capabilities, including the HTTP framework, database, object storage, Redis, plugin runtime, logging, and metrics.apps/*are composition roots that assemble dependencies, register routes, start processes, or provide development commands.sdk/*is published for external users and currently reuses internal contracts, domain types, and part of the runtime channel implementation.
Domain Layer
packages/domain stores stable business models:
entities/: core entities such as plugins, tools, models, datasets, and workflows.value-objects/: immutable business values such asResult, errors, permissions, streaming responses, and i18n strings.ports/: port interfaces for repositories, file storage, URL file fetching, plugin runtime, tool invocation, and more.
Ports are defined in the domain layer, and concrete implementations live in infrastructure. Use cases depend only on ports, making it easy to replace Mongo, S3, runtime drivers, or external file-fetching policies.
Application Layer
packages/usecase splits use cases by business capability:
plugin/: plugin upload, install, confirm, delete, configuration read/write, version list, tag list, active plugin replacement, and more.tool/: tool list, tool detail, and tool execution.model/: model list and model providers.runtime/: runtime metrics snapshots.
Use cases usually follow makeXxxUC(deps) => async (input) => Result<output>. Dependencies are injected through parameters, input and output types are explicit, and errors are returned through the Result value object.
Interface Adapter Layer
packages/interface-adapter owns external protocol boundaries:
contracts/route/: HTTP API contracts organized by resource.contracts/dto/: request and response DTOs.auth/: auth token parsing and validation adapters.http/: HTTP-related base types.
Server routes register OpenAPI contracts from these definitions and call use cases inside handlers.
Infrastructure Layer
packages/infrastructure provides replaceable technical implementations:
hono/: Hono app, unified responses, error and 404 hooks, and middleware.storage/mongo/: Mongo connection and model definitions.storage/s3/: S3 client and object storage capabilities.redis/: Redis client.file-storage/,file-ttl/: local and remote file storage plus temporary-file cleanup.plugin/: plugin repository,.pkgparsing, invocation, runtime management, and drivers.logger/,metrics/: logging and OpenTelemetry metrics.utils/secure/: security utilities such as SSRF protection.
apps/server/src/deps.ts is part of the server composition root. It creates Mongo, S3, Redis, file storage, plugin repositories, runtime managers, and tool managers, then injects them into routes.
Application Entrypoints
Server
apps/server/main.ts starts the service:
- Initialize logger and metrics.
- Create route dependencies.
- Register model, plugin, runtime, tool, and workflow routes.
- Initialize proxy, database, runtime, and other infrastructure.
- Listen on
env.PORTwith Hono Node Server. - Handle
SIGTERMandSIGINT, closing the HTTP server, metrics, and logger.
CLI
apps/cli targets plugin developers and provides create, check, build, pack, debug, and related commands. The CLI also contains plugin templates and Codex skills for generating plugin projects that follow the current package protocol.
Debug Runtime Monitor
apps/debug-runtime-monitor is a Vite app for observing plugin runtime state locally. It depends on runtime APIs exposed by the server and does not carry core business logic.
SDK
sdk/client: for FastGPT or other callers. It wraps FastGPT Plugin service requests, transport, and tool streaming responses.sdk/factory: for plugin authors. It provides plugin manifest, tool factory, invoke client, runtime channel, and related declaration capabilities.
SDK packages are published independently. The apps/server build first builds sdk/factory to ensure the types and artifacts required for loading plugins at runtime are available.
Request Flow
sequenceDiagram
participant FastGPT as FastGPT / Client
participant Route as apps/server Route
participant Contract as interface-adapter Contract
participant UC as usecase
participant Port as domain Port
participant Infra as infrastructure Impl
participant Runtime as Plugin Runtime
FastGPT->>Route: HTTP Request
Route->>Contract: validate request / response schema
Route->>UC: call usecase(input)
UC->>Port: use domain port
Port->>Infra: resolved by dependency injection
Infra->>Runtime: load / invoke plugin when needed
Runtime-->>Infra: invocation result
Infra-->>UC: Result
UC-->>Route: Result
Route-->>FastGPT: JSON / stream response
For plugin installation:
apps/server/src/routes/plugin.route.tsreceives the request and validates DTOs.- The route creates
makePluginInstallUC. - The use case downloads the plugin package through
URLFileFetcherPort. - The use case saves the temporary file through
LocalFileStoragePort. - The use case parses the
.pkgor plugin packages inside a zip throughPluginPKGFilePort. - The use case writes plugin metadata and files through
PluginRepoPort. - If the plugin type is tool, the use case registers it with
PluginRuntimeManagerPort.
Dependency Injection Conventions
When adding a business capability, prefer the existing pattern:
- Define required ports in
domain/ports. - Write business orchestration in
usecaseand depend on port types. - Implement ports in
infrastructure. - Define HTTP DTOs and OpenAPI contracts in
interface-adapter/contracts. - Register routes in
apps/server/src/routesand call use cases. - Assemble concrete implementations in
apps/server/src/deps.ts.
This keeps core business logic decoupled from frameworks, databases, and runtime drivers.
Path Aliases
The root tsconfig.json defines the main path aliases:
@domain/* -> packages/domain/src/*
@usecase/* -> packages/usecase/src/*
@shared/* -> packages/shared/src/*
@interface-adapter/* -> packages/interface-adapter/src/*
@infrastructure/* -> packages/infrastructure/src/*
@fastgpt-plugin/cli/* -> apps/cli/src/*
@fastgpt-plugin/sdk-* -> sdk/*/src/*
Prefer these aliases in code to express layer boundaries and reduce deep relative paths.
Test Strategy
Current tests are distributed near affected modules by risk:
*.spec.ts/*.test.ts: close to tested code, covering use cases, CLI commands, builds, DTOs, response utilities, security utilities, URL fetchers, and more.test/fixtures/: cross-package fixtures for plugins, tools, tool suites, and related cases.- Root
vitest.config.ts: unified test entry.
Suggested tests for new capabilities:
- Use unit tests for domain value objects and pure functions.
- Use mock ports in usecase tests to verify business branches and error returns.
- Isolate external IO in infrastructure tests and cover serialization, error mapping, and security limits.
- Cover DTO validation, status codes, and response shapes in route tests.
Extension Principles
- Keep
domainandusecaseindependent from infrastructure details such as Hono, Mongo, S3, and Redis. - When adding plugin types, update modeling in domain entities, package protocol parsing, runtime registration, and API contracts together.
- When adding runtime drivers, implement
PluginRuntimeManagerPortand switch assembly indeps.ts. - When adding storage backends, implement the corresponding file storage or repo port while keeping use cases unchanged.
- When changing public SDKs, CLIs, HTTP APIs, or the
.pkgpackage protocol, consider backward compatibility and update the upgrade docs.