> For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt.

# Cloud Manager, Pipelines and CI/CD

## 26 – Cloud Manager, Pipelines and CI/CD

> **Target:** 3–4 years experienced AEM Developer **Covers from your additional list:** Cloud Manager in depth · pipeline types and quality gates · Git branching strategy · environments · what CI/CD actually looks like on an AEM project. **Project domain:** a global energy technology company's marketing site.

***

## Before we start — why this is a different kind of CI/CD

If you've worked with Jenkins, GitHub Actions, GitLab CI, or Azure DevOps on other projects, you already have a mental model of CI/CD: a YAML file sits in the repository, it defines stages, and you own that file completely — you can add a step, change an order, point it at a different test suite, whenever you like.

**Cloud Manager doesn't work that way, and the first thing worth being honest about in an interview is that this is a deliberate difference, not a missing feature.** The pipeline stages, the quality gates, and the environments are configured through Cloud Manager itself — the UI and its API — not through a pipeline file living in your Git history. You bring the code; Adobe brings the pipeline. That trade shows up everywhere in this file: less flexibility than a hand-rolled Jenkins pipeline, but a guarantee that every AEM as a Cloud Service customer is releasing through the same disciplined, tested path, and that nobody can quietly disable the code quality gate the week before a deadline.

**Why this is worth knowing cold for a 3-4 year interview.** File 14 already covered _that_ Cloud Manager pipelines are the only route to production and _why_ that's both a benefit and a constraint. This file is the follow-up an interviewer asks next: _"okay, walk me through what's actually in that pipeline"_ and _"how do you organise your branches so that works?"_ Those two questions are where a candidate who has only read about Cloud Service gets caught, because the honest answer needs the mechanics, not just the marketing line about "faster releases."

**One more framing point before we start, because it will save you in a follow-up.** A branching strategy for Cloud Manager is not something Adobe hands you — it's something your team designs, because Cloud Manager's actual rule is much smaller than people assume: **a pipeline is wired to one Git branch.** Everything else — how many branches you keep, what a release looks like, how a fix gets from a feature branch to production — is a decision your project makes on top of that one rule. Say that distinction out loud in an interview and you sound like someone who has actually set one of these up, rather than someone reciting a diagram.

***

## 1. Introduction

### 1.1 What Cloud Manager actually is

Cloud Manager is Adobe's **control plane** for AEM as a Cloud Service. It is not a separate product you install — it's the console (and API) that sits in front of four things:

- **A Git repository** — either the one Cloud Manager provisions for you, or an integration with your own GitHub/GitLab/Bitbucket repository on higher tiers.
- **Pipelines** — the build-test-deploy sequences that turn a commit into a running environment.
- **Environments** — the actual AEM instances (author, publish, dispatcher) that a pipeline deploys to.
- **Monitoring and logs** — dashboards, downloadable logs, and alerting for the environments it manages.

If you remember one sentence for an interview: **Cloud Manager is the only door into a Cloud Service environment**, and everything in this file is really just an explanation of what's behind that door.

### 1.2 The four-level hierarchy

Cloud Manager organises everything under a **Program**. Understanding this hierarchy is what turns "I've used Cloud Manager" into an answer that survives a follow-up question:

flowchart TD Program\["Program\n(one logical project — e.g. the energy company's main marketing site)"] Program --> EnvDev\["Environment: Development\n(persistent or RDE-backed, depending on tier)"] Program --> EnvStage\["Environment: Stage\n(mirrors production topology)"] Program --> EnvProd\["Environment: Production\n(author + publish + dispatcher, customer-facing)"] Program --> PipeNonProd\["Non-production pipeline\n(builds, tests, deploys to Dev/Stage)"] Program --> PipeProd\["Production pipeline\n(builds, tests, deploys to Stage, gate, then Production)"] PipeNonProd -.wired to.-> EnvStage PipeProd -.wired to.-> EnvProd GitBranch\["A Git branch"] -.triggers.-> PipeNonProd GitBranch2\["A different Git branch"] -.triggers.-> PipeProd

A **Program** is a single project — in our energy-sector example, "the corporate marketing site" would be one program, and a separate microsite or headless project might be a second program with its own environments and pipelines. Each program has its own environments and its own pipelines, and a pipeline is always wired to exactly one Git branch and one target environment.

### 1.3 Why "no pipeline file in the repo" is the right way to think about it

Your `pom.xml`, your `core` module, your `ui.apps` filters — all of that lives in Git, exactly as file 25 described. What does **not** live in Git is the definition of the pipeline stages themselves. You configure:

- which branch feeds which pipeline,
- whether a pipeline is "non-production" or "production" type,
- optional custom steps (a webhook call to an external system, for instance),
- and quality gate thresholds, on plans where that's configurable,

all through the Cloud Manager UI or its REST API — never through a file a developer edits and merges like a `Jenkinsfile`. That is a genuine constraint on flexibility, and it's also the reason a Cloud Service pipeline can't be quietly weakened by a rushed pull request the way a self-hosted Jenkinsfile sometimes can.

### 1.4 A real project example, end to end

**Requirement.** A component team needed to ship a new "Compare Products" panel across the corporate site to twenty country sites.

**What made it a genuine CI/CD story, not just a code story.** The panel touched `core` (a new Sling Model), `ui.apps` (the component and its dialog), and `ui.frontend` (new clientlib JS/CSS). Three modules, one change, one pipeline run.

**The approach.** Developers worked on feature branches, opened pull requests into a shared `develop` branch that fed the **non-production pipeline**, which deployed automatically to the Stage environment on every merge. QA validated on Stage. When a release was ready, `develop` was merged into `main`, which fed the **production pipeline** — full-stack build, both quality gates, deploy to Stage again for a final check, a manual approval gate, then a rolling deployment to Production.

**The hard part.** The first attempt at the production pipeline failed at the code quality gate — not because of a bug, but because the SonarQube rule set flagged a security hotspot in a new HTTP call that hadn't been reviewed. The pipeline doesn't ask "is this actually a problem" — it enforces the rule, and a human has to either fix the code or mark the hotspot reviewed in SonarQube before the gate passes.

**What we learned.** The team started running the same SonarQube ruleset locally (via a Maven plugin, matched to the same rules Cloud Manager applies) before opening a pull request, rather than discovering findings only when the pipeline ran — which is a theme that comes back properly in file 28.

**Result.** The panel shipped through the pipeline as designed, with zero manual deployment steps and a complete audit trail of exactly which commit produced the production build — something a pre-Cloud-Service, hand-deployed release never had.

***

## 2. Core Concepts

### 2.1 Programs and environments

Every Cloud Service customer has at least one **Program**. Inside it, the environments available depend on the customer's tier:

- **Production** — always present. The environment customers actually see.
- **Stage** — always present on a production program. Same topology as production (author, publish, dispatcher), used to validate a release before it goes live.
- **Development** — present on higher tiers as a persistent environment; on smaller tiers, day-to-day development iteration happens through **RDE** instead (file 14), and a persistent Dev environment may not exist at all.

**The point worth making explicitly:** Stage is not a "nice to have" testing environment — it's a structural part of every production pipeline. A production deployment cannot skip it. Every production release is deployed to Stage first, inside the same pipeline run, before the approval gate.

### 2.2 The Git repository

Cloud Manager provisions a Git repository for the program (or integrates with an existing GitHub/GitLab/Bitbucket repository on Enterprise tier). Locally, this is just another remote:

```bash
git remote add cloudmanager https://git.cloudmanager.adobe.com/<org>/<program>.git
git push cloudmanager main
```

Pushing to a branch does nothing by itself — a push only triggers a pipeline if that branch is currently wired to one in the Cloud Manager UI. This is the detail that trips people coming from GitHub Actions: there, _any_ push can trigger a workflow because the trigger rules live in the pushed code itself (`.github/workflows/*.yml`). Here, the trigger rule lives in Cloud Manager's configuration, entirely outside the commit.

### 2.3 Pipeline types

Four pipeline types matter for a developer to know by name and purpose, because "which pipeline handles X" is a very common follow-up:

| Pipeline type             | What it builds and deploys                                                                | Why it exists                                                           |
| ------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| **Full-stack**            | `core`, `ui.apps`, `ui.content`, `ui.config`, dispatcher config — the whole `all` package | The default pipeline for an application change                          |
| **Front-end**             | Just the `ui.frontend` module (the npm/webpack build)                                     | Front-end developers iterate on CSS/JS without waiting for a Java build |
| **Web-tier (dispatcher)** | Only the `dispatcher` module                                                              | A cache rule or filter change doesn't need a full application rebuild   |
| **Config**                | Only OSGi configuration (`ui.config` / `config.<runmode>` sources)                        | A configuration change is common and should be fast                     |

**The concept underneath all four:** a full-stack rebuild for a one-line dispatcher filter change is wasteful and slow, so Cloud Manager gives you narrower pipelines for narrower changes. Knowing this list by name, and being able to say _why_ a dispatcher rule change should go through the web-tier pipeline rather than full-stack, is the kind of practical detail that separates "I've read about Cloud Manager" from "I've shipped through one."

### 2.4 Non-production vs. production pipelines

Independent of _what_ a pipeline builds, every pipeline is also either:

- **Non-production** — builds, runs the quality gates, deploys to Development and/or Stage. Never touches Production. Used continuously, often on every merge to a shared branch.
- **Production** — everything a non-production pipeline does, **plus** a deployment to Production after an approval gate.

The practical reason both exist: you want the fast feedback of the quality gates on every merge, without a Production deployment happening every single time. A team typically runs the non-production pipeline constantly against an integration branch, and only promotes to the production pipeline — usually by merging into a release/main branch — when a release is actually intended.

### 2.5 Quality gates, in the order they run

A full-stack production pipeline runs through gates in roughly this order:

1. **Build** — Maven builds every module, exactly as a local `mvn clean install` would, inside an Adobe-managed container pinned to a specific AEM Cloud SDK version.
2. **Code Quality** — SonarQube analysis (Adobe's own rule set for AEM projects) plus **OakPAL** validation of the content packages. Detail on exactly which SonarQube rules matter is file 28's job; the thing to know here is that this gate can **block the pipeline** on critical findings, and that it enforces standards on **new or changed code**, not a retroactive rewrite of the whole codebase.
3. **Security** — scanning for known vulnerabilities in dependencies and common code-level security issues.
4. **Deploy to Stage** — the build artefact is deployed to the Stage environment.
5. **Functional / UI tests** — automated tests run against the real Stage environment (this is where `it.tests` and `ui.tests` from file 27 actually execute, as opposed to the unit tests, which already ran during the Build step).
6. **Approval gate** _(production pipelines only)_ — a human with the right Cloud Manager permission clicks Approve before the pipeline proceeds.
7. **Deploy to Production** — a rolling deployment, replacing pods gradually rather than an all-at-once cutover, so the site doesn't go down during a release.

**Why the order matters for an interview answer:** notice that code quality and security run _before_ anything is deployed anywhere. A build that fails those gates never reaches Stage, let alone Production — which is the mechanism behind file 14's claim that "production can't drift from source control." It's not just that deployment only happens through Git; it's that a deployment that doesn't meet the bar never becomes a deployment at all.

### 2.6 The approval gate

On a production pipeline, after Stage validation succeeds, the pipeline pauses and waits for a manual approval — someone with the appropriate role in Cloud Manager has to explicitly approve the step before the rollout to Production continues. This exists for the obvious reason: an automated pipeline that's technically green (tests pass, quality gates pass) is not the same thing as "we, as a team, have decided this is going live right now." The gate is where a release manager, a product owner, or a lead developer makes that call — often timed around a change window, a marketing announcement, or simply "not on a Friday afternoon."

### 2.7 Rollback, honestly

This is worth being precise about rather than confident-sounding, because it's an area where an overconfident answer falls apart under a follow-up. There is no "undo button" that reverts a live Production environment to its exact previous state the way `git reset` reverts a repository. What actually happens:

- The standard route is to **re-run the pipeline against the previous known-good commit** — either by re-triggering a prior successful pipeline execution, or by pushing a revert commit and letting a fresh pipeline run through the same gates.
- Because there's no emergency hotfix path (file 14), a rollback is itself a deployment, and it goes through the same Stage validation and approval gate as any other production change — which takes the time it takes.
- This is exactly why file 14's mitigations — feature flags and the fast config pipeline — matter in practice: a flag can be flipped off in seconds without a full pipeline run, whereas an actual code rollback cannot.

If asked "how do you roll back a bad release," the honest, defensible answer is: _"the real rollback is redeploying the last known-good commit through the pipeline, which is why we try to ship behind feature flags for anything risky — flipping a flag is faster than any deployment, including a rollback."_

### 2.8 Custom pipeline steps

Non-production and production pipelines support adding a small number of **custom steps** — most commonly a step that calls an external webhook, for example to notify a Slack or Teams channel when a deployment reaches a particular stage, or to trigger an external test suite that isn't part of the standard `it.tests` / `ui.tests` set. This is intentionally limited compared to a fully scriptable Jenkins pipeline — you're extending specific, defined extension points, not writing arbitrary pipeline logic — which is consistent with the whole "Adobe owns the pipeline shape" theme of this file.

### 2.9 Automation: the Cloud Manager API and the aio CLI

Everything visible in the Cloud Manager UI — triggering a pipeline execution, checking its status, approving a gate — is also available through Adobe's **Cloud Manager API**, and the `aio` CLI (already introduced in file 14 for RDE) has a Cloud Manager plugin that wraps it. In practice this is used to integrate pipeline triggers into other tooling — for example, kicking off a pipeline from an external ticketing system, or posting pipeline status into a dashboard.

**A caution worth stating plainly, the same way file 21 was careful about Oak internals:** I wouldn't try to recite exact `aio` command flags from memory in an interview. What's worth knowing solidly is the _capability_ — that pipeline execution, monitoring, and even approving the gate can be driven from the command line and not just the web UI — because that's the fact that answers "can this be automated," which is the actual question being tested.

***

## 3. Internal Working

### 3.1 What happens the moment you push

When you push to a branch that's wired to a pipeline, Cloud Manager's webhook on that branch fires, and a new **pipeline execution** starts. Nothing runs on your machine or on the target environment yet — the first thing that happens is Adobe spinning up a build container, pinned to a specific AEM Cloud SDK version matched to your program, and checking out your commit inside it.

**Why the pinned SDK version matters practically:** this is the same `aem-sdk-api` version discipline from file 25. If your `pom.xml` depends on a newer or older SDK version than the one the pipeline's build container uses, you can see a build succeed locally and fail — or worse, succeed but behave subtly differently — in the pipeline. Keeping the local SDK dependency version aligned with what Cloud Manager uses is a small piece of hygiene that prevents a confusing class of "works on my machine" bug that has nothing to do with your code.

### 3.2 The build step, mechanically

Inside that container, the build step runs essentially the same Maven build you'd run locally — `mvn clean install` across the reactor — producing the same module artefacts described in file 25 (the `core` JAR, the `ui.apps` / `ui.content` / `ui.config` packages, and the `all` aggregate). Unit tests (file 27's territory) run here, as part of the normal Maven build lifecycle, before the artefact is considered built at all. A unit test failure fails the Build step outright — the pipeline never even reaches the quality gates.

### 3.3 What OakPAL is actually checking

**OakPAL** (Oak Package Acceptance Layer) inspects the _built content packages_ — not your source folders — against structural rules before anything is deployed anywhere. Concretely, it can catch things like:

- a package attempting to write outside the paths its own `filter.xml` declares,
- mutable content ending up inside what's meant to be an immutable `ui.apps` package,
- disallowed or unexpected node types showing up in package content.

The important framing: this is a **structural, package-level check**, independent of whether your Java code even compiles cleanly or your SonarQube score is good. A package can pass every code quality rule and still fail OakPAL because of what it would actually do to the repository on install — which is exactly the class of problem file 25's "deployment that deleted a week of content" story represents. OakPAL is Adobe's answer to catching that _before_ a package ever reaches a real environment, rather than after.

### 3.4 The deploy step and why it's rolling, not all-at-once

A Cloud Service publish tier is multiple pods behind a load balancer (file 14). Deploying a new build doesn't take the whole tier down and bring it back up — pods are replaced gradually, so traffic keeps being served by the pods still running the previous version while new pods with the new version come up and pass health checks. This is why a Cloud Service deployment doesn't need a maintenance window the way a single-instance 6.5 publish restart historically did, and it's also why a deployment briefly runs **two versions of your code side by side** — worth remembering if you're ever debugging something that looks inconsistent for a few minutes right after a release.

### 3.5 Where dispatcher and config changes skip the Java build entirely

Because the web-tier and config pipelines are separate pipeline types (section 2.3), a dispatcher-only or configuration-only change never goes through the `core` module's compile-and-test cycle at all — the pipeline only touches the `dispatcher` module or the OSGi config sources respectively. This is the mechanical reason those pipelines are faster: there's simply less to build, not just a shorter queue.

***

## 8. Configuration Examples

### 8.1 Adding the Cloud Manager remote and pushing

```bash
# One-time setup: add Cloud Manager's Git repository as a remote
git remote add cloudmanager https://git.cloudmanager.adobe.com/<org>/<program>.git

# Pushing only triggers a pipeline if this branch is wired to one
# in the Cloud Manager UI — the push itself does nothing on its own.
git push cloudmanager release/2026-q1
```

### 8.2 Keeping the SDK version deliberate, not accidental

```xml
<!-- pom.xml — the version that connects your local build to what
     the Cloud Manager pipeline actually builds against.
     Bump this on purpose, and check it against the program's
     current release train — not just against "does it compile." -->
<dependency>
  <groupId>com.adobe.aem</groupId>
  <artifactId>aem-sdk-api</artifactId>
  <version>2026.1.XXXXX.XXXXXXX</version>
  <scope>provided</scope>
</dependency>
```

### 8.3 Recognising a pipeline-shaped problem versus a code-shaped one

```text
Symptom: "Build passed locally, failed at Cloud Manager's Build step"
  → Check the SDK version pin first (section 3.1 / story 3)
  → Then check for a dependency scope issue masked by a local autoInstall

Symptom: "Pipeline green through Stage, nothing happening after that"
  → Check whether it's a production pipeline waiting on the approval gate
  → This is not a failure — check who has approval permission (story 1)

Symptom: "A simple dispatcher change took 40 minutes"
  → It went through the full-stack pipeline instead of the web-tier pipeline
  → Isolate dispatcher-only changes into their own commit next time (story 2)
```

### 8.4 A defensible branching layout

```text
main                → feeds the PRODUCTION pipeline
                      (updated only when a release is intended)

develop             → feeds the NON-PRODUCTION pipeline
                      (every merge deploys to Stage automatically)

feature/compare-products
feature/faq-accordion
                    → merge into develop via pull request
                      (never pushed directly to a wired branch)
```

***

## 9. Common Mistakes

| Mistake                                                                | Why it happens                                            | The actual cost                                                                                   |
| ---------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Assuming the pipeline is defined in a repo file                        | Habit from Jenkins/GitHub Actions                         | Looking for a `.yml` that doesn't exist instead of checking Cloud Manager's configuration         |
| Pushing feature branches straight to a wired branch                    | Convenience                                               | Triggers a pipeline run — and a Stage deployment — per feature branch                             |
| Bundling a dispatcher-only fix into a full-stack change                | Habit, or not knowing web-tier pipelines exist            | A 40-minute pipeline for a change that needed 3                                                   |
| Treating a "waiting for approval" pipeline as broken                   | Not knowing the approval gate is a deliberate pause       | Wasted debugging time looking for a nonexistent failure                                           |
| Bumping the SDK version without checking the pipeline's pinned version | Local build succeeds, so it looks safe                    | Pipeline-only build failures with no obvious local cause                                          |
| Believing there's an emergency deployment bypass                       | Experience from non-Cloud-Service AEM, or other platforms | Designing incident response around a shortcut that doesn't exist                                  |
| Only one person holding approval permission                            | Nobody thought about it until someone was away            | A ready release stalls for days                                                                   |
| Assuming a green pipeline means "safe to ship anything"                | Conflating gate-passing with judgment                     | Shipping something technically correct but badly timed, which the approval gate exists to prevent |
| Not aligning local and pipeline SonarQube rules                        | Discovering findings only when the pipeline runs          | Repeated pipeline failures late in the process instead of early local feedback                    |
| Confusing OakPAL failures with SonarQube failures                      | Both show up as "code quality gate failed"                | Debugging code style when the actual problem is a package structure violation                     |

***

## 10. Best Practices

- **Match pipeline type to change type.** Dispatcher-only → web-tier. Config-only → config pipeline. Everything else → full-stack. This is a developer decision made by how commits are structured and pushed, not something automatic.
- **Keep the SDK version deliberate.** Treat `aem-sdk-api` version bumps like any other dependency change — call them out, and check them against what the program's Cloud Manager environments actually run.
- **Never push a feature branch straight to a wired branch.** Merge via pull request into the branch that feeds a pipeline, so a Stage deployment happens once per merged change, not once per push.
- **Hold approval permission with more than one person.** A release shouldn't stall because one person is unavailable.
- **Ship anything risky behind a feature flag.** It decouples "the code is deployed" from "the feature is live," which matters because a rollback is a full pipeline run and a flag flip isn't.
- **Run the same quality checks locally before opening a pull request**, where the tooling allows it — catching a SonarQube or OakPAL finding on your own machine is minutes; catching it in the pipeline is a full run's worth of time, repeated until it's fixed.
- **Treat Stage as production-equivalent, not as an afterthought environment.** Every production release goes through it — a bug that only appears on Stage-scale, real-instance behaviour is exactly the class of bug unit tests can't catch.
- **Design the branching model for the team's actual size**, not for a diagram you copied from documentation. Two developers rarely need the same branch topology as twenty.

***

## 11. Debugging Tips

| Symptom                                                                    | Where to look                                  | What it usually means                                                                                                          |
| -------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Build succeeds locally, fails in the pipeline                              | Cloud Manager's Build step logs                | SDK version mismatch, or a scope issue masked by local `autoInstall` state                                                     |
| Pipeline blocked at "Code Quality"                                         | The SonarQube report attached to the execution | A blocking rule was actually violated — check new/changed code specifically                                                    |
| Pipeline blocked at "Code Quality" but the code looks fine                 | The OakPAL section of the same report          | A package structure issue, not a code style issue — check `filter.xml` and package contents                                    |
| Pipeline sits at "waiting" indefinitely                                    | Whether it's a production pipeline past Stage  | It's the approval gate, not a failure — check who has permission to approve                                                    |
| A change reaches Stage but never Production                                | The approval step's status                     | Nobody has approved it yet                                                                                                     |
| Dispatcher change takes far longer than expected                           | Which pipeline it was pushed through           | It went through full-stack instead of web-tier                                                                                 |
| A component behaves inconsistently for a few minutes right after a release | Timing against the deployment window           | The rolling deployment briefly runs old and new pod versions side by side — expected, and should resolve once fully rolled out |

***

## 12. Performance Notes

Pipeline duration is a real cost, not just an inconvenience, because it determines how fast a team can respond to anything — a bug fix, a rollback, or a genuine incident. The practical levers a developer controls:

- **Use the narrowest pipeline that's true to the change.** A dispatcher or config-only change through the full-stack pipeline pays for a Java build and full quality gate suite it doesn't need.
- **Keep the Build step fast by keeping the module boundaries clean** (file 25) — a bloated `core` module with unnecessary dependencies slows every single pipeline run, not just the occasional one.
- **Fix quality gate findings locally before pushing**, rather than using the pipeline itself as your linter — every round trip through Code Quality costs a full pipeline execution's time.
- **Don't bundle unrelated changes into one commit or one pull request.** A component change and a dispatcher fix bundled together forces the whole thing through the slower, full-stack path even though only part of it needed to be there.

***

## 15. Comparison Tables

Four different distinctions get confused with each other under interview pressure, so it's worth having each one straight before you're asked to compare them live.

|                   | **Non-production pipeline** | **Production pipeline**              |
| ----------------- | --------------------------- | ------------------------------------ |
| Deploys to        | Development / Stage         | Development / Stage, then Production |
| Approval gate     | No                          | Yes                                  |
| Typical frequency | Every merge                 | Only on an intended release          |
| Purpose           | Continuous validation       | Actual release                       |

|          | **Full-stack**      | **Front-end**      | **Web-tier**              | **Config**                 |
| -------- | ------------------- | ------------------ | ------------------------- | -------------------------- |
| Builds   | Everything          | `ui.frontend` only | `dispatcher` only         | OSGi config only           |
| Use case | Application changes | CSS/JS iteration   | Cache/filter rule changes | Configuration-only changes |
| Speed    | Slowest             | Fast               | Fast                      | Fastest                    |

|         | **Code Quality gate**                         | **Security gate**                             |
| ------- | --------------------------------------------- | --------------------------------------------- |
| Tooling | SonarQube + OakPAL                            | Vulnerability/dependency scanning             |
| Checks  | Code standards on new code, package structure | Known vulnerabilities, common security issues |
| Runs on | Source and built packages                     | Dependencies and code                         |

|                     | **On 6.5 (self-managed)**                      | **On Cloud Service (Cloud Manager)**                 |
| ------------------- | ---------------------------------------------- | ---------------------------------------------------- |
| Pipeline definition | Wherever the team built it (Jenkinsfile, etc.) | Configured in Cloud Manager, not a repo file         |
| Emergency hotfix    | Possible, by hand                              | No bypass — same pipeline, every time                |
| Rollback            | Redeploy old package/bundle manually           | Redeploy last known-good commit through the pipeline |
| Quality gates       | Whatever the team chose to enforce             | Enforced platform-wide, can't be quietly skipped     |

***

## Next topic

**`28-Code-Quality-SonarQube-and-Best-Practices`** — how the Cloud Manager quality gate actually scores a pull request, the SonarQube and OakPAL rules that matter most in practice, and the coding standards and review habits that keep a codebase from accumulating the kind of debt this file's pipeline discipline can't catch on its own.

***

_Topic 26 of the AEM Interview Preparation repository. Teaching style, energy-sector project domain._
