# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Structure ``` core/ ├── dotCMS/ # Main backend Java code │ └── src/main/java/com/ │ ├── dotcms/ # Modern domain-driven packages (prefer these) │ └── dotmarketing/ # Legacy packages (15+ yr old code, still active) ├── core-web/ # Frontend (Angular/Nx monorepo) → see core-web/CLAUDE.md ├── dotcms-integration/ # Integration tests ├── dotcms-postman/ # Postman API tests ├── bom/application/pom.xml # Dependency versions (ONLY place for versions) ├── parent/pom.xml # Plugin management └── .github/workflows/ # CI/CD pipelines ``` ## Environment Prerequisites ```bash sdk env install # installs the Java version pinned in .sdkmanrc — build fails with wrong version nvm use # installs the Node version pinned in .nvmrc — frontend build fails with wrong version ``` ## Build & Test Commands ```bash # Build (choose based on scope) ./mvnw install -pl :dotcms-core --am -DskipTests # Core + in-project deps (~2-3 min) ✅ ./mvnw install -pl :dotcms-core -DskipTests # ⚠️ Can fail: missing in-project deps ./mvnw clean install -DskipTests # Full rebuild (~8-15 min) ./mvnw clean install -DskipTests -Ddocker.skip # Full rebuild, skip Docker image # Test (⚠️ NEVER run full integration suite — 60+ min) ./mvnw verify -pl :dotcms-integration -Dcoreit.test.skip=false -Dit.test=MyTestClass # Specific class ./mvnw verify -pl :dotcms-integration -Dcoreit.test.skip=false -Dit.test=MyTest#testMethod # Specific method ./mvnw verify -pl :dotcms-postman -Dpostman.test.skip=false -Dpostman.collections=all # Postman # IDE Testing (fastest iteration) just test-integration-ide # Start PostgreSQL + Elasticsearch + dotCMS just test-integration-stop # Stop services when done # Run just dev-run # Start dotCMS in Docker with Glowroot cd core-web && pnpm nx serve dotcms-ui # Frontend dev server only (Nx is not global — always via pnpm) ``` > All test modules need explicit `skip=false` flags or tests are silently skipped. ## Essential Java Patterns ```java import com.dotmarketing.util.Config; // Config.getStringProperty("key", "default") import com.dotmarketing.util.Logger; // Logger.info(this, "message") import com.dotmarketing.util.UtilMethods; // UtilMethods.isSet(value) UserAPI userAPI = APILocator.getUserAPI(); // Service access pattern ``` > **Batch permission filtering**: prefer `permissionAPI.filterCollection(Collection

, int, User, boolean)` over per-item `doesUserHavePermission` loops — one SQL round-trip vs N. See [Java Standards → Permission Checks](docs/backend/JAVA_STANDARDS.md#permission-checks--batch-vs-scalar). ## Critical Rules - **Config/Logger only**: Never `System.out`, `System.getProperty`, or `System.getenv` - **Maven versions**: Add to `bom/application/pom.xml` ONLY, never `dotCMS/pom.xml` - **Java version**: see `.sdkmanrc` for the runtime version. Core modules compile to whatever `dotcms.core.compiler.release` is set to in `parent/pom.xml` (override e.g. `-Ddotcms.core.compiler.release=11` for older bytecode); `tools/dotcms-cli` targets whatever `maven.compiler.release` is set to in its own `pom.xml`, historically lower for portability. - **Security**: No hardcoded secrets, validate all input, never log sensitive data - **REST @Schema**: Must match actual return type — see [REST API Guide](dotCMS/src/main/java/com/dotcms/rest/CLAUDE.md) - **Integration test registration**: A new integration test class not added to a `MainSuite*`/`Junit5Suite*` `@SuiteClasses` list compiles fine but is **silently never run in CI** (green build, zero coverage) — it only runs locally via `-Dit.test=`. See [Integration Tests → Registering Tests in a MainSuite](docs/testing/INTEGRATION_TESTS.md#registering-tests-in-a-mainsuite-ci-gate). - **Integration tests can silently run zero tests**: the Maven build cache may short-circuit failsafe (`Skipping plugin execution (cached): failsafe:integration-test`) — BUILD SUCCESS, `0`, exit 0. Pass `-Dmaven.build.cache.enabled=false`, prefer class-level over `-Dit.test=Class#method` selection, and confirm `Tests run: N` in `target/failsafe-reports/*.txt` rather than trusting the exit code. See [Integration Tests → The build cache can skip the tests entirely](docs/testing/INTEGRATION_TESTS.md#the-build-cache-can-skip-the-tests-entirely). - **Frontend**: See [core-web/CLAUDE.md](core-web/CLAUDE.md) for Angular/TypeScript standards ### OpenAPI / Swagger `openapi.yaml` is **auto-generated** by `swagger-maven-plugin` at compile phase — it writes directly to `src/main/webapp/WEB-INF/openapi/openapi.yaml`. The CI verifies the committed file matches what the build produces. - All description changes must go in Java `@Operation` / `@Parameter` annotations, not in the yaml directly - Regenerate after annotation changes: `./mvnw compile -pl :dotcms-core --am -DskipTests` (no Docker needed; `--am` avoids the same missing-in-project-deps failure noted above) - Commit the regenerated yaml alongside the Java changes ### Progressive Enhancement When editing ANY code, improve incrementally: - Add missing generics: `List` not `List` - Replace legacy: `Logger.info()` not `System.out.println()` - Modern Angular: `@if` not `*ngIf`, `input()` not `@Input()` - Add missing annotations: `@Override`, `@Nullable` - Add missing Javadoc on any Java method you edit, human-readable not AI-oriented — see [Java Standards → Javadoc Requirements](docs/backend/JAVA_STANDARDS.md#javadoc-requirements-required) ## Spec-Driven Development (Spec-Kit) This repo uses [GitHub Spec-Kit](https://github.com/github/spec-kit) for spec-driven work, customized for dotCMS. How to run it: [Spec-Kit Quick Start](docs/core/SPEC_KIT_QUICK_START.md). How it's built + upgrade re-apply notes: [.specify/CUSTOMIZATIONS.md](.specify/CUSTOMIZATIONS.md). - **Flow**: `/speckit-specify` (new feature) **or** `/speckit-specify-fix` (issue/bug resolution) → **PR 1 (spec) approved** → `/speckit-plan` → `/speckit-tasks` → `/speckit-implement` → `/speckit-converge` → PR 2 (implementation). - **Two PRs, gated on approval — not merge**: PR 1 carries `spec.md` **alone** and another dev must **approve** it before `/speckit-plan` runs. Do **not** wait for PR 1 to merge — branch off the spec branch (the spec isn't on `main` yet) and open PR 2 with the implementation. If the spec changes after sign-off, get it re-approved. **Before opening PR 2, run `/speckit-converge` on your final code** and get `converged` (or consciously accept what remains). Human-triggered and human-judged; nothing enforces it. See [Quick Start §3](docs/core/SPEC_KIT_QUICK_START.md). - **Constitution**: [.specify/memory/constitution.md](.specify/memory/constitution.md) — legacy-awareness + Critical Rules; loaded by every skill. - **Reporting**: never let a reference carry the meaning. Say what a thing is or does, then attach the pointer in parentheses — spec or task id, commit sha, CI run id, ADR number, path. The test is whether the reader could act on the sentence without opening the thing it names: "proving that ten files upload as ten is still pending (T065)", not "T065 is pending"; "ADR-0018 makes the DB authoritative for folder and host, so the scope belongs in the SQL builder", not "per ADR-0018". References are encouraged — paths, classes, methods, config keys and line numbers are checkable, and the repair for a bare one is to add the meaning beside it, never to drop it. See [Constitution → Reporting to the Developer](.specify/memory/constitution.md). - **TDD (Principle V, non-negotiable)**: no implementation code before tests are written, **dev-approved**, and confirmed **failing (Red)**. If a test type can't be done, the dev must say so and why. Enforced in the constitution + `tasks-template` `[GATE]` tasks + plan Test Strategy. - **Convergence (closing step — you trigger it)**: `/speckit-converge` checks the code against the approved spec. `/speckit-implement` **recommends** it on finishing (`after_implement` hook, `optional: true`) but does **not** run it — the end of the task list is rarely the end of your work, and a run fired before your manual corrections would assess code you're about to change. Run it when you judge the work done, fix, repeat until `converged`. **Append-only** — findings become tasks in `tasks.md`, never direct edits. See [Quick Start §9](docs/core/SPEC_KIT_QUICK_START.md). - **ADRs**: live only in the private repo `dotCMS/platform-adrs`. `/speckit-plan` **always consults** relevant ADRs (auto `before_plan` hook → `/speckit-adr-context`, read-only via `gh`). Spec-Kit **never creates ADRs** — it only *proposes* them; ADRs are authored in `platform-adrs` via its `new-adr.sh`. ## Tech Stack - **Backend**: Java (see `.sdkmanrc` / `parent/pom.xml`'s `dotcms.core.compiler.release`, override-able), Maven, CDI - **Frontend**: Angular (see `core-web/package.json`'s `@angular/core`), Nx, PrimeNG, Tailwind CSS, Jest/Spectator — [core-web/CLAUDE.md](core-web/CLAUDE.md) - **Infrastructure**: Docker, PostgreSQL, Elasticsearch, GitHub Actions ## Documentation (Load On-Demand) ### Core Architecture & Workflows - [Architecture Overview](docs/core/ARCHITECTURE_OVERVIEW.md) — System design, modules, patterns - [Git Workflows](docs/core/GIT_WORKFLOWS.md) — Branch naming, PR process, conventional commits - [CI/CD Pipeline](docs/core/CICD_PIPELINE.md) — Build process, testing, deployment - [Security Principles](docs/core/SECURITY_PRINCIPLES.md) — Input validation, secrets, logging - [GitHub Issue Management](docs/core/GITHUB_ISSUE_MANAGEMENT.md) — Issues, PRs, epics - [Rollback-Unsafe Change Categories](docs/core/ROLLBACK_UNSAFE_CATEGORIES.md) — DB schema, ES mapping, API contract risks ### Backend Development (Java/Maven) - [Java Standards](docs/backend/JAVA_STANDARDS.md) — Coding patterns, immutables, exceptions, utilities - [When to Use Virtual Threads](docs/backend/VIRTUAL_THREADS.md) — Socket I/O yes, file I/O no; carrier pinning - [REST API Patterns](docs/backend/REST_API_PATTERNS.md) — JAX-RS, Swagger, @Schema rules - [Inference API](docs/backend/INFERENCE_API.md) — OpenAI-compatible `/api/inference/v1` family: chat completions, streaming, models, embeddings, images; bearer-only auth, per-site resolution, limits - [Maven Build System](docs/backend/MAVEN_BUILD_SYSTEM.md) — Dependency management - [Configuration Patterns](docs/backend/CONFIGURATION_PATTERNS.md) — Config.getProperty() usage - [Database Patterns](docs/backend/DATABASE_PATTERNS.md) — DotConnect, transactions - [Health Monitoring](docs/backend/HEALTH_MONITORING.md) — Health endpoints, log levels - [Security Patterns](docs/backend/SECURITY_BACKEND.md) — Input validation, auth, SQL/XSS prevention, secure logging - [Search API Migration](docs/backend/SEARCH_API_MIGRATION.md) — ES → OpenSearch: deprecated `ContentletAPI` search methods, plugin migration guide - [Telemetry Implementation](docs/backend/TELEMETRY_IMPLEMENTATION.md) — CDI-based metrics system, creating new metrics, `/v1/usage` endpoints - [Index Field Emission](docs/backend/INDEX_FIELD_EMISSION.md) — how `loadFields`/`toMap` build the index document; the `_dotraw` zero-padding sort invariant - [Jandex Metadata Scanning](docs/backend/JANDEX_METADATA_SCANNING.md) — Fast class/annotation metadata lookup, prefer over reflection - **ES → OpenSearch Migration** — infra migration from ElasticSearch to OpenSearch, phased dual-write/read rollout - [Migration Design](docs/backend/OPENSEARCH_MIGRATION.md) — Architecture, phased rollout, configuration - [Migration Test Plan](docs/backend/OPENSEARCH_MIGRATION_TEST_PLAN.md) — QA test plan for the migration phases - [Client Configuration](docs/backend/OPENSEARCH_CLIENT_CONFIGURATION.md) — `OS_*`/`ES_*` config property reference and fallback chain - [Migration Tester Guide](docs/backend/OPENSEARCH_MIGRATION_TESTER_GUIDE.md) — Getting-started guide for QA testers validating the migration - [System Events](docs/backend/SYSTEM_EVENTS.md) — Cross-node event queue: at-least-once delivery, consumer idempotency rules, payload deserialization ### Frontend Development (Angular/TypeScript) - **[docs/frontend/README.md](docs/frontend/README.md) — index of all frontend docs and when to load each. Start here if unsure.** - [Angular Standards](docs/frontend/ANGULAR_STANDARDS.md) — **single source of truth**: syntax, signals, change detection, forms, icons - [Component Architecture](docs/frontend/COMPONENT_ARCHITECTURE.md) — Structure, file layout, data flow - [State Management](docs/frontend/STATE_MANAGEMENT.md) — NgRx Signal Store, rxMethod, patchState - [Styling Standards](docs/frontend/STYLING_STANDARDS.md) — Tailwind, PrimeNG theme, BEM, SCSS, **form markup** (global `.form` / `.field`, labels, hints/errors, accessible naming) - [TypeScript Standards](docs/frontend/TYPESCRIPT_STANDARDS.md) — Strict types, as const, `#` private - [Testing Frontend](docs/frontend/TESTING_FRONTEND.md) — Writing tests: Spectator, Jest, byTestId - [Testing Review Rules](docs/frontend/TESTING_REVIEW_RULES.md) — Reviewing tests: violation checklist - [Breadcrumbs](docs/frontend/BREADCRUMBS.md) — GlobalStore breadcrumb trail ### Testing - [Backend Unit Tests](docs/testing/BACKEND_UNIT_TESTS.md) — Surefire in `:dotcms-core`, Mockito setup, naming (there is no category/tag mechanism), running and debugging - [Integration Tests](docs/testing/INTEGRATION_TESTS.md) — Running/debugging tests, MainSuite registration, API testing, database setup - [E2E Tests](docs/testing/E2E_TESTS.md) — Playwright, user workflows ### CLI (`tools/dotcms-cli`) - [CLI Overview](docs/cli/CLI_OVERVIEW.md) — Quarkus + PicocLI architecture, module layout, command patterns. **Compiles to a lower `maven.compiler.release` than the core modules** — read the property before using modern syntax - [CLI Build System](docs/cli/CLI_BUILD_SYSTEM.md) — Maven profiles (`dist`, `native`, `release`), Quarkus dev mode, native image, testcontainers ### Infrastructure - [Docker Build Process](docs/infrastructure/DOCKER_BUILD_PROCESS.md) — Container setup, optimization ## Context Management ### For Claude - Use this guide for always-available context - Load `/docs/` files on-demand with Read tool - Use `/clear` between different work contexts ### For Cursor - Project rules: `.cursor/rules/` (`.mdc` files with globs); see `.cursor/rules/README.md` - Use `@docs/path/file.md` syntax for detailed patterns - Domain-specific rules load by file pattern (Java, Angular, tests, docs) ## Documentation Maintenance - **CLAUDE.md**: Navigation hub + essential quick-reference only - **`/docs/`**: Full patterns by domain — single source of truth - **`.cursor/rules/`**: Short reminders with globs, link to `/docs/` - When patterns are missing: update the relevant `/docs/{domain}/` file, not this file