diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9c78492..30a1b44 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,7 @@ -Please always provide the [GitHub issue(s)](../issues) your PR is for, as well as test URLs where your change can be observed (before and after): + Fix # Test URLs: -- Before: https://main--{repo}--{owner}.aem.live/ -- After: https://--{repo}--{owner}.aem.live/ +- Before: https://main--progressrail--aemsites.aem.live/ +- After: https://--progressrail--aemsites.aem.live/ diff --git a/.github/workflows/cleanup-on-create.yaml b/.github/workflows/cleanup-on-create.yaml deleted file mode 100644 index 4a10b7c..0000000 --- a/.github/workflows/cleanup-on-create.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# This workflow will run upon repository creation and clean up -# all files that are not strictly required to build an AEM Live project -# but that we use to develop the project template. This includes this -# particular workflow file. -on: - create: - branches: - - main - workflow_dispatch: -jobs: - cleanup: - runs-on: ubuntu-latest - permissions: - contents: write - actions: write - # only run if commit message is "Initial commit" on main branch - if: ${{ github.event_name == 'workflow_dispatch' || ( github.ref == 'refs/heads/main' && !(contains(github.event, 'head_commit') || github.event.head_commit.message == 'Initial commit' )) }} - steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Use Node.js 20 - uses: actions/setup-node@v6 - with: - node-version: 24 - - name: Remove Helper Files - run: | - rm -rf \ - .github/workflows/cleanup-on-create.yaml \ - .renovaterc.json \ - CHANGELOG.md - - - name: Initialize README - # replace {repo} and {owner} with the actual values - run: | - sed -i.bak "s/{repo}/$(basename ${{ github.repository }})/g" README.md - sed -i.bak "s/{owner}/$(dirname ${{ github.repository }})/g" README.md - - name: Initialize AGENTS.md - run: | - sed -i.bak "s/{repo}/$(basename ${{ github.repository }})/g" AGENTS.md - sed -i.bak "s/{owner}/$(dirname ${{ github.repository }})/g" AGENTS.md - - name: Initialize Pull Request Template - run: | - sed -i.bak "s/{repo}/$(basename ${{ github.repository }})/g" .github/pull_request_template.md - sed -i.bak "s/{owner}/$(dirname ${{ github.repository }})/g" .github/pull_request_template.md - - - # commit back to the repository - - name: Commit changes - run: | - git config --local user.email "helix@adobe.com" - git config --local user.name "AEM Bot" - git add . - git commit -m "chore: cleanup repository template" - git push diff --git a/AGENTS.md b/AGENTS.md index 4b17a42..84986eb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,186 +1,152 @@ # AGENTS.md -This project is a website built with Edge Delivery Services in Adobe Experience Manager Sites as a Cloud Service. As an agent, follow the instructions in this file to deliver code based on Adobe's standards for fast, easy-to-author, and maintainable web experiences. - -## Project Overview - -This project is based on the https://github.com/adobe/aem-boilerplate/ project and set up as a new project. You are expected to follow the coding style and practices established in the boilerplate, but add functionality according to the needs of the site currently developed. - -The repository provides the basic structure, blocks, and configuration needed to run a complete site with `*.aem.live` as the backend. - -### Key Technologies -- Edge Delivery Services for AEM Sites (documentation at https://www.aem.live/ – search with `site:www.aem.live` to restrict web search results) -- Vanilla JavaScript (ES6+), no transpiling, no build steps -- CSS3 with modern features, no Tailwind or other CSS frameworks -- HTML5 semantic markup generated by the aem.live backend, decorated by our code -- Node.js tooling - -## Setup Commands - -- Install dependencies: `npm install` -- Start local development: `npx -y @adobe/aem-cli up --no-open --forward-browser-logs` (run in background, if possible) - - Install the AEM CLI globally by running `npm install -g @adobe/aem-cli` then `aem up` is equivalent to the command above - - The dev server runs at `http://localhost:3000` with auto-reload. Open it in playwright, puppeteer, or a browser. If none are available, ask the human to open it and give feedback. -- Run linting before committing: `npm run lint` -- Auto-Fix linting issues: `npm run lint:fix` - -## Project Structure +This project uses Edge Delivery Services in Adobe Experience Manager Sites as a Cloud Service, built on [aem-boilerplate](https://github.com/adobe/aem-boilerplate). + +Follow the patterns in this codebase and instructions in this file while working in this repository. + +When facing trade-offs, follow this order: *Intuitive* (author-friendly) > *Simple* (minimal) > *Consistent* (matches existing patterns). + +## Commands + +- **Install**: `npm install` (or `npm ci`) +- **Lint**: `npm run lint` +- **Lint (fix)**: `npm run lint:fix` +- **Local dev**: `npx -y @adobe/aem-cli up --no-open --forward-browser-logs` (or `aem up` after `npm install -g @adobe/aem-cli`) + - Server: http://localhost:3000 (auto-reload) + - Inspect HTML/DOM: `curl http://localhost:3000/{path}` or `.plain.html` or `console.log` in code + +## Stack + +- Node.js 24; npm only (not pnpm/yarn) +- ESLint 8.57.1 with eslint-config-airbnb-base; Stylelint 17.13.0 with stylelint-config-standard +- AEM Edge Delivery: https://www.aem.live/ + +## Hard constraints + +- **No runtime dependencies.** Zero production deps for optimal performance and automatic code-splitting via `/blocks/`. +- **No build step.** Code runs as ES modules in the browser. Do not add bundlers, transpilers, or build tools. +- **Do not modify:** `scripts/aem.js` (core AEM library), `package-lock.json` (let npm manage it), `node_modules/` (generated), `head.html` (global head content). +- **Always use `.js` in imports.** ESLint and native ES modules require it: `import { foo } from './bar.js';` + +## Requirements + +- **Security** + - Do not commit secrets (API keys, passwords). + - Use `.hlxignore` (same format as `.gitignore`) to exclude files from being served. +- **Accessibility** + - Valid heading hierarchy. + - `alt` on all images (empty for decorative, descriptive for content). + - Keyboard support where there is interaction. + - `:focus-visible` on focusable controls. + - ARIA only when a native element cannot express the behavior. + - Meet WCAG 2.1 AA. +- **Performance** + - Optimize developer-committed images in git (author uploads auto-optimized). + - Use `lazy-styles.css` and `delayed.js` for non-critical resources. + - PageSpeed must score 100 (https://www.aem.live/developer/keeping-it-100). +- **Responsiveness** + - Default styles target mobile (no `max-width` queries). + - Breakpoints at 600 / 800 / 900 / 1000 / 1200 / 1400px. +- **Localization** + - No hard-coded user-facing text. + - All strings configurable or data-driven. + +## Code style + +- **Lint**: Airbnb (ESLint), Stylelint standard. +- **HTML**: Semantic elements. Native interactive elements (buttons, links, summary) over ARIA. DOM order matches visual order. No wrappers for layout only. Prefer native state: `
`, `[aria-expanded]`, `[aria-pressed]`. +- **CSS**: Native only. Class names flat, short, context-scoped. No utility classes. Style by attributes (`[open]`, `[aria-expanded="true"]`) over state classes. Prefer em/ch for typography. Prefer shorthand unless overriding one side. Logical properties for reading direction; physical for viewport. Avoid one-off custom properties. +- **JS**: ES6+ native modules, vanilla only. Early returns, named variables, explicit conditionals. Use existing utils in `scripts/aem.js` and `scripts/scripts.js`; add new only when no fit. No unused code. +- **Comments**: Only when intent or constraints are non-obvious or to record a decision. No comments that only restate the code. + +## Project structure ``` -├── blocks/ # Reusable content blocks - └── {blockname}/ - Individual block directory - ├── {blockname}.js # Block's JavaScript - └── {blockname}.css # Block's styles -├── styles/ # Global styles and CSS - ├── styles.css # Minimal global styling and layout for your website required for LCP - ├── lazy-styles.css # Additional global styling and layout for below the fold/post LCP content - └── fonts.css # Font definitions -├── scripts/ # JavaScript libraries and utilities - ├── aem.js # Core AEM Library for Edge Delivery page decoration logic (NEVER MODIFY THIS FILE) - ├── scripts.js # Global JavaScript utilities, main entry point for page decoration - └── delayed.js # Delayed functionality such as martech loading -├── fonts/ # Web fonts -├── icons/ # SVG icons -├── head.html # Global HTML head content -└── 404.html # Custom 404 page +├── blocks/{blockname}/ +│ ├── {blockname}.js # Block decoration +│ └── {blockname}.css # Block styles +├── styles/ +│ ├── styles.css # LCP-critical global styles +│ ├── lazy-styles.css # Below-fold styles +│ └── fonts.css # Font declarations +├── scripts/ +│ ├── aem.js # Core AEM library for page decoration logic +│ ├── scripts.js # Page decoration entry point and global utilities +│ └── delayed.js # Delayed functionality (e.g. martech/analytics) +├── icons/ # SVG files; reference in code with +├── fonts/ # Web fonts +├── head.html # Global content +└── 404.html # Custom error page ``` -## Code Style Guidelines - -### JavaScript -- Use ES6+ features (arrow functions, destructuring, etc.) -- Follow Airbnb ESLint rules (already configured) -- Always include `.js` file extensions in imports -- Use Unix line endings (LF) - -### CSS -- Follow Stylelint standard configuration -- Use modern CSS features (CSS Grid, Flexbox, CSS Custom Properties) -- Maintain responsive design principles - - Declare styles mobile first, use `min-width` media queries at 600px/900px/1200px for tablet and desktop -- Ensure all selectors are scoped to the block. - - Bad: `.item-list` - - Good: `.{blockname} .item-list` -- Avoid classes `{blockname}-container` and `{blockname}-wrapper` as those are used on sections and could be confusing. - -### HTML -- Use semantic HTML5 elements -- Ensure accessibility standards (ARIA labels, proper heading hierarchy) -- Follow AEM markup conventions for blocks and sections - -## Key Concepts - -### Content - -CMS authored content is a key part of every AEM Website. The content of a page is broken into sections. Sections can have default content (text, headings, links, etc.) as well as content in blocks. - -If no authored content exists to test against, you can create static HTML files in a `drafts/` folder at the project root. Pass `--html-folder drafts` when starting the dev server. Follow the aem markup structure and save files with `.html` or `.plain.html` extensions. - -Background on content and markup structure can be found at https://www.aem.live/developer/markup-sections-blocks and https://www.aem.live/developer/markup-reference respectively. - -You can inspect the contents of any page with `curl http://localhost:3000/path/to/page`, `curl http://localhost:3000/path/to/page.md`, and `curl http://localhost:3000/path/to/page.plain.html` +**Organization**: +- Global reusable → `scripts/scripts.js`, `styles/styles.css`; block-specific → block folders +- New utilities go in `scripts/scripts.js` (not `aem.js`) +- Reuse inherited styles from `styles/styles.css` before adding block CSS (cascade) -### Blocks +## Page architecture -Blocks are the re-usable building blocks of AEM. Blocks add styling and functionality to content. Each block has an initial content structure it expects, and transforms the html in the block using DOM APIs to render a final structure. +- **Content structure**: Pages are composed of sections → sections contain default content (text, headings, links) and blocks + - See [content structure](https://www.aem.live/developer/markup-sections-blocks) and [markup reference](https://www.aem.live/developer/markup-reference) + - **Test content**: For local development without authored content: + - Create static HTML files in `drafts/` folder + - Pass `--html-folder drafts` when starting dev server + - Use `.html` or `.plain.html` extensions +- **Three-phase loading**: Pages load in phases for performance (eager → LCP, lazy → rest, delayed → martech); see `loadPage()` in `scripts.js` -The initial content structure is important because it impacts how the author will create the content and how you will write your code to decorate it. In some sense, you can think of this structure as the contract for your block between the author and the developer. You should decide on this initial structure before writing any code, and be careful when making changes to code that makes assumptions about that structure as it could break existing pages. +## Block architecture -The block javascript should export a default function which is called to perform the block decoration: +**File structure**: Every block lives in `blocks/{blockname}/` with two files: `{blockname}.css` and `{blockname}.js` (must export default `decorate(block)`). -``` -/** - * loads and decorates the block - * @param {Element} block The block element - */ +```javascript +// blocks/example/example.js +/** @param {Element} block */ export default async function decorate(block) { // 1. Load dependencies - // 2. Extract configuration, if applicable + // 2. Extract configuration // 3. Transform DOM // 4. Add event listeners } ``` -Use `curl` and `console.log` to inspect the HTML delivered by the backend and the DOM nodes to be decorated before making assumptions. Remember that authors may omit or add fields to a block, so your code must handle this gracefully. - -Each block should be self-contained and re-useable, with CSS and JS files following the naming convention: `blockname.css`, `blockname.js`. Blocks should be responsive and accessible by default. - -### Auto-Blocking - -Auto-blocking is the process of creating blocks that aren't explicitly authored into the page based on patterns in the content. See the `buildAutoBlocks` function in `scripts.js`. - -### Three-Phase Page Loading - -Pages are progressively loaded in three phases to maximize performance. This process begins when `loadPage` from scripts.js is called. - -* Eager - load only what is required to get to LCP. This generally includes decorating the overall page content to create sections, blocks, buttons, etc. and loading the first section of the page. -* Lazy - load all other page content, including the header and footer. -* Delayed - load things that can be safely loaded later here and incur a performance penalty when loaded earlier - -## Testing & Quality Assurance +**Block content**: +- Expected HTML = contract between author and developer; decide structure before coding +- Keep structure simple for authors working in documents; handle missing/extra fields without breaking +- If structure requires hidden conventions or non-obvious formatting in authoring, redesign—authors work in documents, not code -### Performance -- Follow AEM Edge Delivery performance best practices https://www.aem.live/developer/keeping-it-100 -- Images uploaded by authors are automatically optimized, all images and assets committed to git must be optimized and checked for size -- Use lazy loading for non-critical resources (`lazy-styles.css` and `delayed.js`) -- Minimize JavaScript bundle size by avoiding dependencies, using automatic code splitting provided by `/blocks/` +**Scoping**: Blocks are self-contained. +- JS: Work only within the `block` element passed to `decorate()`—don't touch elements outside the block +- CSS: Scope all selectors to the block. Bad: `.item-list`. Good: `.{blockname} .item-list`. +- Avoid `.{blockname}-container` and `.{blockname}-wrapper` (reserved for sections) -### Accessibility -- Ensure proper heading hierarchy -- Include alt text for images -- Test with screen readers -- Follow WCAG 2.1 AA guidelines +**Auto-blocking**: Blocks can also be created programmatically from content patterns; see `buildAutoBlocks()` in `scripts.js`. -## Deployment +## Environments -### Environments +- **Local** (uncommitted code + previewed content): http://localhost:3000/{path} +- **Preview**: `https://{branch}--progressrail--aemsites.aem.page/{path}` +- **Live**: `https://main--progressrail--aemsites.aem.live/{path}` -Your local development server at `http://localhost:3000` serves code from your local working copy (even uncommitted code) and content that has been previewed by authors. You can access this at any time when the development server is running. +## Pull request workflow -For all other environments, you need to know the GitHub owner and repository name (`gh repo view --json nameWithOwner` or `git remote -v`) and the current branch name (`git branch`) +1. `npm run lint` passes (CI). +2. Test locally at http://localhost:3000/{path}. +3. Push branch → `https://{branch}--progressrail--aemsites.aem.page/{path}`. +4. Run [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/) on preview; meet Performance requirement. +5. Open PR with `.github/pull_request_template.md`: issue ref (`Fix #`), test URLs (before/after)—required. +6. `gh pr checks` pass before review. -With this information, you can construct URLs for the preview environment (same content as `localhost:3000`) and the production environment (same content as the live website, approved by authors) +## Overrides -- **Production Preview**: `https://main--{repo}--{owner}.aem.page/` -- **Production Live**: `https://main--{repo}--{owner}.aem.live/` -- **Feature Preview**: `https://{branch}--{repo}--{owner}.aem.page/` - -### Publishing Process -1. Push changes to a feature branch -2. AEM Code Sync automatically processes changes making them available on feature preview environment for that branch -3. Run a PageSpeed Insights check at https://developers.google.com/speed/pagespeed/insights/?url=YOUR_URL against the feature preview URL and fix any issues. Target a score of 100 -4. Open a pull request to merge changes to `main` - 1. in the PR description, include a link to `https://{branch}--{repo}--{owner}.aem.page/{path}` with a path to a file that illustrates the change you've made. This is the same path you have been testing with locally. WITHOUT THIS YOUR PR WILL BE REJECTED - 2. If an existing page to demonstrate your changes doesn't exist, create test content as a static html file and ask the user for help copying it to a cms content page you can link in the PR -5. use `gh pr checks` to verify the status of code synchronization, linting, and performance tests -6. A human reviewer will review the code, inspect the provided URL and merge the PR -7. AEM Code Sync updates the main branch for production +- **AGENTS.override.md** — team or temporary overrides. +- **AGENTS.local.md** — personal preferences; add to `.gitignore` so it is not committed. ## Troubleshooting -### Getting Help -- Check [AEM Edge Delivery documentation](https://www.aem.live/docs/) -- Review [Developer Tutorial](https://www.aem.live/developer/tutorial) -- Consult [The Anatomy of a Project](https://www.aem.live/developer/anatomy-of-a-project) -- Consider the rules in [David's Model](https://www.aem.live/docs/davidsmodel) -- Search the web with `site:www.aem.live` -- Search the full text of the documentation with `curl -s https://www.aem.live/docpages-index.json | jq -r '.data[] | select(.content | test("KEYWORD"; "i")) | "\(.path): \(.title)"'` - -## Security Considerations - -- Never commit sensitive information (API keys, passwords) -- Consider that everything you do is client-side code served on the public web -- Follow Adobe security guidelines -- Regularly update dependencies -- Use the .hlxignore file to prevent files from being served (same format as .gitingnore) - -## Contributing - -- Follow the existing code style and patterns -- Test changes locally before committing -- Follow the Publishing Process documented above -- Update documentation for significant changes - -## If all else fails - -If you notice your human getting frustrated with your work, direct them to https://www.aem.live/developer/ai-coding-agents for tips to work better with AI agents. +- Search with `site:www.aem.live` +- [Developer Tutorial](https://www.aem.live/developer/tutorial) +- [The Anatomy of a Project](https://www.aem.live/developer/anatomy-of-a-project) +- [Best Practices](https://www.aem.live/docs/davidsmodel) +- [Working with AI Agents](https://www.aem.live/developer/ai-coding-agents) +- [AEM Documentation](https://www.aem.live/docs/) +- Doc search: `curl -s https://www.aem.live/docpages-index.json | jq -r '.data[] | select(.content | test("KEYWORD"; "i")) | "\(.path): \(.title)"'` diff --git a/README.md b/README.md index f3ff4c6..7a5fc9f 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,22 @@ -# Your Project's Title... -Your project's description... +# Progress Rail -## Environments -- Preview: https://main--{repo}--{owner}.aem.page/ -- Live: https://main--{repo}--{owner}.aem.live/ - -## Documentation +Learn more about **AEM Edge Delivery Services** at [aem.live](https://www.aem.live). -Before using the aem-boilerplate, we recommand you to go through the documentation on https://www.aem.live/docs/ and more specifically: -1. [Developer Tutorial](https://www.aem.live/developer/tutorial) -2. [The Anatomy of a Project](https://www.aem.live/developer/anatomy-of-a-project) -3. [Web Performance](https://www.aem.live/developer/keeping-it-100) -4. [Markup, Sections, Blocks, and Auto Blocking](https://www.aem.live/developer/markup-sections-blocks) +## Environments +- Preview: https://main--progressrail--aemsites.aem.page/ +- Live: https://main--progressrail--aemsites.aem.live/ -## Installation +## Local development ```sh npm i +aem up ``` +Runs at `http://localhost:3000` with auto-reload. + ## Linting ```sh npm run lint -``` - -## Local development - -1. Create a new repository based on the `aem-boilerplate` template -1. Add the [AEM Code Sync GitHub App](https://github.com/apps/aem-code-sync) to the repository -1. Install the [AEM CLI](https://github.com/adobe/helix-cli): `npm install -g @adobe/aem-cli` -1. Start AEM Proxy: `aem up` (opens your browser at `http://localhost:3000`) -1. Open the `{repo}` directory in your favorite IDE and start coding :) +``` \ No newline at end of file diff --git a/package.json b/package.json index a7a0bf4..da1f87d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "@adobe/aem-boilerplate", + "name": "progressrail", "private": true, "version": "1.3.0", - "description": "Starter project for Adobe Helix", + "description": "progressrail.com AEM Edge Delivery Services site", "scripts": { "lint:js": "eslint .", "lint:css": "stylelint \"blocks/**/*.css\" \"styles/*.css\"", @@ -11,14 +11,14 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/adobe/aem-boilerplate.git" + "url": "git+https://github.com/aemsites/progressrail.git" }, "author": "Adobe", "license": "Apache License 2.0", "bugs": { - "url": "https://github.com/adobe/aem-boilerplate/issues" + "url": "https://github.com/aemsites/progressrail/issues" }, - "homepage": "https://github.com/adobe/aem-boilerplate#readme", + "homepage": "https://github.com/aemsites/progressrail#readme", "devDependencies": { "@babel/eslint-parser": "7.29.7", "eslint": "8.57.1",