Add @Operation to the MCP gateway endpoints (protected-resource metadata, JSON-RPC handler) and behavior-accurate method JavaDoc. Docs only, no logic changes.
Add behavior-accurate method JavaDoc (@param/@return) across data controllers and normalize @Parameter descriptions with examples. Correct two @Operation descriptions that wrongly claimed to return new ids. Docs only, no logic changes.
Add behavior-accurate method JavaDoc (@param/@return) across auth controllers and normalize @Parameter descriptions. Add @Operation to the six OAuth 2.1 endpoints (discovery, jwks, register, authorize, token, revoke) that previously had none. Docs only, no logic changes.
Replace stub method JavaDoc (bare ID/Device placeholders) with behavior-accurate descriptions, @param and @return across manager controllers; normalize @Parameter descriptions with examples. Comment and annotation docs only, no logic changes.
Standardize description wording, add scalar-field examples, mark required
fields via requiredMode, and drop examples from object/collection fields.
Spans VO/Query/ext/controller plus related BO/DTO/response types.
Generate <op>-<stack>[-<registry>] compose shortcuts and test/coverage
targets in the Makefile, remove the install-hooks target and the
.githooks commit-msg linter, and document the design.
Replace the scattered @Value injections in OAuthMcpRuntimeServiceImpl
with a typed OAuthProperties bean covering issuer, audience, TTLs and
JWT key material.
Drop the entity/request package and route controller, service, builder
and runtime paths through ChatCompletionVO, ModelConfigVO/ModelProviderVO,
the relocated dto/ChatMessageDTO and the renamed AgenticPreparedChatBO.
Record that read-only projection/aggregation responses (dashboard stats, health
snapshots, topic/model-option listings, history queries) may be returned directly
as VO without a parallel BO; the "services expose BO" rule applies to persistent
business entities and write-path business inputs.
The route-naming contract treated constant-defined mappings (e.g.
McpConstant.OAUTH2_TOKEN) as empty routes because it only scanned string literals;
recognise a constant reference as a real route. The metadata listener and driver
gRPC server tests stubbed driver lookups with a hardcoded tenant 1L, but the
tenant-safe production code passes null for the system-level metadata broadcast
and the driver's own tenant for the metadata snapshot; stub the matching tenant.
Rename the camelCase query params on the MCP audit listing (principalId, toolId,
riskLevel) to snake_case to satisfy the public HTTP route-naming contract.
TopicService is a read-only projection over devices and points and never used any
MyBatis-Plus IService method, yet exposed the full DeviceDO persistence API on the
service boundary. Make it a plain service backed by Db.lambdaQuery, and drop the
manual deleted=0 filter (handled by @TableLogic) along with two dead commented-out
enableFlag filters.
Move the four command-submission inputs (point read/write, command call, event
report) off web VO types and onto dedicated BO types so the data service and
facade layers no longer depend on request VOs. Controllers and the gRPC servers
convert the inbound VO/request into the BO via PointCommandBuilder and the
command/event builders; PointCommandLocalFacade builds the BO directly. The
RabbitMQ EventReportDTO overload and read-only history projections are unchanged.
Replace the naked Byte requirePasswordChange flag on LocalCredentialBO/VO with a
domain enum (NOT_REQUIRED/REQUIRED), mirroring ConfirmFlagEnum. The DO keeps Byte
for persistence; the builder converts via getIndex()/ofIndex(), and the few
existing call sites (LocalCredentialServiceImpl, TokenServiceImpl, tests) compare
against the enum instead of magic 0/1 literals.
Stop leaking persistence entities through the audit-log and tenant-membership
service boundaries. AuditLogService.list now returns IdentityAuditLogBO and the
controller maps it to the new IdentityAuditLogVO via IdentityAuditLogBuilder, so
the dc3_identity_audit_log table shape is no longer the public API response.
TenantMembershipService.add/getByTenantIdAndPrincipalId accept and return BO;
callers in UserController, ServiceAccountServiceImpl and TenantMembershipController
build BO instead of hand-populating DO.
Remove the test/coverage, app/dev, and compose-* alias targets along
with their check-* guards, and drop the matching .PHONY and MVN_SUB
entries. Reorder deploy and install-hooks under the trimmed target set.
Rewrite @Operation summary/description across all center controllers
(manager, auth, data, agentic) from mechanical restatements into
MCP-tool-grade prose: what the endpoint does, when to call it, the
return shape, tenant scope and side effects. Disambiguate sibling
endpoints so an LLM can select the right tool.
Fix the shared @Parameter id description that read "entity to delete"
on non-delete endpoints (getById/enable/disable) — keep it for delete,
use a neutral wording elsewhere. Enrich VO @Schema descriptions with
examples and required-mode hints. These feed the MCP tool catalog
(description via runtime scan, input schema via the OpenAPI snapshot).
Tool authorization (HIGH-risk confirmation):
- add AuthorizeToolCall RPC; the gateway calls it before tool execution
- sign/consume confirmation tickets with idempotency-key dedup
- propagate x-dc3-ai metadata (riskLevel/destructive/openWorld/idempotent) from the scan through the registry to the tool catalog
OAuth hardening:
- rotate refresh tokens and revoke the authorization on replay via previous_refresh_token_hash
Password lifecycle:
- require password change on login when flagged or expired (R20303/R20304)
- expose a public POST /token/change_password endpoint
OpenAPI aggregation:
- switch McpOpenApiAggregator to classpath static snapshots, dropping the runtime fetch and McpAggregatorProperties
- introduce TenantContextHolder holding tenantId with a runIgnore closure
- bind/clear the holder in BaseController.async from the reactive security context
- add unit tests for set/get and runIgnore semantics
- delete the RequirePermission annotation (no references in repo)
- drop unused imports in AuditLogController and PrincipalController
- return empty list instead of null in RoleResourceBindServiceImpl
- reformat McpAuditCommand/McpToolRecord javadoc and IdentityAuditLogMapper.xml
Default-initialize the MCP introspect WebClient.Builder so the gateway
starts when no WebClient.Builder bean is present.
Replace the explicit auth-route path list with /api/v3/auth/** (the public
/token path stays carved out purely by route ordering). This is required so
new auth endpoints route correctly — the old list omitted /principal,
/tenant_membership, /identity_audit and /mcp management.
Spring AMQP removed CorrelationData.getFuture(); move point-value
publish-confirmation logging onto RabbitTemplate.setConfirmCallback and
carry device/point context through a PointValueCorrelation subclass.
New dc3_identity_audit_log table + IdentityAuditLogDO/Manager/Mapper +
AuditLogService.log() write entry point (never throws — audit must not
break the audited operation) and a tenant-scoped, filtered read API
(POST /identity_audit/list, admin RBAC).
Wire recording into the identity controllers: service account and
principal enable/disable, and tenant membership add/remove.
dc3_mcp_audit_log is already written on every tools/call; expose a
tenant-scoped, filtered listAudit read path (mapper SELECT + service +
GET /mcp/audit/list) so the audit can be queried, not only recorded.
McpAuditCommand gains a createTime field populated on read-back.
Add McpOpenApiAggregator (config-gated, off by default) that fetches each
service's /v3/api-docs and stores the JSON request schema per tool in
tool_ext; McpToolRecord gains a toolExt field, the mapper persists it, and
tools/list surfaces the real schema instead of the static default. Zero
regression when the aggregator is disabled.
registerClient now pins the client to the authenticated caller's tenant
(ignoring the body tenant id) and requires an authenticated principal,
closing a cross-tenant client-registration hole; add boundary tests.
Gate OAuth dynamic client registration (/oauth2/register): open in
dev/test, closed in pre/pro unless dc3.oauth.dcr.enabled=true.
ServiceAccount: add /enable and /disable endpoints reusing the full
update path so the linked principal stays in sync.
Principal: list/get-by-id/enable/disable service + controller (admin RBAC,
the principal roster is a platform identity view scoped by permission).
TenantMembership: add BO/VO/Query/Builder, paged list + get-by-id on the
service, and a tenant-scoped controller (list/add pinned to the caller's
tenant; delete verifies ownership before removing).
AuthConstant: add PRINCIPAL_URL_PREFIX and TENANT_MEMBERSHIP_URL_PREFIX.
Update auth, gateway, architecture, quickstart, changelog, and superpowers design documents for the Principal identity model and OAuth-backed MCP server.
Replace legacy user-login and role-user binding runtime with Principal, LocalCredential, TenantMembership, ServiceAccount, and RolePrincipalBind.
Switch gateway/backend identity propagation to X-Auth-Principal and align agentic/controller security context types with PrincipalHeader.
- Add mcp-server.md: full design for exposing OpenAPI interfaces as MCP
tools through the gateway, covering architecture, database model,
permission control (reusing dc3_resource/dc3_role_resource_bind),
HTTP vs gRPC analysis, dynamic tool refresh, and observability
- Register MCP Service in VitePress sidebar config
- Add entry to design index page
Add loadResourcesByCodes() to query existing resources by resource_code
key during the sync cycle. When a scanned API maps to an existing resource
that was previously unlinked from the entity, reconcile by updating the
existing row instead of attempting a duplicate insert.
Finish moving io.swagger.v3.oas.annotations imports to alphabetical position
in remaining auth controllers. Add @Schema descriptions to SessionExt,
BaseVO, and Pages for richer OpenAPI schema generation.
Multiple scanned APIs can share the same resource_code when their apiName
values collide (e.g. two dashboard endpoints both resolve to 'dashboard:get').
Previously reconcileLeafResources inserted one resource row per API, which
violated the (resource_code, service_name) unique constraint.
Track seen resource keys with a LinkedHashSet during the insert-phase loop
and skip subsequent APIs that produce an already-seen resource_code.