# AGENTS.md

This file provides guidance for AI coding agents (Claude Code, Codex, Gemini CLI, etc.) working in this repository.

## Navigation

- Locating files or understanding structure → [Repository Structure](#repository-structure)
- Writing or reviewing PHP → [Key Conventions → PHP](#php) + [Known Constraints → PHP Constraints](#php-constraints)
- Working on REST API controllers → [Key Conventions → REST API](#rest-api)
- Editing styles or scripts → [Key Conventions → CSS/JS](#cssjs) + [Known Constraints → JavaScript](#javascript)
- Checks required before committing → [Development Workflow](#development-workflow)
- Branch naming or commit format → [Creating Branches](#creating-branches) + [Commits](#commits)
- Verifying whether a file is safe to modify → [What Not to Touch](#what-not-to-touch)

## Project Overview

**CoCart JWT Authentication** is an open-source WordPress plugin that adds JWT (JSON Web Token) authentication support to CoCart. It enables stateless authentication for headless and decoupled storefronts using CoCart's REST API.

- **Plugin file:** `cocart-jwt-authentication.php`
- **Main class:** `CoCart\JWTAuthentication\Plugin` (namespaced)
- **Autoloader:** PSR-4 via Composer (`CoCart\JWTAuthentication\` → `includes/classes/`)
- **Constant:** `COCART_JWT_AUTHENTICATION_FILE`
- **Text domain:** `cocart-jwt-authentication`
- **PHP minimum:** 7.4
- **WordPress minimum:** 6.0
- **WooCommerce minimum:** 7.0
- **CoCart minimum:** 4.3
- **Default branch:** `master`
- **License:** GPLv3 — public repository, open-source

## Repository Structure

```text
cocart-jwt-authentication.php       # Main plugin file — defines constants, boots plugin
includes/
├── class-cocart-jwt-authentication.php   # Boots CoCart\JWTAuthentication\Plugin
├── abstracts/                            # Abstract base classes
└── classes/                             # All feature classes (namespaced)
    ├── class-cocart-jwt-plugin.php       # Main plugin class (singleton)
    └── rest-api/                         # REST API controllers and auth handlers
assets/
├── scss/                               # SCSS source — only this is tracked in git
├── css/                                # Compiled CSS — generated by CI, not tracked
├── js/                                 # JS source; *.min.js compiled by CI, not tracked
└── images/                             # Static images
languages/                              # Only README.md tracked; .pot/.po/.mo generated by CI
tests/
└── unit/                               # PHPUnit unit test classes
bin/
└── install-wp-tests.sh                 # WordPress test environment installer
```

## Key Conventions

### PHP

- Follow [WordPress Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/)
- All classes use the `CoCart\JWTAuthentication\` namespace — do not add global class names
- Use `cocart-jwt-authentication` as the text domain in all translatable strings
- Use numbered arguments in `printf`/`sprintf` when replacing more than one value: `%1$s`, `%2$s`
- Use sentence case for translatable strings: `Some thing` not `Some Thing`
- Avoid HTML in strings — insert via `sprintf` instead
- Do not call deprecated functions from plugin source; use replacement functions directly
- Use `COCART_JWT_AUTHENTICATION_FILE` constant — do not hardcode the plugin path

### REST API

- Authentication handlers live in `includes/classes/rest-api/`
- CoCart uses WooCommerce Data Stores API for session management — not WooCommerce default sessions
- This plugin extends CoCart's authentication layer — do not bypass CoCart's auth hooks
- JWT tokens are issued and validated here — do not duplicate logic in controllers

### CSS/JS

- Edit SCSS source in `assets/scss/` — never edit compiled CSS in `assets/css/`
- Compiled CSS and minified JS are generated by CI (`npx grunt css js`) — do not commit them
- RTL CSS is auto-generated from compiled CSS — do not create RTL files manually

## Build Commands

```bash
# Install dependencies
npm ci
composer install

# Compile CSS and JS
npx grunt css js

# Watch for changes during development
npx grunt watch

# Code standards
composer phpcs          # Check PHP coding standards
composer phpcbf         # Auto-fix coding standards issues
composer phpstan        # Static analysis

# Download translations
npx grunt get-translations

# Fix text domain references
npm run fix:textdomain
```

## Development Workflow

1. Make code changes
2. Run `composer phpcs` on changed PHP files — fix all violations before continuing
3. Run `composer phpstan` on changed PHP files — fix errors in code, never add to baseline
4. Run `vendor/bin/phpunit` — all tests must pass before committing
5. Compile assets if SCSS/JS changed: `npx grunt css js`
6. Commit only after checks are clean
7. Open a pull request against `master`

### Pre-commit Checks

**Before committing PHP changes**, run these to avoid CI failures:

```bash
# Check coding standards on changed files
composer phpcs

# Static analysis
composer phpstan

# Run the test suite
vendor/bin/phpunit
```

**PHPStan baseline policy:** The baseline file (`phpstan-baseline.neon`) must never grow. If PHPStan reports a new error, fix it in the code. If your fix resolves a previously baselined error, remove the corresponding entry from the baseline. The baseline should only shrink over time.

## Known Constraints

### Project Structure

- Never add standalone global functions — all code must use the `CoCart\JWTAuthentication\` namespace
- Never modify `CHANGELOG.md` — updated by the CoCart team only
- Never commit compiled CSS (`assets/css/`) or minified JS (`assets/js/**/*.min.js`) — generated by CI
- Never commit `.pot` files — generated by CI
- Never edit RTL CSS files manually — auto-generated from compiled CSS
- All new classes go in `includes/classes/` under the appropriate subdirectory

### JavaScript

- Never write inline JavaScript — all JS must live in enqueued script files so it can be compiled, linted, and minified
- Never use dynamic code execution functions (`call`, `apply`, `Function` constructor, or similar patterns that execute strings as code)
- Never enqueue scripts or styles outside the designated admin class

### PHP Constraints

- Never use `var_dump()`, `print_r()`, or `error_log()` in committed code — remove all debug output before committing
- Never access `$_GET`, `$_POST`, or `$_SERVER` directly in REST API controllers — use `WP_REST_Request` parameter methods
- Never write raw database queries — use WooCommerce Data Stores or existing CoCart abstractions
- Never use `wp_die()` inside REST API controllers — return a `WP_Error` instance instead
- Never output unescaped content — use `esc_html()`, `esc_attr()`, `wp_json_encode()`, or the appropriate escaping function
- Never hardcode credentials, tokens, or API keys — use WordPress options or constants defined outside the codebase

## What Not to Touch

- **`CHANGELOG.md`** — updated by the CoCart team, not contributors
- **`languages/*.pot`** — generated by CI (`wp i18n make-pot`), not tracked in git
- **`assets/css/`** — compiled by CI, not tracked in git
- **`assets/js/**/*.min.js`** — compiled by CI, not tracked in git
- **`vendor/`** — managed by Composer, not tracked in git
- **`node_modules/`** — managed by npm, not tracked in git

## Creating Branches

Branch names follow this structure (`{short-slug}` = brief descriptor of the change):

- `release/{version}` — release branches
- `refactor/{short-slug}` — refactors
- `test/{short-slug}` — test-only changes
- `fix/{issue-number}-{short-slug}` — bug fixes (always include the issue number)
- `add/{short-slug}` — new features

## Commits

- Each commit should address one atomic unit of work
- Subject line: imperative mood, no trailing period, max 50 characters (e.g. `Fix token expiry on guest checkout`)
- Blank line between subject and body
- Body lines: max 72 characters
- Explain *what* and *why*, not just *how* — only explain *how* if it isn't obvious
- Reference the related issue number in the commit body (e.g. `Fixes #123`)
- Do not amend published commits

## Agent Rules

- Run pre-commit checks before every commit — do not skip them for any reason
- Do not modify generated files (`assets/css/`, `*.min.js`, `*.pot`) — CI overwrites them
- Do not add entries to the PHPStan baseline — fix the error in code instead
- Do not create new files when an existing class can be extended or modified
- Do not reach past a CoCart abstraction to call WordPress or WooCommerce directly — use the abstraction
- Do not amend commits that have already been pushed
- Check [What Not to Touch](#what-not-to-touch) before modifying any file you are uncertain about
- Check [Known Constraints](#known-constraints) before writing any new PHP, JS, or SQL
