# AGENTS.md This document provides guidance for agentic coding tools working on the UrbanOps (urbanops) codebase. ## Build & Test Commands ### Build Commands ```bash # Clean and compile all modules mvn clean compile # Build entire project (skipping tests) mvn clean install -DskipTests # Build specific module with dependencies mvn clean install -DskipTests -pl -am ``` ### Test Commands ```bash # Run all tests mvn test # Run all tests for a specific module mvn test -pl urbanops-module-system # Run a single test class mvn test -Dtest=AdminUserServiceImplTest # Run a single test method mvn test -Dtest=AdminUserServiceImplTest#testCreateUser # Run tests with specific profile mvn test -Punit-test ``` ## Project Structure - `urbanops-server` - Main Spring Boot application entry point - `urbanops-module-system` - System management (users, roles, permissions, etc.) - `urbanops-module-infra` - Infrastructure (files, jobs, configs, code generation) - `urbanops-module-bpm` - Business Process Management (Flowable) - `urbanops-module-xxx` - Business domain modules (garden, workorder, report, etc.) - `urbanops-framework` - Shared framework components (security, redis, mybatis, etc.) - `urbanops-dependencies` - Maven dependency version management ## Code Style Guidelines ### Package Structure ``` com.zteits.urbanops.module.{module-name} ├── controller/admin - Admin API controllers ├── controller/app - App API controllers ├── controller/bridge - Legacy bridge controllers ├── service/.../impl - Service implementations ├── dal/dataobject - Database entities (DO classes) ├── dal/mysql - MyBatis mappers ├── controller/.../vo - View Objects (Request/Response VOs) ├── convert - MapStruct converters └── enums - Module-specific enums ``` ### Naming Conventions - **Controllers**: `XxxController` (e.g., `UserController`) - **Services**: `XxxService` (interface) and `XxxServiceImpl` (implementation) - **Mappers**: `XxxMapper` (e.g., `AdminUserMapper`) - **Data Objects**: `XxxDO` (e.g., `AdminUserDO`) - **View Objects**: `XxxPageReqVO`, `XxxSaveReqVO`, `XxxRespVO`, `XxxSimpleRespVO` - **Converters**: `XxxConvert` (MapStruct interface) ### Code Organization - DO classes extend `TenantBaseDO` or `BaseDO`, use `@TableName`, `@KeySequence`, `@Data`, `@EqualsAndHashCode(callSuper = true)`, `@Builder` - VO classes use `@Schema` for documentation, `@NotBlank`/`@NotNull`/`@Size` for validation - Controllers use `@Tag`, `@Operation`, `@PreAuthorize`, `@Valid`, `CommonResult` for responses - Services use `@Service`, `@Slf4j`, `@Transactional(rollbackFor = Exception.class)`, `@Resource` ### Error Handling - Use `exception(ErrorCode)` from `ServiceExceptionUtil` to throw business exceptions - Define error codes in module's `ErrorCodeConstants` interface - Error code format: `1-002-xxx-xxx-xxx` (system module: 1-002-xxx-xxx-xxx) ### Imports & Dependencies - Organize: standard library → third-party → project packages - No wildcard imports (e.g., avoid `import java.util.*`) - Use Jakarta EE: `jakarta.*` imports - Use Spring Boot 3.x and Spring Framework 6.x APIs ### Validation - Use Jakarta Bean Validation: `@NotNull`, `@NotBlank`, `@Size`, `@Pattern`, `@Email` - Use `@Valid` for nested object validation - Use `@AssertTrue` for complex validation with custom methods ### Lombok Usage - `@Data` for POJOs, `@Builder` for construction, `@EqualsAndHashCode(callSuper = true)` for DOs - Configured in `lombok.config`: `lombok.accessors.chain=true`, `lombok.tostring.callsuper=CALL` ### Testing Guidelines - Extend `BaseMockitoUnitTest` (no DB) or `BaseDbUnitTest` (H2 database) - Use JUnit 5: `@Test`, `@BeforeEach`, `@BeforeAll` - Naming: `test{MethodName}_{scenario}` - Use `assertPojoEquals()` for comparing DOs, `assertServiceException()` for exceptions - Clean up test data via `@Sql` with `/sql/clean.sql` ### Database - Use MyBatis Plus, mappers extend `BaseMapper` - Use `TenantBaseDO` for multi-tenant tables, `BaseDO` for single-tenant ### Security - Use `@PreAuthorize` with format `{module}:{resource}:{action}` (e.g., `system:user:create`) - Inject current user: `SecurityFrameworkUtils.getLoginUserId()` ### Date/Time - Use `java.time`, `LocalDateTime` for timestamps - Format: `DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND`, `@DateTimeFormat` ### Logging - Use `@Slf4j`, levels: `ERROR`, `WARN`, `INFO`, `DEBUG` - Log meaningful context, avoid sensitive info (passwords, tokens, PII) ### API Documentation - Use OpenAPI 3.0: `@Tag`, `@Operation`, `@Parameter`, `@Schema` - Chinese descriptions in `@Schema`, mark required with `requiredMode`, provide `example` values ### Module Communication - Use module APIs (`urbanops-module-api`) for cross-module communication - Use `@Lazy` to avoid circular dependencies ### Adding New Features 1. Create DO class in `dal/dataobject` 2. Create Mapper interface in `dal/mysql` 3. Create Service interface and implementation 4. Create VO classes in `controller/.../vo` 5. Create Controller class 6. Create Convert interface (MapStruct) 7. Write unit tests extending appropriate base class 8. Add error codes to `ErrorCodeConstants` ### Common Pitfalls - Forgetting `@Transactional` on modifying service methods - Using wrong DO base class (`BaseDO` vs `TenantBaseDO`) - Not using `@Valid` for request body validation - Not handling exceptions appropriately - Direct database access bypassing Service layer - Using `System.out.println` instead of logger