diff --git a/AGENTS.md b/AGENTS.md index 423f0d6b5..6b745d672 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,574 +1,387 @@ # AGENTS.md -Shared engineering instructions for AI coding agents working in this repository. +Canonical engineering instructions for AI coding agents working in IoT DC3. -This is the canonical project guidance file. Keep tool-specific files such as `CLAUDE.md` as thin compatibility pointers -to this file so various AI coding assistants follow the same rules. +## Scope and precedence -## Project Snapshot +- This file applies to the whole repository. +- Follow the user's request first, then this repository-level guidance. +- Keep changes focused. Do not revert unrelated work in a dirty worktree. +- Do not create a Git commit without the explicit, commit-specific confirmation described below. -IoT DC3 is a distributed industrial IoT platform for device connectivity, data collection, metadata management, and -gateway access. The project is built around Spring Boot services, gRPC contracts, RabbitMQ messaging, PostgreSQL -persistence, and Docker/Podman Compose deployment. +## Sources of truth -Primary runtime layers: +Avoid copying volatile versions or generated state into documentation. Verify them at the source: -- **Gateway**: HTTP entrypoint through Spring Cloud Gateway. -- **Auth Center**: tenant, token, user, role, resource, and API authorization. -- **Manager Center**: driver, device, point, profile, and metadata coordination. -- **Data Center**: point value ingestion, query, command dispatch, and data dashboards. -- **Agentic Center**: AI-assisted operations backed by OpenAI-compatible APIs. -- **Drivers**: protocol adapters for Modbus TCP, MQTT, OPC DA/UA, PLC S7, CoAP, listening-virtual, and virtual drivers. +| Concern | Source of truth | +|---|---| +| Java, Spring, Maven plugins and reactor modules | root `pom.xml` and affected module POMs | +| Backend build commands | root `Makefile` | +| Frontend dependencies and scripts | `dc3-web/package.json` and `dc3-web/pnpm-lock.yaml` | +| Frontend build image/tool pins | `dc3-web/Dockerfile` | +| Containers and registries | root `Makefile`, `.env.example`, and `dc3/docker-compose*.yml` | +| CI behaviour | `.github/workflows/` | +| Release notes | `dc3/bin/changelog.py` and generated `dc3/doc/CHANGE.md` | -Core stack: +If this file disagrees with executable configuration, treat the executable configuration as current and update this +file as part of the same change when appropriate. -- Java 21 -- Maven 3.9+ -- Spring Boot / Spring Cloud (versions managed by the `dc3-parent` POM — check `pom.xml`) -- Spring Framework 7 -- PostgreSQL, RabbitMQ, optional EMQX, optional Grafana/Elasticsearch stacks -- Spring gRPC with generated protobuf APIs -- Compose runtime, wrapped by the root `Makefile` (`COMPOSE=podman compose` by default) +## Project overview -## Repository Map +IoT DC3 is a distributed industrial IoT platform. Its main runtime areas are: -``` +- Gateway: HTTP entrypoint through Spring Cloud Gateway. +- Auth Center: tenant, token, user, role, resource, and API authorization. +- Manager Center: drivers, devices, points, profiles, and metadata. +- Data Center: point-value ingestion, queries, commands, and dashboards. +- Agentic Center: AI-assisted operations through OpenAI-compatible APIs. +- Drivers: protocol adapters built on the shared driver SDK. +- Web: Vue-based management UI in `dc3-web/`. + +The backend targets Java 21 and is a Maven multi-module Spring Boot/Spring Cloud project. Check the root POM for current +framework versions. + +## Repository map + +```text iot-dc3/ -├── dc3-api/ # Protobuf & gRPC contracts -│ ├── dc3-api-auth # auth service proto -│ ├── dc3-api-data # data service proto -│ ├── dc3-api-driver # driver service proto -│ └── dc3-api-manager # manager service proto -├── dc3-common/ # Shared libraries -│ ├── dc3-common-model # Base BO/VO/DTO/Builder/Ext classes -│ ├── dc3-common-public # BaseService, R envelope, TenantOwned -│ ├── dc3-common-web # BaseController (reactive), WebFlux config -│ ├── dc3-common-auth # Token gRPC server, auth controllers -│ ├── dc3-common-manager # Device/Driver/Point/Profile services + DAL -│ ├── dc3-common-data # Point value ingestion, command dispatch -│ ├── dc3-common-driver # Driver SDK (SPI interfaces + runtime) -│ ├── dc3-common-facade/ # Cross-service facade -│ │ ├── dc3-common-facade-api # Interface contracts -│ │ ├── dc3-common-facade-grpc # gRPC implementations -│ │ ├── dc3-common-facade-local-auth # In-process auth facade -│ │ ├── dc3-common-facade-local-data # In-process data facade -│ │ └── dc3-common-facade-local-manager # In-process manager facade -│ ├── dc3-common-dal # Shared label/group DAL -│ ├── dc3-common-postgres # MyBatis-Plus configuration -│ ├── dc3-common-rabbitmq # RabbitMQ config and constants -│ ├── dc3-common-mqtt # MQTT config -│ ├── dc3-common-repository # Point value repository abstraction -│ ├── dc3-common-quartz # Scheduling infrastructure -│ ├── dc3-common-test # Testcontainers, harnesses, contract test bases -│ ├── dc3-common-agentic # AI-assisted operations -│ ├── dc3-common-gateway # Gateway utilities -│ ├── dc3-common-log # Logging configuration -│ ├── dc3-common-exception # Exception hierarchy -│ ├── dc3-common-constant # Shared constants -│ ├── dc3-common-sql # SQL utilities -│ ├── dc3-common-thread # Thread pool config -│ ├── dc3-common-api # API utilities -│ └── dc3-common-resource-registrar # Resource registration -├── dc3-center/ # Deployable service applications -│ ├── dc3-center-auth # Auth service -│ ├── dc3-center-manager # Manager service -│ ├── dc3-center-data # Data service -│ ├── dc3-center-agentic # AI-assisted operations service -│ └── dc3-center-single # All-in-one single process -├── dc3-driver/ # Protocol driver implementations -│ ├── dc3-driver-modbus-tcp # Modbus TCP -│ ├── dc3-driver-modbus-rtu # Modbus RTU -│ ├── dc3-driver-mqtt # MQTT -│ ├── dc3-driver-opc-ua # OPC UA -│ ├── dc3-driver-opc-da # OPC DA -│ ├── dc3-driver-plcs7 # S7 PLC -│ ├── dc3-driver-coap # CoAP -│ ├── dc3-driver-virtual # Virtual (simulator) -│ ├── dc3-driver-listening-virtual # Listening virtual -│ └── ... (20+ more protocol drivers) -├── dc3-gateway/ # Spring Cloud Gateway (HTTP entrypoint) -├── dc3-coverage/ # JaCoCo aggregate coverage report -├── dc3-e2e/ # Testcontainers-backed E2E tests -├── dc3/ # Compose files, env, scripts, docs -│ ├── docker-compose.yml # Main app stack -│ ├── docker-compose-db.yml # Database services -│ ├── docker-compose-dev.yml # Development overrides -│ ├── docker-compose-optional.yml # Optional monitoring/messaging -│ ├── env/dev.env # IDE-friendly local env vars -│ └── bin/ # changelog.py, tag.sh -├── Makefile # Preferred command entrypoint -├── .husky/ # Git hooks (pre-commit runs lint-staged) -└── .mvn/settings.xml # Local Maven mirror (mainland China) +├── dc3-api/ protobuf and gRPC contracts +├── dc3-common/ shared models, services, DAL, facades, driver SDK, and infrastructure +├── dc3-center/ deployable auth, manager, data, agentic, and single-process applications +├── dc3-driver/ protocol driver implementations +├── dc3-gateway/ HTTP gateway +├── dc3-web/ Vue/TypeScript frontend +├── dc3-coverage/ aggregate JaCoCo report and absolute coverage gate +├── dc3-e2e/ Testcontainers-backed end-to-end tests +├── dc3/ compose files, environment files, scripts, and generated release notes +├── Makefile preferred backend/container command entrypoint +└── .mvn/settings.xml local Maven mirror configuration ``` -## Layering Architecture +## Backend architecture -All business modules follow a strict four-layer pattern: +### Layering -``` -Controller (WebFlux, Mono>) → Service (BO) → Manager (DO, MyBatis-Plus) → Mapper (SQL) +Business modules follow this flow: + +```text +Controller (WebFlux) -> Service (BO) -> Manager (DO) -> Mapper (SQL) ``` -### Key Base Classes +- Controllers implement the `BaseController` interface and return `Mono>`. +- Use `BaseController.async(...)` to move blocking JDBC work to the bounded-elastic scheduler. +- Services extend `BaseService`, work in business objects, and own business rules. +- Managers extend MyBatis-Plus `IService`; implementations extend `ServiceImpl`. +- Mappers extend MyBatis-Plus `BaseMapper` and contain persistence-level SQL operations. +- Do not expose persistence objects from controllers or facade contracts. -| Class | Module | Purpose | -|---------------------------------|---------------------|---------------------------------------------------------------------------------------| -| `BaseService` | `dc3-common-public` | CRUD interface: `add`, `delete`, `update`, `getById`, `list(Q)` | -| `BaseController` | `dc3-common-web` | Reactive controller interface with `getUserHeader`, `requireTenant`, `async` defaults | -| `R` | `dc3-common-public` | Response envelope: `ok`, `code`, `message`, `data` — use `R.ok(data)` / `R.fail(msg)` | -| `BaseBO` / `BaseVO` / `BaseDTO` | `dc3-common-model` | Shared fields: `id`, `remark`, `creatorId/Name/Time`, `operatorId/Name/Time` | -| `BaseBuilder` | `dc3-common-model` | MapStruct `@Mapper(componentModel = "spring")` for VO↔BO↔DTO conversion | -| `BaseExt` | `dc3-common-model` | JSON extension column: `type`, `version`, `remark` | -| `TenantOwned` | `dc3-common-public` | Marker interface for tenant-scoped entities; used by `BaseController.requireTenant()` | +Common types: -### Controller Layer +| Type | Module | Role | +|---|---|---| +| `BaseService` | `dc3-common-public` | base CRUD service contract | +| `BaseController` | `dc3-common-web` | reactive controller helpers and user/tenant context | +| `R` | `dc3-common-public` | standard response envelope; use `R.ok(...)` and `R.fail(...)` | +| `BaseBO`, `BaseVO`, `BaseDTO` | `dc3-common-model` | shared business, web, and transfer fields | +| `BaseBuilder` | `dc3-common-model` | MapStruct conversion base | +| `TenantOwned` | `dc3-common-public` | marker for tenant-scoped entities | -Controllers implement the `BaseController` interface (Java interface with default methods, not an abstract class). They -return `Mono>`. The `async()` helper offloads blocking JDBC calls to the `boundedElastic` scheduler. Example: +### Tenant safety -```java -public Mono> getById(@PathVariable Long id) { - return async(() -> R.ok(deviceService.getById(id))); -} +Tenant isolation is a hard requirement. + +- Preserve tenant scope in every new query and mutation. +- Carry tenant IDs through gRPC requests whenever the contract supports them. +- Include tenant context in cache keys for tenant-owned data. +- Validate ownership before returning or mutating data across service boundaries. +- Do not add `tenantId IS NULL` shortcuts unless the data model explicitly defines global records. +- Treat missing tenant validation as a correctness and security defect, not a convenience trade-off. + +### Facade boundaries + +Business code must use facade interfaces for cross-service calls. + +- Contracts belong in `dc3-common-facade-api`. +- Transport-backed implementations belong in `dc3-common-facade-grpc`. +- In-process implementations belong in the matching module: + `dc3-common-facade-local-auth`, `dc3-common-facade-local-data`, or + `dc3-common-facade-local-manager`. +- `dc3-common-facade-local` is a dependency aggregator and does not contain implementation sources. +- Keep controllers and services independent from transport details unless they are explicit transport adapters. + +### gRPC contracts + +Proto files live under `dc3-api/*/src/main/protobuf`. + +When changing a contract: + +1. Update the `.proto` file. +2. Compile the affected API module to regenerate sources. +3. Update server implementations and client builders/stubs together. +4. Preserve backward compatibility where practical. +5. Verify tenant propagation and the `GrpcR` error envelope. + +Servers are Spring beans extending generated `*ImplBase` classes. Reuse shared stub configuration; do not construct ad +hoc channels in business code. + +### Driver SDK + +Drivers implement protocol behaviour through the SPI types in `dc3-common-driver`; shared runtime services handle +registration, scheduling, and value dispatch. + +Primary extension points are `DriverProtocol`, `DriverLifecycle`, `DriverMetadataListener`, `DriverHealth`, +`DeviceHealth`, and `DriverCommand`. Prefer existing SDK plumbing over driver-specific infrastructure. + +Driver `application.yml` metadata is user-facing: + +- Keep `name`, `attribute-name`, and `remark` in English. +- Treat driver `code` values as routing-stable identifiers. Changing one requires a metadata and RabbitMQ migration + plan. + +## API and domain conventions + +### CRUD verbs + +CRUD-shaped names reflect result cardinality across Service, Controller, Facade, gRPC server, and proto RPCs: + +| Action | Java | HTTP | gRPC | +|---|---|---|---| +| create one | `add(BO)` | `/add` | n/a | +| delete by ID | `delete(Long)` | `/delete` | n/a | +| update one | `update(BO)` | `/update` | n/a | +| return one | `getXxx(...)` | `/get_xxx` | `GetXxx` | +| return many | `listXxx(...)` | `/list_xxx` | `ListXxx` | + +- Base CRUD comes from `BaseService`: `add`, `delete`, `update`, `getById`, and `list(Q)`. +- Reserve `select*` for raw Mapper/Manager persistence operations. +- Reserve MyBatis-Plus `remove*` for the Manager layer; business deletion uses `delete*`. +- Do not introduce `find*`, `query*`, or `fetch*` as primary CRUD verbs. +- HTTP paths are lowercase snake_case and mirror Java names. +- Use `getStatusByPage(Q)` for status maps and `dispatchRead`/`dispatchWrite` for command dispatch, following existing + contracts. + +### Models and enums + +- DOs model database storage; BOs model business semantics; VOs/DTOs model web or transport input/output. +- Persistent write paths accept BOs in services. Controllers and transport adapters convert VO/DTO input to BO. +- Read-only projections may return VOs directly when a duplicate BO would add no business meaning. +- Use MapStruct builders for VO/BO/DO conversion, including enum/index conversion. +- Do not leak database-coded `Byte`, `Integer`, or `String` flags when a domain enum exists or should exist. +- `*FlagEnum` is for boolean-like toggles, `*StatusEnum` for state machines, and `*TypeEnum` for classifications. +- Enum constants use descriptive `UPPER_SNAKE_CASE`; enum `code` values use lowercase tokens. +- Do not introduce magic flag constants such as `private static final Byte DEFAULT = 1`. +- Do not expose secrets in VOs. Exclude `apiKey`, `password`, `secret`, `token`, and credential fields from serialization + and Lombok `@ToString`. + +### Web API and OpenAPI + +- Controllers return the standard `R` envelope and never expose DOs. +- Apply grouped validation consistently and keep validation/exception messages in English. +- Document REST endpoints with springdoc annotations; do not maintain a parallel handwritten OpenAPI spec. +- Each business controller package needs the appropriate `GroupedOpenApi` bean, gateway aggregation route, and Swagger + UI entry. +- Shared WebFlux/springdoc configuration belongs in `dc3-common-web` and must be registered through + `AutoConfiguration.imports` when component scanning will not discover it. +- Docs are enabled in development-style profiles and disabled in production. Export a running stack with `make openapi`. + +### Configuration and logging + +- Custom configuration-property prefixes use `dc3.*`. +- Prefer validated, typed `@ConfigurationProperties` over scattered `@Value` fields. +- YAML deployment values use `${ENV:default}` placeholders. +- WebFlux base paths use `spring.webflux.base-path`, not `server.servlet.context-path`. +- Use English, stable event names and parameterized SLF4J messages. +- Prefer structured fields such as `tenantId={}, userId={}, deviceId={}`. +- Never log tokens, passwords, credentials, full request bodies, or raw private payloads at info level. +- Pass caught exceptions to warn/error logs unless stack-trace suppression is intentional. + +## Frontend conventions + +Frontend code lives in `dc3-web/`. Its executable configuration is the source of truth: + +- dependencies, package-manager version, and scripts: `dc3-web/package.json` and `pnpm-lock.yaml`; +- TypeScript behaviour: `dc3-web/tsconfig.json`; +- Vite, proxy, environment, and SCSS behaviour: `dc3-web/vite.config.ts`; +- test configuration: `dc3-web/vitest.config.ts` and `playwright.config.ts`; +- container toolchain pins: `dc3-web/Dockerfile`. + +Use pnpm only; do not create npm or Yarn lockfiles. Keep package-manager pins aligned between `package.json` and the +Dockerfile. + +Key rules: + +- `verbatimModuleSyntax` is enabled. Use `import type` for every type-only import; Vue components, functions, and icons + remain normal value imports. +- Use `Form` for create/update payloads and `Record` for read responses. +- Represent Java 64-bit IDs as strings and preserve the existing JSONBigInt handling. +- API wrappers mirror backend cardinality: `getXxx` for one value, `listXxx` for collections/maps/pages, and + `addXxx`/`updateXxx`/`deleteXxx` for mutations. +- Reuse CRUD helpers from `src/api/common.ts` and API bases from `src/config/constant/api.ts`; keep API wrappers thin. +- Prefer `