diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8fb3067 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,76 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +Version format: `XX.YY.ZZ` (zero-padded semver). + +## [Unreleased] + +## [05.00.00] - 2026-05-11 + +### Added +- Centralized MokoWaaS Grafana dashboard for all Joomla sites (2-column layout) +- MokoStandards MCP server with 24 governance tools +- Wiki health check and GitHub wiki mirror sync +- Daily wiki sync workflow — mirrors all Gitea wikis to GitHub +- CHANGELOG `[Unreleased]` section check in repo health (5 pts) +- Client platform type with detection and structure definition +- PHPStan, Gitleaks, and Renovate — templates, workflows, and docs +- Cascade and branch protection workflow documentation +- Branch protection setup workflow +- Client-site definition +- Pre-release workflow for manual dev/alpha/beta/rc builds +- PR-check, security-audit, notify, cleanup workflow definitions +- Expanded workflow suite (10 workflows from MokoOnyx) +- `.gitea/workflows` definitions to Joomla structure defs +- Joomla workflow templates from MokoOnyx +- Cleanup script to remove `.claude/` and `.mcp.json` from repos +- Auto-discover all repos with wikis across all orgs +- CLAUDE.md to repo health check, flag unwanted files +- `.moko-platform` manifest (replaces `.mokostandards`) +- PR branch policy check workflow + +### Changed +- Major version bump: `04.05.00` → `05.00.00` across all definitions, templates, and wiki +- Grafana endpoint dashboards: 2 columns per row (reduced congestion) +- Sync engine clones template repos at runtime for workflows +- Simplified platform types across definitions and sync engine +- Removed `templates/github` — all CI/templates now in `.gitea/` +- Removed `templates/workflows` — canonical source is now template repos +- Updated mokostandards xmlns to point to MokoStandards-API repo +- Comprehensive repo health check updates + +### Fixed +- Remove gitea-actions[bot] from push whitelist (not a real user) +- Delete-then-create branch protection rules to avoid 422 +- Patch version bump in pre-release workflow +- Always emit `` tag in UpdateXmlGenerator +- Rewrite `updates.xml.template` with 5 stability channels +- Migrate `.mokostandards` from `.github/` to `.gitea/` on Gitea + +## [04.05.00] - 2026-03-15 + +### Added +- Dual-platform support (Gitea + GitHub) and Joomla template tooling +- Templates, CLI dirs, docs, and Gitea-first platform config +- Sync to all branches, listBranches, ext-zip +- All templates from MokoStandards + +### Changed +- Migrated to Gitea-only workflows and API +- Converted all gh CLI calls to Gitea API curl across workflow templates +- Gitea-primary tokens: GA_TOKEN for Gitea API, GH_TOKEN for GitHub mirror +- Updated all references to MokoConsulting org and Gitea URLs + +### Fixed +- Guzzle base_uri resolution for Gitea API paths +- Replace all hardcoded GitHub API URLs with platform adapter pattern +- Split repoRoot into apiRoot + standardsRoot +- Auto-release template: use Gitea API for main sync, auth push URL +- Bulk_sync: resolve label names to IDs, fix username +- Remove sha256: prefix from update XML templates + +## [04.00.00] - 2026-01-01 + +- Initial release: MokoStandards Enterprise API extracted from MokoStandards diff --git a/composer.json b/composer.json index 56cec14..a22054d 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "mokoconsulting-tech/enterprise", "description": "MokoStandards Enterprise API \u2014 PHP implementation", "type": "library", - "version": "04.05.00", + "version": "05.00.00", "license": "GPL-3.0-or-later", "authors": [ { diff --git a/definitions/default/crm-module.tf b/definitions/default/crm-module.tf index e34ddd9..dced5bb 100644 --- a/definitions/default/crm-module.tf +++ b/definitions/default/crm-module.tf @@ -4,7 +4,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -17,7 +17,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/default/crm-platform.tf b/definitions/default/crm-platform.tf index 3e8a962..b6ac625 100644 --- a/definitions/default/crm-platform.tf +++ b/definitions/default/crm-platform.tf @@ -8,7 +8,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -21,7 +21,7 @@ locals { platform = "dolibarr" last_updated = "2026-03-31T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/default/default-repository.tf b/definitions/default/default-repository.tf index 6e2a533..73d6eac 100644 --- a/definitions/default/default-repository.tf +++ b/definitions/default/default-repository.tf @@ -4,7 +4,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -17,7 +17,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/default/generic-repository.tf b/definitions/default/generic-repository.tf index 0d36b5f..03b83c3 100644 --- a/definitions/default/generic-repository.tf +++ b/definitions/default/generic-repository.tf @@ -4,7 +4,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -17,7 +17,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/default/github-private-repository.tf b/definitions/default/github-private-repository.tf index 9f1a624..2467d04 100644 --- a/definitions/default/github-private-repository.tf +++ b/definitions/default/github-private-repository.tf @@ -5,7 +5,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 * * NOTES @@ -28,7 +28,7 @@ locals { platform = "github-private" last_updated = "2026-03-12T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" visibility = "private" sync_priority = -1 diff --git a/definitions/default/standards-repository.tf b/definitions/default/standards-repository.tf index cd4732a..0bbdeeb 100644 --- a/definitions/default/standards-repository.tf +++ b/definitions/default/standards-repository.tf @@ -4,7 +4,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -17,7 +17,7 @@ locals { platform = "standards" last_updated = "2026-03-03T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/default/waas-component.tf b/definitions/default/waas-component.tf index 7756ec2..667269d 100644 --- a/definitions/default/waas-component.tf +++ b/definitions/default/waas-component.tf @@ -4,7 +4,7 @@ * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -17,7 +17,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/.github-private.def.tf b/definitions/sync/.github-private.def.tf index 1bc5081..43e3445 100644 --- a/definitions/sync/.github-private.def.tf +++ b/definitions/sync/.github-private.def.tf @@ -83,7 +83,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -96,7 +96,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/.github.def.tf b/definitions/sync/.github.def.tf index f533119..ecf9918 100644 --- a/definitions/sync/.github.def.tf +++ b/definitions/sync/.github.def.tf @@ -98,7 +98,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -111,7 +111,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/Copy-PortablePath.def.tf b/definitions/sync/Copy-PortablePath.def.tf index 4da453d..33b8bd8 100644 --- a/definitions/sync/Copy-PortablePath.def.tf +++ b/definitions/sync/Copy-PortablePath.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/DoliMods.def.tf b/definitions/sync/DoliMods.def.tf index 76e29b3..f395231 100644 --- a/definitions/sync/DoliMods.def.tf +++ b/definitions/sync/DoliMods.def.tf @@ -89,7 +89,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -102,7 +102,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoCRM.def.tf b/definitions/sync/MokoCRM.def.tf index 60ce9bf..4c281d9 100644 --- a/definitions/sync/MokoCRM.def.tf +++ b/definitions/sync/MokoCRM.def.tf @@ -91,7 +91,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -104,7 +104,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoCassiopeia.def.tf b/definitions/sync/MokoCassiopeia.def.tf index 59ff676..d682f19 100644 --- a/definitions/sync/MokoCassiopeia.def.tf +++ b/definitions/sync/MokoCassiopeia.def.tf @@ -86,7 +86,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -99,7 +99,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliAdInsights.def.tf b/definitions/sync/MokoDoliAdInsights.def.tf index 0f22154..db9caf8 100644 --- a/definitions/sync/MokoDoliAdInsights.def.tf +++ b/definitions/sync/MokoDoliAdInsights.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliArt.def.tf b/definitions/sync/MokoDoliArt.def.tf index 291ded3..f7865bd 100644 --- a/definitions/sync/MokoDoliArt.def.tf +++ b/definitions/sync/MokoDoliArt.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliAuth.def.tf b/definitions/sync/MokoDoliAuth.def.tf index e3f0ddc..8051886 100644 --- a/definitions/sync/MokoDoliAuth.def.tf +++ b/definitions/sync/MokoDoliAuth.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliCare.def.tf b/definitions/sync/MokoDoliCare.def.tf index b4ed9ee..2517fe8 100644 --- a/definitions/sync/MokoDoliCare.def.tf +++ b/definitions/sync/MokoDoliCare.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliChimp.def.tf b/definitions/sync/MokoDoliChimp.def.tf index 7683002..4f06fdb 100644 --- a/definitions/sync/MokoDoliChimp.def.tf +++ b/definitions/sync/MokoDoliChimp.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliClaude.def.tf b/definitions/sync/MokoDoliClaude.def.tf index 68da312..24c5cb3 100644 --- a/definitions/sync/MokoDoliClaude.def.tf +++ b/definitions/sync/MokoDoliClaude.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliCredits.def.tf b/definitions/sync/MokoDoliCredits.def.tf index 3a32d95..4787ffc 100644 --- a/definitions/sync/MokoDoliCredits.def.tf +++ b/definitions/sync/MokoDoliCredits.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliDymo.def.tf b/definitions/sync/MokoDoliDymo.def.tf index 194d78b..e19bdea 100644 --- a/definitions/sync/MokoDoliDymo.def.tf +++ b/definitions/sync/MokoDoliDymo.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliForm.def.tf b/definitions/sync/MokoDoliForm.def.tf index 8fe13c4..20f25d5 100644 --- a/definitions/sync/MokoDoliForm.def.tf +++ b/definitions/sync/MokoDoliForm.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliG.def.tf b/definitions/sync/MokoDoliG.def.tf index e9e6f2a..5eddea6 100644 --- a/definitions/sync/MokoDoliG.def.tf +++ b/definitions/sync/MokoDoliG.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliGithub.def.tf b/definitions/sync/MokoDoliGithub.def.tf index fecd5ef..e7cc94f 100644 --- a/definitions/sync/MokoDoliGithub.def.tf +++ b/definitions/sync/MokoDoliGithub.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliHRM.def.tf b/definitions/sync/MokoDoliHRM.def.tf index 6d21e39..7888346 100644 --- a/definitions/sync/MokoDoliHRM.def.tf +++ b/definitions/sync/MokoDoliHRM.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliMods.def.tf b/definitions/sync/MokoDoliMods.def.tf index 7912f42..c5cb7ce 100644 --- a/definitions/sync/MokoDoliMods.def.tf +++ b/definitions/sync/MokoDoliMods.def.tf @@ -103,7 +103,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -116,7 +116,7 @@ locals { platform = "dolibarr" last_updated = "2026-03-31T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliMulti.def.tf b/definitions/sync/MokoDoliMulti.def.tf index bc406e5..1b8b49f 100644 --- a/definitions/sync/MokoDoliMulti.def.tf +++ b/definitions/sync/MokoDoliMulti.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliOffline.def.tf b/definitions/sync/MokoDoliOffline.def.tf index ae984e1..08af317 100644 --- a/definitions/sync/MokoDoliOffline.def.tf +++ b/definitions/sync/MokoDoliOffline.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliPhone.com.def.tf b/definitions/sync/MokoDoliPhone.com.def.tf index 64881a4..afca29e 100644 --- a/definitions/sync/MokoDoliPhone.com.def.tf +++ b/definitions/sync/MokoDoliPhone.com.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliProjTemplate.def.tf b/definitions/sync/MokoDoliProjTemplate.def.tf index e32b47b..80362e4 100644 --- a/definitions/sync/MokoDoliProjTemplate.def.tf +++ b/definitions/sync/MokoDoliProjTemplate.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliRelease.def.tf b/definitions/sync/MokoDoliRelease.def.tf index f1abcdb..c306308 100644 --- a/definitions/sync/MokoDoliRelease.def.tf +++ b/definitions/sync/MokoDoliRelease.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliSign.def.tf b/definitions/sync/MokoDoliSign.def.tf index 8094fbe..f4f130d 100644 --- a/definitions/sync/MokoDoliSign.def.tf +++ b/definitions/sync/MokoDoliSign.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliTools.def.tf b/definitions/sync/MokoDoliTools.def.tf index cdb8ac0..b20c8d4 100644 --- a/definitions/sync/MokoDoliTools.def.tf +++ b/definitions/sync/MokoDoliTools.def.tf @@ -81,7 +81,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -94,7 +94,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDoliTraining.def.tf b/definitions/sync/MokoDoliTraining.def.tf index 3ef587c..2b6c156 100644 --- a/definitions/sync/MokoDoliTraining.def.tf +++ b/definitions/sync/MokoDoliTraining.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoDolibarr.def.tf b/definitions/sync/MokoDolibarr.def.tf index 0b9770c..0ab06d8 100644 --- a/definitions/sync/MokoDolibarr.def.tf +++ b/definitions/sync/MokoDolibarr.def.tf @@ -103,7 +103,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -116,7 +116,7 @@ locals { platform = "dolibarr" last_updated = "2026-03-31T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoISOUpdatePortable.def.tf b/definitions/sync/MokoISOUpdatePortable.def.tf index 826e915..e63839b 100644 --- a/definitions/sync/MokoISOUpdatePortable.def.tf +++ b/definitions/sync/MokoISOUpdatePortable.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoJoomHero.def.tf b/definitions/sync/MokoJoomHero.def.tf index ca5e45a..e49679c 100644 --- a/definitions/sync/MokoJoomHero.def.tf +++ b/definitions/sync/MokoJoomHero.def.tf @@ -85,7 +85,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -98,7 +98,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoJoomTOS.def.tf b/definitions/sync/MokoJoomTOS.def.tf index 23a2ea1..d487bfd 100644 --- a/definitions/sync/MokoJoomTOS.def.tf +++ b/definitions/sync/MokoJoomTOS.def.tf @@ -85,7 +85,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -98,7 +98,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoPerfectPublisher-Discord.def.tf b/definitions/sync/MokoPerfectPublisher-Discord.def.tf index 72e331b..2eea2f3 100644 --- a/definitions/sync/MokoPerfectPublisher-Discord.def.tf +++ b/definitions/sync/MokoPerfectPublisher-Discord.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoStandards-Template-Client.def.tf b/definitions/sync/MokoStandards-Template-Client.def.tf index 7844159..22d6a9c 100644 --- a/definitions/sync/MokoStandards-Template-Client.def.tf +++ b/definitions/sync/MokoStandards-Template-Client.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoStandards-Template-Dolibarr.def.tf b/definitions/sync/MokoStandards-Template-Dolibarr.def.tf index be9c23a..f72d075 100644 --- a/definitions/sync/MokoStandards-Template-Dolibarr.def.tf +++ b/definitions/sync/MokoStandards-Template-Dolibarr.def.tf @@ -90,7 +90,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -103,7 +103,7 @@ locals { platform = "dolibarr" last_updated = "2026-01-07T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoStandards-Template-Generic.def.tf b/definitions/sync/MokoStandards-Template-Generic.def.tf index 73f312e..bd1402e 100644 --- a/definitions/sync/MokoStandards-Template-Generic.def.tf +++ b/definitions/sync/MokoStandards-Template-Generic.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoStandards-Template-Joomla-Component.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Component.def.tf new file mode 100644 index 0000000..a081178 --- /dev/null +++ b/definitions/sync/MokoStandards-Template-Joomla-Component.def.tf @@ -0,0 +1,1335 @@ +/** + * Repository Sync Tracking Definition: mokoconsulting-tech/MokoStandards-Template-Joomla-Component + * + * Auto-generated by MokoStandards bulk sync on 2026-04-02T15:30:04+00:00 + * Platform : waas-component + * Description: A repo template for a Joomla Component coding project according to MokoStandards + * + * DO NOT EDIT MANUALLY — this file is regenerated on every successful sync. + * To change what gets synced, edit api/definitions/default/waas-component.tf + * and re-run the bulk-repo-sync workflow. + */ + +locals { + sync_record = { + metadata = { + repo = "mokoconsulting-tech/MokoStandards-Template-Joomla-Component" + default_branch = "main" + detected_platform = "waas-component" + description = "A repo template for a Joomla Component coding project according to MokoStandards" + sync_timestamp = "2026-04-02T15:30:04+00:00" + source_repo = "mokoconsulting-tech/MokoStandards" + base_definition = "api/definitions/default/waas-component.tf" + } + + sync_stats = { + total_files = 41 + created_files = 3 + updated_files = 35 + skipped_files = 3 + } + + synced_files = [ + { path = "LICENSE" action = "updated" }, + { path = "SECURITY.md" action = "updated" }, + { path = "CODE_OF_CONDUCT.md" action = "updated" }, + { path = "CONTRIBUTING.md" action = "updated" }, + { path = "update.xml" action = "updated" }, + { path = "phpstan.neon" action = "updated" }, + { path = "Makefile" action = "updated" }, + { path = ".gitignore" action = "updated" }, + { path = "composer.json" action = "updated" }, + { path = ".mokostandards" action = "created" }, + { path = "docs/update-server.md" action = "created" }, + { path = ".github/copilot.yml" action = "updated" }, + { path = ".github/copilot-instructions.md" action = "updated" }, + { path = ".github/CLAUDE.md" action = "updated" }, + { path = ".github/workflows/codeql-analysis.yml" action = "updated" }, + { path = ".github/workflows/standards-compliance.yml" action = "updated" }, + { path = ".github/workflows/enterprise-firewall-setup.yml" action = "updated" }, + { path = ".github/workflows/deploy-dev.yml" action = "updated" }, + { path = ".github/workflows/deploy-demo.yml" action = "updated" }, + { path = ".github/workflows/deploy-rs.yml" action = "updated" }, + { path = ".github/workflows/sync-version-on-merge.yml" action = "updated" }, + { path = ".github/workflows/auto-release.yml" action = "updated" }, + { path = ".github/workflows/repository-cleanup.yml" action = "updated" }, + { path = ".github/workflows/auto-dev-issue.yml" action = "updated" }, + { path = ".github/workflows/repo_health.yml" action = "created" }, + { path = ".github/ISSUE_TEMPLATE/config.yml" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/adr.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/bug_report.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/documentation.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/enterprise_support.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/feature_request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/firewall-request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/question.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/request-license.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/rfc.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/security.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/joomla_issue.md" action = "updated" }, + { path = ".github/CODEOWNERS" action = "updated" }, + { path = ".github/.mokostandards" action = "migrated from root" }, + ] + + skipped_files = [ + { path = "GOVERNANCE.md" reason = "Preserved (always_overwrite=false)" }, + { path = ".github/workflows/ci-joomla.yml" reason = "Source file not found" }, + { path = ".github/workflows/custom/README.md" reason = "README — never overwritten" }, + ] + } +} + +# ---- Base platform definition (reference copy) ---- +/** + * MokoWaaS Component Structure Definition + * Standard repository structure for MokoWaaS (Joomla) components + * + * Copyright (C) 2026 Moko Consulting + * SPDX-License-Identifier: GPL-3.0-or-later + * Version: 05.00.00 + * Schema Version: 1.0 + */ + +locals { + repository_structure = { + metadata = { + name = "MokoWaaS Component" + description = "Standard repository structure for MokoWaaS (Joomla) components" + repository_type = "waas-component" + platform = "mokowaas" + last_updated = "2026-01-15T00:00:00Z" + maintainer = "Moko Consulting" + version = "05.00.00" + schema_version = "1.0" + } + + root_files = [ + { + name = "README.md" + extension = "md" + description = "Developer-focused documentation for contributors and maintainers" + required = true + always_overwrite = false + protected = true + audience = "developer" + }, + { + name = "LICENSE" + extension = "" + description = "License file (GPL-3.0-or-later) - Default for Joomla/WaaS components" + required = true + audience = "general" + template = "templates/licenses/GPL-3.0" + license_type = "GPL-3.0-or-later" + }, + { + name = "CHANGELOG.md" + extension = "md" + description = "Version history and changes" + required = true + audience = "general" + }, + { + name = "SECURITY.md" + extension = "md" + description = "Security policy and vulnerability reporting" + required = true + always_overwrite = true + template = "templates/docs/required/template-SECURITY.md" + audience = "general" + }, + { + name = "CODE_OF_CONDUCT.md" + extension = "md" + description = "Community code of conduct" + required = true + always_overwrite = true + template = "templates/docs/extra/template-CODE_OF_CONDUCT.md" + always_overwrite = true + audience = "contributor" + }, + { + name = "ROADMAP.md" + extension = "md" + description = "Project roadmap with version goals and milestones" + required = false + audience = "general" + }, + { + name = "CONTRIBUTING.md" + extension = "md" + description = "Contribution guidelines" + required = true + always_overwrite = true + template = "templates/docs/required/template-CONTRIBUTING.md" + audience = "contributor" + }, + { + name = "update.xml" + extension = "xml" + description = "Joomla extension update server manifest — lists releases for Joomla auto-update; must be kept in sync with manifest.xml version" + required = true + always_overwrite = false + audience = "developer" + template = "templates/joomla/update.xml.template" + stub_content = <<-MOKO_END + + + + {{EXTENSION_NAME}} + {{REPO_NAME}} — Moko Consulting Joomla extension + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + {{VERSION}} + {{REPO_URL}}/releases/tag/{{VERSION}} + + {{DOWNLOAD_URL}} + + + 7.4 + Moko Consulting + {{MAINTAINER_URL}} + + + MOKO_END + }, + { + name = "phpstan.neon" + extension = "neon" + description = "PHPStan static analysis config with Joomla framework class stubs" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/phpstan.joomla.neon" + }, + { + name = "Makefile" + description = "Build automation using MokoStandards templates" + required = true + always_overwrite = true + audience = "developer" + source_path = "templates/makefiles" + source_filename = "Makefile.joomla.template" + source_type = "template" + destination_path = "." + destination_filename = "Makefile" + create_path = false + template = "templates/makefiles/Makefile.joomla.template" + }, + { + name = ".gitignore" + extension = "gitignore" + description = "Git ignore patterns for Joomla development - preserved during sync operations" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/.gitignore.joomla" + validation_rules = [ + { + type = "content-pattern" + description = "Must contain sftp-config pattern to ignore SFTP sync configuration files" + pattern = "sftp-config" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.css pattern to ignore custom user CSS overrides" + pattern = "user\\.css" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.js pattern to ignore custom user JavaScript overrides" + pattern = "user\\.js" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain modulebuilder.txt pattern to ignore Joomla Module Builder artifacts" + pattern = "modulebuilder\\.txt" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain colors_custom.css pattern to ignore custom color scheme overrides" + pattern = "colors_custom\\.css" + severity = "error" + } + ] + }, + { + name = ".gitattributes" + extension = "gitattributes" + description = "Git attributes configuration" + required = true + audience = "developer" + }, + { + name = ".editorconfig" + extension = "editorconfig" + description = "Editor configuration for consistent coding style - preserved during sync" + required = true + always_overwrite = false + audience = "developer" + }, + { + name = "composer.json" + extension = "json" + description = "Composer manifest — requires mokoconsulting-tech/enterprise for CLI scripts and tooling" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/composer.joomla.json" + }, + { + name = ".mokostandards" + extension = "yml" + description = "MokoStandards governance attachment — links this repo back to the standards source" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/mokostandards.yml.template" + }, + { + name = "GOVERNANCE.md" + extension = "md" + description = "Project governance rules, roles, and decision process — auto-maintained by MokoStandards" + required = true + always_overwrite = false + protected = true + audience = "all" + template = "templates/docs/required/GOVERNANCE.md" + } + ] + + directories = [ + { + name = "site" + path = "site" + description = "Component frontend (site) code" + required = true + purpose = "Contains frontend component code deployed to site" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main site controller" + required = true + audience = "developer" + }, + { + name = "manifest.xml" + extension = "xml" + description = "Component manifest for site" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "site/controllers" + description = "Site controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "site/models" + description = "Site models" + requirement_status = "suggested" + }, + { + name = "views" + path = "site/views" + description = "Site views" + required = true + } + ] + }, + { + name = "admin" + path = "admin" + description = "Component backend (admin) code" + required = true + purpose = "Contains backend component code for administrator" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main admin controller" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "admin/controllers" + description = "Admin controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "admin/models" + description = "Admin models" + requirement_status = "suggested" + }, + { + name = "views" + path = "admin/views" + description = "Admin views" + required = true + }, + { + name = "sql" + path = "admin/sql" + description = "Database schema files" + requirement_status = "suggested" + } + ] + }, + { + name = "media" + path = "media" + description = "Media files (CSS, JS, images)" + requirement_status = "suggested" + purpose = "Contains static assets" + subdirectories = [ + { + name = "css" + path = "media/css" + description = "Stylesheets" + requirement_status = "suggested" + }, + { + name = "js" + path = "media/js" + description = "JavaScript files" + requirement_status = "suggested" + }, + { + name = "images" + path = "media/images" + description = "Image files" + requirement_status = "suggested" + } + ] + }, + { + name = "language" + path = "language" + description = "Language translation files" + required = true + purpose = "Contains language INI files" + }, + { + name = "docs" + path = "docs" + description = "Developer and technical documentation" + required = true + purpose = "Contains technical documentation, API docs, architecture diagrams" + files = [ + { + name = "index.md" + extension = "md" + description = "Documentation index" + required = true + }, + { + name = "update-server.md" + extension = "md" + description = "Joomla update server (update.xml) documentation" + required = true + always_overwrite = true + template = "templates/docs/required/template-update-server-joomla.md" + } + ] + }, + { + name = "scripts" + path = "scripts" + description = "Repo-specific scripts — not managed by MokoStandards sync" + required = false + purpose = "Optional directory for repo-specific build helpers and one-off scripts. MokoStandards tools are installed via Composer (mokoconsulting-tech/enterprise) and called through vendor/bin/." + files = [ + { + name = "MokoStandards.override.xml" + extension = "xml" + description = "MokoStandards sync override configuration - preserved during sync" + requirement_status = "optional" + always_overwrite = false + audience = "developer" + } + ] + }, + { + name = "tests" + path = "tests" + description = "Test files" + required = true + purpose = "Contains unit tests, integration tests, and test fixtures" + subdirectories = [ + { + name = "unit" + path = "tests/unit" + description = "Unit tests" + required = true + }, + { + name = "integration" + path = "tests/integration" + description = "Integration tests" + requirement_status = "suggested" + } + ] + }, + { + name = ".github" + path = ".github" + description = "GitHub-specific configuration" + requirement_status = "suggested" + purpose = "Contains GitHub Actions workflows and configuration" + files = [ + { + name = "copilot.yml" + extension = "yml" + description = "GitHub Copilot allowed domains configuration" + requirement_status = "required" + always_overwrite = true + template = ".github/copilot.yml" + }, + { + name = "copilot-instructions.md" + extension = "md" + description = "GitHub Copilot custom instructions enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "copilot-instructions.md" + template = "templates/github/copilot-instructions.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # {{REPO_NAME}} — GitHub Copilot Custom Instructions + + ## What This Repo Is + + This is a **Moko Consulting MokoWaaS** (Joomla) repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync. + + Repository URL: {{REPO_URL}} + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Platform: **Joomla 4.x / MokoWaaS** + + --- + + ## Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. JavaScript may be used for frontend enhancements. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + ## File Header — Always Required on New Files + + Every new file needs a copyright header as its first content. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /path/to/file.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown:** + ```markdown + + ``` + + **YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. JSON files are exempt. + + --- + + ## Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`. + - The `VERSION: XX.YY.ZZ` field in `README.md` governs all other version references. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. + + ```xml + + 01.02.04 + + + + + {{EXTENSION_NAME}} + 01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + + + + ``` + + --- + + ## Joomla Extension Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required, see below) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images (deployed to /media/{{EXTENSION_ELEMENT}}/) + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ + │ ├── copilot-instructions.md # This file + │ └── CLAUDE.md + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + ├── LICENSE # GPL-3.0-or-later + └── Makefile # Build automation + ``` + + --- + + ## update.xml — Required in Repo Root + + `update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. + + The `manifest.xml` must reference it via: + ```xml + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. + - The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. + - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). + - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. + + --- + + ## manifest.xml Rules + + - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). + - `` tag must be kept in sync with `README.md` version and `update.xml`. + - Must include `` block pointing to this repo's `update.xml`. + - Must include `` and `` sections. + - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. + + --- + + ## GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these in workflows + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + ## MokoStandards Reference + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies: + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + + --- + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `MyController` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + --- + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + --- + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + ## Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed manifest.xml | Update `update.xml` version; bump README.md version | + | New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + ## Key Constraints + + - Never commit directly to `main` — all changes go via PR, squash-merged + - Never skip the FILE INFORMATION block on a new file + - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files + - Never hardcode version numbers in body text — update `README.md` and let automation propagate + - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` + - Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync + MOKO_END + }, + { + name = "CLAUDE.md" + extension = "md" + description = "Claude AI assistant context enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "CLAUDE.md" + template = "templates/github/CLAUDE.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{REPO_DESCRIPTION}}` | First paragraph of `README.md` body, or the GitHub repo description | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # What This Repo Is + + **{{REPO_NAME}}** is a Moko Consulting **MokoWaaS** (Joomla) extension repository. + + {{REPO_DESCRIPTION}} + + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Repository URL: {{REPO_URL}} + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) — the single source of truth for coding standards, file-header policies, GitHub Actions workflows, and Terraform configuration templates across all Moko Consulting repositories. + + --- + + # Repo Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ # CI/CD workflows (synced from MokoStandards) + │ ├── copilot-instructions.md + │ └── CLAUDE.md # This file + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + └── LICENSE # GPL-3.0-or-later + ``` + + --- + + # Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + # Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it to all `FILE INFORMATION` headers automatically on merge. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a version number in body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + Three files must **always have the same version**: + + | File | Where the version lives | + |------|------------------------| + | `README.md` | `FILE INFORMATION` block + badge | + | `manifest.xml` | `` tag | + | `update.xml` | `` in the most recent `` block | + + The `make release` command / release workflow syncs all three automatically. + + --- + + # update.xml — Required in Repo Root + + `update.xml` is the Joomla update server manifest. It allows Joomla installations to check for new versions of this extension via: + + ```xml + + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release prepends a new `` block at the top — older entries are preserved. + - `` in `update.xml` must exactly match `` in `manifest.xml` and `README.md`. + - `` must be a publicly accessible GitHub Releases asset URL. + - `` — backslash is literal (Joomla regex syntax). + + Example `update.xml` entry for a new release: + ```xml + + + {{EXTENSION_NAME}} + {{REPO_NAME}} + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + 01.02.04 + {{REPO_URL}}/releases/tag/01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + 7.4 + Moko Consulting + https://mokoconsulting.tech + + + ``` + + --- + + # File Header Requirements + + Every new file **must** have a copyright header as its first content. JSON files, binary files, generated files, and third-party files are exempt. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /site/controllers/item.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of file purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown / YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. + + --- + + # Coding Standards + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `ItemModel` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + # GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + # Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed `manifest.xml` | Sync version to `update.xml` and `README.md` | + | New release | Prepend `` to `update.xml`; update `CHANGELOG.md`; bump `README.md` | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + # What NOT to Do + + - **Never commit directly to `main`** — all changes go through a PR. + - **Never hardcode version numbers** in body text — update `README.md` and let automation propagate. + - **Never let `manifest.xml`, `update.xml`, and `README.md` versions diverge.** + - **Never skip the FILE INFORMATION block** on a new source file. + - **Never use bare `catch (\Throwable $e) {}`** — always log or re-throw. + - **Never mix tabs and spaces** within a file — follow `.editorconfig`. + - **Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows** — always use `secrets.GH_TOKEN`. + - **Never remove `defined('_JEXEC') or die;`** from web-accessible PHP files. + + --- + + # PR Checklist + + Before opening a PR, verify: + + - [ ] Patch version bumped in `README.md` (e.g. `01.02.03` → `01.02.04`) + - [ ] If this is a release: `manifest.xml` version updated; `update.xml` updated with new entry + - [ ] FILE INFORMATION headers updated in modified files + - [ ] CHANGELOG.md updated + - [ ] Tests pass + + --- + + # Key Policy Documents (MokoStandards) + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + MOKO_END + } + ] + subdirectories = [ + { + name = "workflows" + path = ".github/workflows" + description = "GitHub Actions workflows" + requirement_status = "required" + files = [ + { + name = "ci-joomla.yml" + extension = "yml" + description = "Joomla-specific CI workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/ci-joomla.yml.template" + }, + { + name = "codeql-analysis.yml" + extension = "yml" + description = "CodeQL security analysis workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/generic/codeql-analysis.yml.template" + }, + { + name = "standards-compliance.yml" + extension = "yml" + description = "MokoStandards compliance validation" + requirement_status = "required" + always_overwrite = true + template = ".github/workflows/standards-compliance.yml" + }, + { + name = "enterprise-firewall-setup.yml" + extension = "yml" + description = "Enterprise firewall configuration for trusted domain access" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/enterprise-firewall-setup.yml.template" + }, + { + name = "deploy-dev.yml" + extension = "yml" + description = "SFTP deployment of src/ to the development server" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-dev.yml.template" + }, + { + name = "deploy-demo.yml" + extension = "yml" + description = "SFTP deployment of src/ to the demo server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-demo.yml.template" + }, + { + name = "deploy-rs.yml" + extension = "yml" + description = "SFTP deployment of src/ to the release staging server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-rs.yml.template" + }, + { + name = "sync-version-on-merge.yml" + extension = "yml" + description = "Auto-bump patch version on merge and propagate to all file headers" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/sync-version-on-merge.yml.template" + }, + { + name = "auto-release.yml" + extension = "yml" + description = "Auto-create GitHub Release on push to main with version from README.md" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-release.yml.template" + }, + { + name = "repository-cleanup.yml" + extension = "yml" + description = "Scheduled cleanup: delete retired workflows, stale branches, old workflow runs" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/repository-cleanup.yml.template" + }, + { + name = "auto-dev-issue.yml" + extension = "yml" + description = "Auto-create tracking issue when a dev/** branch is pushed" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-dev-issue.yml.template" + }, + { + name = "repo_health.yml" + extension = "yml" + description = "Joomla-specific repository health check workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/repo_health.yml.template" + } + ] + }, + { + name = "ISSUE_TEMPLATE" + path = ".github/ISSUE_TEMPLATE" + description = "GitHub issue templates synced from MokoStandards" + requirement_status = "required" + files = [ + { + name = "config.yml" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/config.yml" + }, + { + name = "adr.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/adr.md" + }, + { + name = "bug_report.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/bug_report.md" + }, + { + name = "documentation.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/documentation.md" + }, + { + name = "enterprise_support.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/enterprise_support.md" + }, + { + name = "feature_request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/feature_request.md" + }, + { + name = "firewall-request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/firewall-request.md" + }, + { + name = "question.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/question.md" + }, + { + name = "request-license.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/request-license.md" + }, + { + name = "rfc.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/rfc.md" + }, + { + name = "security.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/security.md" + }, + { + name = "joomla_issue.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/joomla_issue.md" + } + ] + } + ] + } + ] + + repository_requirements = { + secrets = [ + { + name = "GH_TOKEN" + description = "Org-level GitHub PAT for automation" + required = true + scope = "org" + }, + { + name = "DEV_FTP_KEY" + description = "SSH private key for SFTP dev deployment (preferred); if DEV_FTP_PASSWORD is also set it is used as the key passphrase, with password-only as fallback" + required = false + scope = "org" + }, + { + name = "DEV_FTP_PASSWORD" + description = "SFTP password for dev deployment; used as SSH key passphrase when DEV_FTP_KEY is also set, and as standalone fallback if key auth fails" + required = false + scope = "org" + note = "At least one of DEV_FTP_KEY or DEV_FTP_PASSWORD must be configured" + } + ] + + variables = [ + { + name = "DEV_FTP_HOST" + description = "Dev server hostname; may include port suffix (e.g. dev.example.com or dev.example.com:2222)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PATH" + description = "Base remote path for SFTP deployment (e.g. /var/www/html)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_USERNAME" + description = "SFTP username for dev server authentication" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PORT" + description = "Explicit SFTP port override; if omitted the port is parsed from DEV_FTP_HOST or defaults to 22" + required = false + scope = "org" + }, + { + name = "DEV_FTP_SUFFIX" + description = "Per-repo path suffix appended to DEV_FTP_PATH (e.g. /my-extension)" + required = false + scope = "repo" + } + ] + } + } +} diff --git a/definitions/sync/MokoStandards-Template-Joomla-Library.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Library.def.tf new file mode 100644 index 0000000..817bbab --- /dev/null +++ b/definitions/sync/MokoStandards-Template-Joomla-Library.def.tf @@ -0,0 +1,1335 @@ +/** + * Repository Sync Tracking Definition: mokoconsulting-tech/MokoStandards-Template-Joomla-Library + * + * Auto-generated by MokoStandards bulk sync on 2026-04-02T15:31:13+00:00 + * Platform : waas-component + * Description: A repo template for a Joomla Library coding project according to MokoStandards + * + * DO NOT EDIT MANUALLY — this file is regenerated on every successful sync. + * To change what gets synced, edit api/definitions/default/waas-component.tf + * and re-run the bulk-repo-sync workflow. + */ + +locals { + sync_record = { + metadata = { + repo = "mokoconsulting-tech/MokoStandards-Template-Joomla-Library" + default_branch = "main" + detected_platform = "waas-component" + description = "A repo template for a Joomla Library coding project according to MokoStandards" + sync_timestamp = "2026-04-02T15:31:13+00:00" + source_repo = "mokoconsulting-tech/MokoStandards" + base_definition = "api/definitions/default/waas-component.tf" + } + + sync_stats = { + total_files = 41 + created_files = 3 + updated_files = 35 + skipped_files = 3 + } + + synced_files = [ + { path = "LICENSE" action = "updated" }, + { path = "SECURITY.md" action = "updated" }, + { path = "CODE_OF_CONDUCT.md" action = "updated" }, + { path = "CONTRIBUTING.md" action = "updated" }, + { path = "update.xml" action = "updated" }, + { path = "phpstan.neon" action = "updated" }, + { path = "Makefile" action = "updated" }, + { path = ".gitignore" action = "updated" }, + { path = "composer.json" action = "updated" }, + { path = ".mokostandards" action = "created" }, + { path = "docs/update-server.md" action = "created" }, + { path = ".github/copilot.yml" action = "updated" }, + { path = ".github/copilot-instructions.md" action = "updated" }, + { path = ".github/CLAUDE.md" action = "updated" }, + { path = ".github/workflows/codeql-analysis.yml" action = "updated" }, + { path = ".github/workflows/standards-compliance.yml" action = "updated" }, + { path = ".github/workflows/enterprise-firewall-setup.yml" action = "updated" }, + { path = ".github/workflows/deploy-dev.yml" action = "updated" }, + { path = ".github/workflows/deploy-demo.yml" action = "updated" }, + { path = ".github/workflows/deploy-rs.yml" action = "updated" }, + { path = ".github/workflows/sync-version-on-merge.yml" action = "updated" }, + { path = ".github/workflows/auto-release.yml" action = "updated" }, + { path = ".github/workflows/repository-cleanup.yml" action = "updated" }, + { path = ".github/workflows/auto-dev-issue.yml" action = "updated" }, + { path = ".github/workflows/repo_health.yml" action = "created" }, + { path = ".github/ISSUE_TEMPLATE/config.yml" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/adr.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/bug_report.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/documentation.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/enterprise_support.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/feature_request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/firewall-request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/question.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/request-license.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/rfc.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/security.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/joomla_issue.md" action = "updated" }, + { path = ".github/CODEOWNERS" action = "updated" }, + { path = ".github/.mokostandards" action = "migrated from root" }, + ] + + skipped_files = [ + { path = "GOVERNANCE.md" reason = "Preserved (always_overwrite=false)" }, + { path = ".github/workflows/ci-joomla.yml" reason = "Source file not found" }, + { path = ".github/workflows/custom/README.md" reason = "README — never overwritten" }, + ] + } +} + +# ---- Base platform definition (reference copy) ---- +/** + * MokoWaaS Component Structure Definition + * Standard repository structure for MokoWaaS (Joomla) components + * + * Copyright (C) 2026 Moko Consulting + * SPDX-License-Identifier: GPL-3.0-or-later + * Version: 05.00.00 + * Schema Version: 1.0 + */ + +locals { + repository_structure = { + metadata = { + name = "MokoWaaS Component" + description = "Standard repository structure for MokoWaaS (Joomla) components" + repository_type = "waas-component" + platform = "mokowaas" + last_updated = "2026-01-15T00:00:00Z" + maintainer = "Moko Consulting" + version = "05.00.00" + schema_version = "1.0" + } + + root_files = [ + { + name = "README.md" + extension = "md" + description = "Developer-focused documentation for contributors and maintainers" + required = true + always_overwrite = false + protected = true + audience = "developer" + }, + { + name = "LICENSE" + extension = "" + description = "License file (GPL-3.0-or-later) - Default for Joomla/WaaS components" + required = true + audience = "general" + template = "templates/licenses/GPL-3.0" + license_type = "GPL-3.0-or-later" + }, + { + name = "CHANGELOG.md" + extension = "md" + description = "Version history and changes" + required = true + audience = "general" + }, + { + name = "SECURITY.md" + extension = "md" + description = "Security policy and vulnerability reporting" + required = true + always_overwrite = true + template = "templates/docs/required/template-SECURITY.md" + audience = "general" + }, + { + name = "CODE_OF_CONDUCT.md" + extension = "md" + description = "Community code of conduct" + required = true + always_overwrite = true + template = "templates/docs/extra/template-CODE_OF_CONDUCT.md" + always_overwrite = true + audience = "contributor" + }, + { + name = "ROADMAP.md" + extension = "md" + description = "Project roadmap with version goals and milestones" + required = false + audience = "general" + }, + { + name = "CONTRIBUTING.md" + extension = "md" + description = "Contribution guidelines" + required = true + always_overwrite = true + template = "templates/docs/required/template-CONTRIBUTING.md" + audience = "contributor" + }, + { + name = "update.xml" + extension = "xml" + description = "Joomla extension update server manifest — lists releases for Joomla auto-update; must be kept in sync with manifest.xml version" + required = true + always_overwrite = false + audience = "developer" + template = "templates/joomla/update.xml.template" + stub_content = <<-MOKO_END + + + + {{EXTENSION_NAME}} + {{REPO_NAME}} — Moko Consulting Joomla extension + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + {{VERSION}} + {{REPO_URL}}/releases/tag/{{VERSION}} + + {{DOWNLOAD_URL}} + + + 7.4 + Moko Consulting + {{MAINTAINER_URL}} + + + MOKO_END + }, + { + name = "phpstan.neon" + extension = "neon" + description = "PHPStan static analysis config with Joomla framework class stubs" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/phpstan.joomla.neon" + }, + { + name = "Makefile" + description = "Build automation using MokoStandards templates" + required = true + always_overwrite = true + audience = "developer" + source_path = "templates/makefiles" + source_filename = "Makefile.joomla.template" + source_type = "template" + destination_path = "." + destination_filename = "Makefile" + create_path = false + template = "templates/makefiles/Makefile.joomla.template" + }, + { + name = ".gitignore" + extension = "gitignore" + description = "Git ignore patterns for Joomla development - preserved during sync operations" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/.gitignore.joomla" + validation_rules = [ + { + type = "content-pattern" + description = "Must contain sftp-config pattern to ignore SFTP sync configuration files" + pattern = "sftp-config" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.css pattern to ignore custom user CSS overrides" + pattern = "user\\.css" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.js pattern to ignore custom user JavaScript overrides" + pattern = "user\\.js" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain modulebuilder.txt pattern to ignore Joomla Module Builder artifacts" + pattern = "modulebuilder\\.txt" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain colors_custom.css pattern to ignore custom color scheme overrides" + pattern = "colors_custom\\.css" + severity = "error" + } + ] + }, + { + name = ".gitattributes" + extension = "gitattributes" + description = "Git attributes configuration" + required = true + audience = "developer" + }, + { + name = ".editorconfig" + extension = "editorconfig" + description = "Editor configuration for consistent coding style - preserved during sync" + required = true + always_overwrite = false + audience = "developer" + }, + { + name = "composer.json" + extension = "json" + description = "Composer manifest — requires mokoconsulting-tech/enterprise for CLI scripts and tooling" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/composer.joomla.json" + }, + { + name = ".mokostandards" + extension = "yml" + description = "MokoStandards governance attachment — links this repo back to the standards source" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/mokostandards.yml.template" + }, + { + name = "GOVERNANCE.md" + extension = "md" + description = "Project governance rules, roles, and decision process — auto-maintained by MokoStandards" + required = true + always_overwrite = false + protected = true + audience = "all" + template = "templates/docs/required/GOVERNANCE.md" + } + ] + + directories = [ + { + name = "site" + path = "site" + description = "Component frontend (site) code" + required = true + purpose = "Contains frontend component code deployed to site" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main site controller" + required = true + audience = "developer" + }, + { + name = "manifest.xml" + extension = "xml" + description = "Component manifest for site" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "site/controllers" + description = "Site controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "site/models" + description = "Site models" + requirement_status = "suggested" + }, + { + name = "views" + path = "site/views" + description = "Site views" + required = true + } + ] + }, + { + name = "admin" + path = "admin" + description = "Component backend (admin) code" + required = true + purpose = "Contains backend component code for administrator" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main admin controller" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "admin/controllers" + description = "Admin controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "admin/models" + description = "Admin models" + requirement_status = "suggested" + }, + { + name = "views" + path = "admin/views" + description = "Admin views" + required = true + }, + { + name = "sql" + path = "admin/sql" + description = "Database schema files" + requirement_status = "suggested" + } + ] + }, + { + name = "media" + path = "media" + description = "Media files (CSS, JS, images)" + requirement_status = "suggested" + purpose = "Contains static assets" + subdirectories = [ + { + name = "css" + path = "media/css" + description = "Stylesheets" + requirement_status = "suggested" + }, + { + name = "js" + path = "media/js" + description = "JavaScript files" + requirement_status = "suggested" + }, + { + name = "images" + path = "media/images" + description = "Image files" + requirement_status = "suggested" + } + ] + }, + { + name = "language" + path = "language" + description = "Language translation files" + required = true + purpose = "Contains language INI files" + }, + { + name = "docs" + path = "docs" + description = "Developer and technical documentation" + required = true + purpose = "Contains technical documentation, API docs, architecture diagrams" + files = [ + { + name = "index.md" + extension = "md" + description = "Documentation index" + required = true + }, + { + name = "update-server.md" + extension = "md" + description = "Joomla update server (update.xml) documentation" + required = true + always_overwrite = true + template = "templates/docs/required/template-update-server-joomla.md" + } + ] + }, + { + name = "scripts" + path = "scripts" + description = "Repo-specific scripts — not managed by MokoStandards sync" + required = false + purpose = "Optional directory for repo-specific build helpers and one-off scripts. MokoStandards tools are installed via Composer (mokoconsulting-tech/enterprise) and called through vendor/bin/." + files = [ + { + name = "MokoStandards.override.xml" + extension = "xml" + description = "MokoStandards sync override configuration - preserved during sync" + requirement_status = "optional" + always_overwrite = false + audience = "developer" + } + ] + }, + { + name = "tests" + path = "tests" + description = "Test files" + required = true + purpose = "Contains unit tests, integration tests, and test fixtures" + subdirectories = [ + { + name = "unit" + path = "tests/unit" + description = "Unit tests" + required = true + }, + { + name = "integration" + path = "tests/integration" + description = "Integration tests" + requirement_status = "suggested" + } + ] + }, + { + name = ".github" + path = ".github" + description = "GitHub-specific configuration" + requirement_status = "suggested" + purpose = "Contains GitHub Actions workflows and configuration" + files = [ + { + name = "copilot.yml" + extension = "yml" + description = "GitHub Copilot allowed domains configuration" + requirement_status = "required" + always_overwrite = true + template = ".github/copilot.yml" + }, + { + name = "copilot-instructions.md" + extension = "md" + description = "GitHub Copilot custom instructions enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "copilot-instructions.md" + template = "templates/github/copilot-instructions.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # {{REPO_NAME}} — GitHub Copilot Custom Instructions + + ## What This Repo Is + + This is a **Moko Consulting MokoWaaS** (Joomla) repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync. + + Repository URL: {{REPO_URL}} + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Platform: **Joomla 4.x / MokoWaaS** + + --- + + ## Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. JavaScript may be used for frontend enhancements. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + ## File Header — Always Required on New Files + + Every new file needs a copyright header as its first content. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /path/to/file.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown:** + ```markdown + + ``` + + **YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. JSON files are exempt. + + --- + + ## Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`. + - The `VERSION: XX.YY.ZZ` field in `README.md` governs all other version references. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. + + ```xml + + 01.02.04 + + + + + {{EXTENSION_NAME}} + 01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + + + + ``` + + --- + + ## Joomla Extension Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required, see below) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images (deployed to /media/{{EXTENSION_ELEMENT}}/) + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ + │ ├── copilot-instructions.md # This file + │ └── CLAUDE.md + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + ├── LICENSE # GPL-3.0-or-later + └── Makefile # Build automation + ``` + + --- + + ## update.xml — Required in Repo Root + + `update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. + + The `manifest.xml` must reference it via: + ```xml + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. + - The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. + - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). + - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. + + --- + + ## manifest.xml Rules + + - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). + - `` tag must be kept in sync with `README.md` version and `update.xml`. + - Must include `` block pointing to this repo's `update.xml`. + - Must include `` and `` sections. + - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. + + --- + + ## GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these in workflows + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + ## MokoStandards Reference + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies: + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + + --- + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `MyController` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + --- + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + --- + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + ## Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed manifest.xml | Update `update.xml` version; bump README.md version | + | New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + ## Key Constraints + + - Never commit directly to `main` — all changes go via PR, squash-merged + - Never skip the FILE INFORMATION block on a new file + - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files + - Never hardcode version numbers in body text — update `README.md` and let automation propagate + - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` + - Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync + MOKO_END + }, + { + name = "CLAUDE.md" + extension = "md" + description = "Claude AI assistant context enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "CLAUDE.md" + template = "templates/github/CLAUDE.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{REPO_DESCRIPTION}}` | First paragraph of `README.md` body, or the GitHub repo description | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # What This Repo Is + + **{{REPO_NAME}}** is a Moko Consulting **MokoWaaS** (Joomla) extension repository. + + {{REPO_DESCRIPTION}} + + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Repository URL: {{REPO_URL}} + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) — the single source of truth for coding standards, file-header policies, GitHub Actions workflows, and Terraform configuration templates across all Moko Consulting repositories. + + --- + + # Repo Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ # CI/CD workflows (synced from MokoStandards) + │ ├── copilot-instructions.md + │ └── CLAUDE.md # This file + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + └── LICENSE # GPL-3.0-or-later + ``` + + --- + + # Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + # Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it to all `FILE INFORMATION` headers automatically on merge. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a version number in body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + Three files must **always have the same version**: + + | File | Where the version lives | + |------|------------------------| + | `README.md` | `FILE INFORMATION` block + badge | + | `manifest.xml` | `` tag | + | `update.xml` | `` in the most recent `` block | + + The `make release` command / release workflow syncs all three automatically. + + --- + + # update.xml — Required in Repo Root + + `update.xml` is the Joomla update server manifest. It allows Joomla installations to check for new versions of this extension via: + + ```xml + + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release prepends a new `` block at the top — older entries are preserved. + - `` in `update.xml` must exactly match `` in `manifest.xml` and `README.md`. + - `` must be a publicly accessible GitHub Releases asset URL. + - `` — backslash is literal (Joomla regex syntax). + + Example `update.xml` entry for a new release: + ```xml + + + {{EXTENSION_NAME}} + {{REPO_NAME}} + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + 01.02.04 + {{REPO_URL}}/releases/tag/01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + 7.4 + Moko Consulting + https://mokoconsulting.tech + + + ``` + + --- + + # File Header Requirements + + Every new file **must** have a copyright header as its first content. JSON files, binary files, generated files, and third-party files are exempt. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /site/controllers/item.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of file purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown / YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. + + --- + + # Coding Standards + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `ItemModel` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + # GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + # Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed `manifest.xml` | Sync version to `update.xml` and `README.md` | + | New release | Prepend `` to `update.xml`; update `CHANGELOG.md`; bump `README.md` | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + # What NOT to Do + + - **Never commit directly to `main`** — all changes go through a PR. + - **Never hardcode version numbers** in body text — update `README.md` and let automation propagate. + - **Never let `manifest.xml`, `update.xml`, and `README.md` versions diverge.** + - **Never skip the FILE INFORMATION block** on a new source file. + - **Never use bare `catch (\Throwable $e) {}`** — always log or re-throw. + - **Never mix tabs and spaces** within a file — follow `.editorconfig`. + - **Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows** — always use `secrets.GH_TOKEN`. + - **Never remove `defined('_JEXEC') or die;`** from web-accessible PHP files. + + --- + + # PR Checklist + + Before opening a PR, verify: + + - [ ] Patch version bumped in `README.md` (e.g. `01.02.03` → `01.02.04`) + - [ ] If this is a release: `manifest.xml` version updated; `update.xml` updated with new entry + - [ ] FILE INFORMATION headers updated in modified files + - [ ] CHANGELOG.md updated + - [ ] Tests pass + + --- + + # Key Policy Documents (MokoStandards) + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + MOKO_END + } + ] + subdirectories = [ + { + name = "workflows" + path = ".github/workflows" + description = "GitHub Actions workflows" + requirement_status = "required" + files = [ + { + name = "ci-joomla.yml" + extension = "yml" + description = "Joomla-specific CI workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/ci-joomla.yml.template" + }, + { + name = "codeql-analysis.yml" + extension = "yml" + description = "CodeQL security analysis workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/generic/codeql-analysis.yml.template" + }, + { + name = "standards-compliance.yml" + extension = "yml" + description = "MokoStandards compliance validation" + requirement_status = "required" + always_overwrite = true + template = ".github/workflows/standards-compliance.yml" + }, + { + name = "enterprise-firewall-setup.yml" + extension = "yml" + description = "Enterprise firewall configuration for trusted domain access" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/enterprise-firewall-setup.yml.template" + }, + { + name = "deploy-dev.yml" + extension = "yml" + description = "SFTP deployment of src/ to the development server" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-dev.yml.template" + }, + { + name = "deploy-demo.yml" + extension = "yml" + description = "SFTP deployment of src/ to the demo server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-demo.yml.template" + }, + { + name = "deploy-rs.yml" + extension = "yml" + description = "SFTP deployment of src/ to the release staging server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-rs.yml.template" + }, + { + name = "sync-version-on-merge.yml" + extension = "yml" + description = "Auto-bump patch version on merge and propagate to all file headers" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/sync-version-on-merge.yml.template" + }, + { + name = "auto-release.yml" + extension = "yml" + description = "Auto-create GitHub Release on push to main with version from README.md" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-release.yml.template" + }, + { + name = "repository-cleanup.yml" + extension = "yml" + description = "Scheduled cleanup: delete retired workflows, stale branches, old workflow runs" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/repository-cleanup.yml.template" + }, + { + name = "auto-dev-issue.yml" + extension = "yml" + description = "Auto-create tracking issue when a dev/** branch is pushed" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-dev-issue.yml.template" + }, + { + name = "repo_health.yml" + extension = "yml" + description = "Joomla-specific repository health check workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/repo_health.yml.template" + } + ] + }, + { + name = "ISSUE_TEMPLATE" + path = ".github/ISSUE_TEMPLATE" + description = "GitHub issue templates synced from MokoStandards" + requirement_status = "required" + files = [ + { + name = "config.yml" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/config.yml" + }, + { + name = "adr.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/adr.md" + }, + { + name = "bug_report.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/bug_report.md" + }, + { + name = "documentation.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/documentation.md" + }, + { + name = "enterprise_support.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/enterprise_support.md" + }, + { + name = "feature_request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/feature_request.md" + }, + { + name = "firewall-request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/firewall-request.md" + }, + { + name = "question.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/question.md" + }, + { + name = "request-license.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/request-license.md" + }, + { + name = "rfc.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/rfc.md" + }, + { + name = "security.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/security.md" + }, + { + name = "joomla_issue.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/joomla_issue.md" + } + ] + } + ] + } + ] + + repository_requirements = { + secrets = [ + { + name = "GH_TOKEN" + description = "Org-level GitHub PAT for automation" + required = true + scope = "org" + }, + { + name = "DEV_FTP_KEY" + description = "SSH private key for SFTP dev deployment (preferred); if DEV_FTP_PASSWORD is also set it is used as the key passphrase, with password-only as fallback" + required = false + scope = "org" + }, + { + name = "DEV_FTP_PASSWORD" + description = "SFTP password for dev deployment; used as SSH key passphrase when DEV_FTP_KEY is also set, and as standalone fallback if key auth fails" + required = false + scope = "org" + note = "At least one of DEV_FTP_KEY or DEV_FTP_PASSWORD must be configured" + } + ] + + variables = [ + { + name = "DEV_FTP_HOST" + description = "Dev server hostname; may include port suffix (e.g. dev.example.com or dev.example.com:2222)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PATH" + description = "Base remote path for SFTP deployment (e.g. /var/www/html)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_USERNAME" + description = "SFTP username for dev server authentication" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PORT" + description = "Explicit SFTP port override; if omitted the port is parsed from DEV_FTP_HOST or defaults to 22" + required = false + scope = "org" + }, + { + name = "DEV_FTP_SUFFIX" + description = "Per-repo path suffix appended to DEV_FTP_PATH (e.g. /my-extension)" + required = false + scope = "repo" + } + ] + } + } +} diff --git a/definitions/sync/MokoStandards-Template-Joomla-Module.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Module.def.tf new file mode 100644 index 0000000..27d9f65 --- /dev/null +++ b/definitions/sync/MokoStandards-Template-Joomla-Module.def.tf @@ -0,0 +1,1335 @@ +/** + * Repository Sync Tracking Definition: mokoconsulting-tech/MokoStandards-Template-Joomla-Module + * + * Auto-generated by MokoStandards bulk sync on 2026-04-02T15:29:31+00:00 + * Platform : waas-component + * Description: A repo template for a Joomla Module coding project according to MokoStandards + * + * DO NOT EDIT MANUALLY — this file is regenerated on every successful sync. + * To change what gets synced, edit api/definitions/default/waas-component.tf + * and re-run the bulk-repo-sync workflow. + */ + +locals { + sync_record = { + metadata = { + repo = "mokoconsulting-tech/MokoStandards-Template-Joomla-Module" + default_branch = "main" + detected_platform = "waas-component" + description = "A repo template for a Joomla Module coding project according to MokoStandards" + sync_timestamp = "2026-04-02T15:29:31+00:00" + source_repo = "mokoconsulting-tech/MokoStandards" + base_definition = "api/definitions/default/waas-component.tf" + } + + sync_stats = { + total_files = 41 + created_files = 4 + updated_files = 34 + skipped_files = 3 + } + + synced_files = [ + { path = "LICENSE" action = "updated" }, + { path = "SECURITY.md" action = "created" }, + { path = "CODE_OF_CONDUCT.md" action = "updated" }, + { path = "CONTRIBUTING.md" action = "updated" }, + { path = "update.xml" action = "updated" }, + { path = "phpstan.neon" action = "updated" }, + { path = "Makefile" action = "updated" }, + { path = ".gitignore" action = "updated" }, + { path = "composer.json" action = "updated" }, + { path = ".mokostandards" action = "created" }, + { path = "docs/update-server.md" action = "created" }, + { path = ".github/copilot.yml" action = "updated" }, + { path = ".github/copilot-instructions.md" action = "updated" }, + { path = ".github/CLAUDE.md" action = "updated" }, + { path = ".github/workflows/codeql-analysis.yml" action = "updated" }, + { path = ".github/workflows/standards-compliance.yml" action = "updated" }, + { path = ".github/workflows/enterprise-firewall-setup.yml" action = "updated" }, + { path = ".github/workflows/deploy-dev.yml" action = "updated" }, + { path = ".github/workflows/deploy-demo.yml" action = "updated" }, + { path = ".github/workflows/deploy-rs.yml" action = "updated" }, + { path = ".github/workflows/sync-version-on-merge.yml" action = "updated" }, + { path = ".github/workflows/auto-release.yml" action = "updated" }, + { path = ".github/workflows/repository-cleanup.yml" action = "updated" }, + { path = ".github/workflows/auto-dev-issue.yml" action = "updated" }, + { path = ".github/workflows/repo_health.yml" action = "created" }, + { path = ".github/ISSUE_TEMPLATE/config.yml" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/adr.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/bug_report.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/documentation.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/enterprise_support.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/feature_request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/firewall-request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/question.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/request-license.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/rfc.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/security.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/joomla_issue.md" action = "updated" }, + { path = ".github/CODEOWNERS" action = "updated" }, + { path = ".github/.mokostandards" action = "migrated from root" }, + ] + + skipped_files = [ + { path = "GOVERNANCE.md" reason = "Preserved (always_overwrite=false)" }, + { path = ".github/workflows/ci-joomla.yml" reason = "Source file not found" }, + { path = ".github/workflows/custom/README.md" reason = "README — never overwritten" }, + ] + } +} + +# ---- Base platform definition (reference copy) ---- +/** + * MokoWaaS Component Structure Definition + * Standard repository structure for MokoWaaS (Joomla) components + * + * Copyright (C) 2026 Moko Consulting + * SPDX-License-Identifier: GPL-3.0-or-later + * Version: 05.00.00 + * Schema Version: 1.0 + */ + +locals { + repository_structure = { + metadata = { + name = "MokoWaaS Component" + description = "Standard repository structure for MokoWaaS (Joomla) components" + repository_type = "waas-component" + platform = "mokowaas" + last_updated = "2026-01-15T00:00:00Z" + maintainer = "Moko Consulting" + version = "05.00.00" + schema_version = "1.0" + } + + root_files = [ + { + name = "README.md" + extension = "md" + description = "Developer-focused documentation for contributors and maintainers" + required = true + always_overwrite = false + protected = true + audience = "developer" + }, + { + name = "LICENSE" + extension = "" + description = "License file (GPL-3.0-or-later) - Default for Joomla/WaaS components" + required = true + audience = "general" + template = "templates/licenses/GPL-3.0" + license_type = "GPL-3.0-or-later" + }, + { + name = "CHANGELOG.md" + extension = "md" + description = "Version history and changes" + required = true + audience = "general" + }, + { + name = "SECURITY.md" + extension = "md" + description = "Security policy and vulnerability reporting" + required = true + always_overwrite = true + template = "templates/docs/required/template-SECURITY.md" + audience = "general" + }, + { + name = "CODE_OF_CONDUCT.md" + extension = "md" + description = "Community code of conduct" + required = true + always_overwrite = true + template = "templates/docs/extra/template-CODE_OF_CONDUCT.md" + always_overwrite = true + audience = "contributor" + }, + { + name = "ROADMAP.md" + extension = "md" + description = "Project roadmap with version goals and milestones" + required = false + audience = "general" + }, + { + name = "CONTRIBUTING.md" + extension = "md" + description = "Contribution guidelines" + required = true + always_overwrite = true + template = "templates/docs/required/template-CONTRIBUTING.md" + audience = "contributor" + }, + { + name = "update.xml" + extension = "xml" + description = "Joomla extension update server manifest — lists releases for Joomla auto-update; must be kept in sync with manifest.xml version" + required = true + always_overwrite = false + audience = "developer" + template = "templates/joomla/update.xml.template" + stub_content = <<-MOKO_END + + + + {{EXTENSION_NAME}} + {{REPO_NAME}} — Moko Consulting Joomla extension + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + {{VERSION}} + {{REPO_URL}}/releases/tag/{{VERSION}} + + {{DOWNLOAD_URL}} + + + 7.4 + Moko Consulting + {{MAINTAINER_URL}} + + + MOKO_END + }, + { + name = "phpstan.neon" + extension = "neon" + description = "PHPStan static analysis config with Joomla framework class stubs" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/phpstan.joomla.neon" + }, + { + name = "Makefile" + description = "Build automation using MokoStandards templates" + required = true + always_overwrite = true + audience = "developer" + source_path = "templates/makefiles" + source_filename = "Makefile.joomla.template" + source_type = "template" + destination_path = "." + destination_filename = "Makefile" + create_path = false + template = "templates/makefiles/Makefile.joomla.template" + }, + { + name = ".gitignore" + extension = "gitignore" + description = "Git ignore patterns for Joomla development - preserved during sync operations" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/.gitignore.joomla" + validation_rules = [ + { + type = "content-pattern" + description = "Must contain sftp-config pattern to ignore SFTP sync configuration files" + pattern = "sftp-config" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.css pattern to ignore custom user CSS overrides" + pattern = "user\\.css" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.js pattern to ignore custom user JavaScript overrides" + pattern = "user\\.js" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain modulebuilder.txt pattern to ignore Joomla Module Builder artifacts" + pattern = "modulebuilder\\.txt" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain colors_custom.css pattern to ignore custom color scheme overrides" + pattern = "colors_custom\\.css" + severity = "error" + } + ] + }, + { + name = ".gitattributes" + extension = "gitattributes" + description = "Git attributes configuration" + required = true + audience = "developer" + }, + { + name = ".editorconfig" + extension = "editorconfig" + description = "Editor configuration for consistent coding style - preserved during sync" + required = true + always_overwrite = false + audience = "developer" + }, + { + name = "composer.json" + extension = "json" + description = "Composer manifest — requires mokoconsulting-tech/enterprise for CLI scripts and tooling" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/composer.joomla.json" + }, + { + name = ".mokostandards" + extension = "yml" + description = "MokoStandards governance attachment — links this repo back to the standards source" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/mokostandards.yml.template" + }, + { + name = "GOVERNANCE.md" + extension = "md" + description = "Project governance rules, roles, and decision process — auto-maintained by MokoStandards" + required = true + always_overwrite = false + protected = true + audience = "all" + template = "templates/docs/required/GOVERNANCE.md" + } + ] + + directories = [ + { + name = "site" + path = "site" + description = "Component frontend (site) code" + required = true + purpose = "Contains frontend component code deployed to site" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main site controller" + required = true + audience = "developer" + }, + { + name = "manifest.xml" + extension = "xml" + description = "Component manifest for site" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "site/controllers" + description = "Site controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "site/models" + description = "Site models" + requirement_status = "suggested" + }, + { + name = "views" + path = "site/views" + description = "Site views" + required = true + } + ] + }, + { + name = "admin" + path = "admin" + description = "Component backend (admin) code" + required = true + purpose = "Contains backend component code for administrator" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main admin controller" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "admin/controllers" + description = "Admin controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "admin/models" + description = "Admin models" + requirement_status = "suggested" + }, + { + name = "views" + path = "admin/views" + description = "Admin views" + required = true + }, + { + name = "sql" + path = "admin/sql" + description = "Database schema files" + requirement_status = "suggested" + } + ] + }, + { + name = "media" + path = "media" + description = "Media files (CSS, JS, images)" + requirement_status = "suggested" + purpose = "Contains static assets" + subdirectories = [ + { + name = "css" + path = "media/css" + description = "Stylesheets" + requirement_status = "suggested" + }, + { + name = "js" + path = "media/js" + description = "JavaScript files" + requirement_status = "suggested" + }, + { + name = "images" + path = "media/images" + description = "Image files" + requirement_status = "suggested" + } + ] + }, + { + name = "language" + path = "language" + description = "Language translation files" + required = true + purpose = "Contains language INI files" + }, + { + name = "docs" + path = "docs" + description = "Developer and technical documentation" + required = true + purpose = "Contains technical documentation, API docs, architecture diagrams" + files = [ + { + name = "index.md" + extension = "md" + description = "Documentation index" + required = true + }, + { + name = "update-server.md" + extension = "md" + description = "Joomla update server (update.xml) documentation" + required = true + always_overwrite = true + template = "templates/docs/required/template-update-server-joomla.md" + } + ] + }, + { + name = "scripts" + path = "scripts" + description = "Repo-specific scripts — not managed by MokoStandards sync" + required = false + purpose = "Optional directory for repo-specific build helpers and one-off scripts. MokoStandards tools are installed via Composer (mokoconsulting-tech/enterprise) and called through vendor/bin/." + files = [ + { + name = "MokoStandards.override.xml" + extension = "xml" + description = "MokoStandards sync override configuration - preserved during sync" + requirement_status = "optional" + always_overwrite = false + audience = "developer" + } + ] + }, + { + name = "tests" + path = "tests" + description = "Test files" + required = true + purpose = "Contains unit tests, integration tests, and test fixtures" + subdirectories = [ + { + name = "unit" + path = "tests/unit" + description = "Unit tests" + required = true + }, + { + name = "integration" + path = "tests/integration" + description = "Integration tests" + requirement_status = "suggested" + } + ] + }, + { + name = ".github" + path = ".github" + description = "GitHub-specific configuration" + requirement_status = "suggested" + purpose = "Contains GitHub Actions workflows and configuration" + files = [ + { + name = "copilot.yml" + extension = "yml" + description = "GitHub Copilot allowed domains configuration" + requirement_status = "required" + always_overwrite = true + template = ".github/copilot.yml" + }, + { + name = "copilot-instructions.md" + extension = "md" + description = "GitHub Copilot custom instructions enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "copilot-instructions.md" + template = "templates/github/copilot-instructions.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # {{REPO_NAME}} — GitHub Copilot Custom Instructions + + ## What This Repo Is + + This is a **Moko Consulting MokoWaaS** (Joomla) repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync. + + Repository URL: {{REPO_URL}} + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Platform: **Joomla 4.x / MokoWaaS** + + --- + + ## Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. JavaScript may be used for frontend enhancements. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + ## File Header — Always Required on New Files + + Every new file needs a copyright header as its first content. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /path/to/file.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown:** + ```markdown + + ``` + + **YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. JSON files are exempt. + + --- + + ## Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`. + - The `VERSION: XX.YY.ZZ` field in `README.md` governs all other version references. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. + + ```xml + + 01.02.04 + + + + + {{EXTENSION_NAME}} + 01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + + + + ``` + + --- + + ## Joomla Extension Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required, see below) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images (deployed to /media/{{EXTENSION_ELEMENT}}/) + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ + │ ├── copilot-instructions.md # This file + │ └── CLAUDE.md + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + ├── LICENSE # GPL-3.0-or-later + └── Makefile # Build automation + ``` + + --- + + ## update.xml — Required in Repo Root + + `update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. + + The `manifest.xml` must reference it via: + ```xml + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. + - The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. + - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). + - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. + + --- + + ## manifest.xml Rules + + - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). + - `` tag must be kept in sync with `README.md` version and `update.xml`. + - Must include `` block pointing to this repo's `update.xml`. + - Must include `` and `` sections. + - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. + + --- + + ## GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these in workflows + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + ## MokoStandards Reference + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies: + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + + --- + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `MyController` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + --- + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + --- + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + ## Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed manifest.xml | Update `update.xml` version; bump README.md version | + | New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + ## Key Constraints + + - Never commit directly to `main` — all changes go via PR, squash-merged + - Never skip the FILE INFORMATION block on a new file + - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files + - Never hardcode version numbers in body text — update `README.md` and let automation propagate + - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` + - Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync + MOKO_END + }, + { + name = "CLAUDE.md" + extension = "md" + description = "Claude AI assistant context enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "CLAUDE.md" + template = "templates/github/CLAUDE.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{REPO_DESCRIPTION}}` | First paragraph of `README.md` body, or the GitHub repo description | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # What This Repo Is + + **{{REPO_NAME}}** is a Moko Consulting **MokoWaaS** (Joomla) extension repository. + + {{REPO_DESCRIPTION}} + + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Repository URL: {{REPO_URL}} + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) — the single source of truth for coding standards, file-header policies, GitHub Actions workflows, and Terraform configuration templates across all Moko Consulting repositories. + + --- + + # Repo Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ # CI/CD workflows (synced from MokoStandards) + │ ├── copilot-instructions.md + │ └── CLAUDE.md # This file + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + └── LICENSE # GPL-3.0-or-later + ``` + + --- + + # Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + # Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it to all `FILE INFORMATION` headers automatically on merge. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a version number in body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + Three files must **always have the same version**: + + | File | Where the version lives | + |------|------------------------| + | `README.md` | `FILE INFORMATION` block + badge | + | `manifest.xml` | `` tag | + | `update.xml` | `` in the most recent `` block | + + The `make release` command / release workflow syncs all three automatically. + + --- + + # update.xml — Required in Repo Root + + `update.xml` is the Joomla update server manifest. It allows Joomla installations to check for new versions of this extension via: + + ```xml + + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release prepends a new `` block at the top — older entries are preserved. + - `` in `update.xml` must exactly match `` in `manifest.xml` and `README.md`. + - `` must be a publicly accessible GitHub Releases asset URL. + - `` — backslash is literal (Joomla regex syntax). + + Example `update.xml` entry for a new release: + ```xml + + + {{EXTENSION_NAME}} + {{REPO_NAME}} + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + 01.02.04 + {{REPO_URL}}/releases/tag/01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + 7.4 + Moko Consulting + https://mokoconsulting.tech + + + ``` + + --- + + # File Header Requirements + + Every new file **must** have a copyright header as its first content. JSON files, binary files, generated files, and third-party files are exempt. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /site/controllers/item.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of file purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown / YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. + + --- + + # Coding Standards + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `ItemModel` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + # GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + # Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed `manifest.xml` | Sync version to `update.xml` and `README.md` | + | New release | Prepend `` to `update.xml`; update `CHANGELOG.md`; bump `README.md` | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + # What NOT to Do + + - **Never commit directly to `main`** — all changes go through a PR. + - **Never hardcode version numbers** in body text — update `README.md` and let automation propagate. + - **Never let `manifest.xml`, `update.xml`, and `README.md` versions diverge.** + - **Never skip the FILE INFORMATION block** on a new source file. + - **Never use bare `catch (\Throwable $e) {}`** — always log or re-throw. + - **Never mix tabs and spaces** within a file — follow `.editorconfig`. + - **Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows** — always use `secrets.GH_TOKEN`. + - **Never remove `defined('_JEXEC') or die;`** from web-accessible PHP files. + + --- + + # PR Checklist + + Before opening a PR, verify: + + - [ ] Patch version bumped in `README.md` (e.g. `01.02.03` → `01.02.04`) + - [ ] If this is a release: `manifest.xml` version updated; `update.xml` updated with new entry + - [ ] FILE INFORMATION headers updated in modified files + - [ ] CHANGELOG.md updated + - [ ] Tests pass + + --- + + # Key Policy Documents (MokoStandards) + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + MOKO_END + } + ] + subdirectories = [ + { + name = "workflows" + path = ".github/workflows" + description = "GitHub Actions workflows" + requirement_status = "required" + files = [ + { + name = "ci-joomla.yml" + extension = "yml" + description = "Joomla-specific CI workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/ci-joomla.yml.template" + }, + { + name = "codeql-analysis.yml" + extension = "yml" + description = "CodeQL security analysis workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/generic/codeql-analysis.yml.template" + }, + { + name = "standards-compliance.yml" + extension = "yml" + description = "MokoStandards compliance validation" + requirement_status = "required" + always_overwrite = true + template = ".github/workflows/standards-compliance.yml" + }, + { + name = "enterprise-firewall-setup.yml" + extension = "yml" + description = "Enterprise firewall configuration for trusted domain access" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/enterprise-firewall-setup.yml.template" + }, + { + name = "deploy-dev.yml" + extension = "yml" + description = "SFTP deployment of src/ to the development server" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-dev.yml.template" + }, + { + name = "deploy-demo.yml" + extension = "yml" + description = "SFTP deployment of src/ to the demo server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-demo.yml.template" + }, + { + name = "deploy-rs.yml" + extension = "yml" + description = "SFTP deployment of src/ to the release staging server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-rs.yml.template" + }, + { + name = "sync-version-on-merge.yml" + extension = "yml" + description = "Auto-bump patch version on merge and propagate to all file headers" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/sync-version-on-merge.yml.template" + }, + { + name = "auto-release.yml" + extension = "yml" + description = "Auto-create GitHub Release on push to main with version from README.md" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-release.yml.template" + }, + { + name = "repository-cleanup.yml" + extension = "yml" + description = "Scheduled cleanup: delete retired workflows, stale branches, old workflow runs" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/repository-cleanup.yml.template" + }, + { + name = "auto-dev-issue.yml" + extension = "yml" + description = "Auto-create tracking issue when a dev/** branch is pushed" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-dev-issue.yml.template" + }, + { + name = "repo_health.yml" + extension = "yml" + description = "Joomla-specific repository health check workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/repo_health.yml.template" + } + ] + }, + { + name = "ISSUE_TEMPLATE" + path = ".github/ISSUE_TEMPLATE" + description = "GitHub issue templates synced from MokoStandards" + requirement_status = "required" + files = [ + { + name = "config.yml" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/config.yml" + }, + { + name = "adr.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/adr.md" + }, + { + name = "bug_report.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/bug_report.md" + }, + { + name = "documentation.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/documentation.md" + }, + { + name = "enterprise_support.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/enterprise_support.md" + }, + { + name = "feature_request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/feature_request.md" + }, + { + name = "firewall-request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/firewall-request.md" + }, + { + name = "question.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/question.md" + }, + { + name = "request-license.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/request-license.md" + }, + { + name = "rfc.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/rfc.md" + }, + { + name = "security.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/security.md" + }, + { + name = "joomla_issue.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/joomla_issue.md" + } + ] + } + ] + } + ] + + repository_requirements = { + secrets = [ + { + name = "GH_TOKEN" + description = "Org-level GitHub PAT for automation" + required = true + scope = "org" + }, + { + name = "DEV_FTP_KEY" + description = "SSH private key for SFTP dev deployment (preferred); if DEV_FTP_PASSWORD is also set it is used as the key passphrase, with password-only as fallback" + required = false + scope = "org" + }, + { + name = "DEV_FTP_PASSWORD" + description = "SFTP password for dev deployment; used as SSH key passphrase when DEV_FTP_KEY is also set, and as standalone fallback if key auth fails" + required = false + scope = "org" + note = "At least one of DEV_FTP_KEY or DEV_FTP_PASSWORD must be configured" + } + ] + + variables = [ + { + name = "DEV_FTP_HOST" + description = "Dev server hostname; may include port suffix (e.g. dev.example.com or dev.example.com:2222)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PATH" + description = "Base remote path for SFTP deployment (e.g. /var/www/html)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_USERNAME" + description = "SFTP username for dev server authentication" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PORT" + description = "Explicit SFTP port override; if omitted the port is parsed from DEV_FTP_HOST or defaults to 22" + required = false + scope = "org" + }, + { + name = "DEV_FTP_SUFFIX" + description = "Per-repo path suffix appended to DEV_FTP_PATH (e.g. /my-extension)" + required = false + scope = "repo" + } + ] + } + } +} diff --git a/definitions/sync/MokoStandards-Template-Joomla-Package.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Package.def.tf new file mode 100644 index 0000000..9ce6e81 --- /dev/null +++ b/definitions/sync/MokoStandards-Template-Joomla-Package.def.tf @@ -0,0 +1,1335 @@ +/** + * Repository Sync Tracking Definition: mokoconsulting-tech/MokoStandards-Template-Joomla-Package + * + * Auto-generated by MokoStandards bulk sync on 2026-04-02T15:30:39+00:00 + * Platform : waas-component + * Description: A repo template for a Joomla Package coding project according to MokoStandards + * + * DO NOT EDIT MANUALLY — this file is regenerated on every successful sync. + * To change what gets synced, edit api/definitions/default/waas-component.tf + * and re-run the bulk-repo-sync workflow. + */ + +locals { + sync_record = { + metadata = { + repo = "mokoconsulting-tech/MokoStandards-Template-Joomla-Package" + default_branch = "main" + detected_platform = "waas-component" + description = "A repo template for a Joomla Package coding project according to MokoStandards" + sync_timestamp = "2026-04-02T15:30:39+00:00" + source_repo = "mokoconsulting-tech/MokoStandards" + base_definition = "api/definitions/default/waas-component.tf" + } + + sync_stats = { + total_files = 41 + created_files = 3 + updated_files = 35 + skipped_files = 3 + } + + synced_files = [ + { path = "LICENSE" action = "updated" }, + { path = "SECURITY.md" action = "updated" }, + { path = "CODE_OF_CONDUCT.md" action = "updated" }, + { path = "CONTRIBUTING.md" action = "updated" }, + { path = "update.xml" action = "updated" }, + { path = "phpstan.neon" action = "updated" }, + { path = "Makefile" action = "updated" }, + { path = ".gitignore" action = "updated" }, + { path = "composer.json" action = "updated" }, + { path = ".mokostandards" action = "created" }, + { path = "docs/update-server.md" action = "created" }, + { path = ".github/copilot.yml" action = "updated" }, + { path = ".github/copilot-instructions.md" action = "updated" }, + { path = ".github/CLAUDE.md" action = "updated" }, + { path = ".github/workflows/codeql-analysis.yml" action = "updated" }, + { path = ".github/workflows/standards-compliance.yml" action = "updated" }, + { path = ".github/workflows/enterprise-firewall-setup.yml" action = "updated" }, + { path = ".github/workflows/deploy-dev.yml" action = "updated" }, + { path = ".github/workflows/deploy-demo.yml" action = "updated" }, + { path = ".github/workflows/deploy-rs.yml" action = "updated" }, + { path = ".github/workflows/sync-version-on-merge.yml" action = "updated" }, + { path = ".github/workflows/auto-release.yml" action = "updated" }, + { path = ".github/workflows/repository-cleanup.yml" action = "updated" }, + { path = ".github/workflows/auto-dev-issue.yml" action = "updated" }, + { path = ".github/workflows/repo_health.yml" action = "created" }, + { path = ".github/ISSUE_TEMPLATE/config.yml" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/adr.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/bug_report.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/documentation.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/enterprise_support.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/feature_request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/firewall-request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/question.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/request-license.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/rfc.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/security.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/joomla_issue.md" action = "updated" }, + { path = ".github/CODEOWNERS" action = "updated" }, + { path = ".github/.mokostandards" action = "migrated from root" }, + ] + + skipped_files = [ + { path = "GOVERNANCE.md" reason = "Preserved (always_overwrite=false)" }, + { path = ".github/workflows/ci-joomla.yml" reason = "Source file not found" }, + { path = ".github/workflows/custom/README.md" reason = "README — never overwritten" }, + ] + } +} + +# ---- Base platform definition (reference copy) ---- +/** + * MokoWaaS Component Structure Definition + * Standard repository structure for MokoWaaS (Joomla) components + * + * Copyright (C) 2026 Moko Consulting + * SPDX-License-Identifier: GPL-3.0-or-later + * Version: 05.00.00 + * Schema Version: 1.0 + */ + +locals { + repository_structure = { + metadata = { + name = "MokoWaaS Component" + description = "Standard repository structure for MokoWaaS (Joomla) components" + repository_type = "waas-component" + platform = "mokowaas" + last_updated = "2026-01-15T00:00:00Z" + maintainer = "Moko Consulting" + version = "05.00.00" + schema_version = "1.0" + } + + root_files = [ + { + name = "README.md" + extension = "md" + description = "Developer-focused documentation for contributors and maintainers" + required = true + always_overwrite = false + protected = true + audience = "developer" + }, + { + name = "LICENSE" + extension = "" + description = "License file (GPL-3.0-or-later) - Default for Joomla/WaaS components" + required = true + audience = "general" + template = "templates/licenses/GPL-3.0" + license_type = "GPL-3.0-or-later" + }, + { + name = "CHANGELOG.md" + extension = "md" + description = "Version history and changes" + required = true + audience = "general" + }, + { + name = "SECURITY.md" + extension = "md" + description = "Security policy and vulnerability reporting" + required = true + always_overwrite = true + template = "templates/docs/required/template-SECURITY.md" + audience = "general" + }, + { + name = "CODE_OF_CONDUCT.md" + extension = "md" + description = "Community code of conduct" + required = true + always_overwrite = true + template = "templates/docs/extra/template-CODE_OF_CONDUCT.md" + always_overwrite = true + audience = "contributor" + }, + { + name = "ROADMAP.md" + extension = "md" + description = "Project roadmap with version goals and milestones" + required = false + audience = "general" + }, + { + name = "CONTRIBUTING.md" + extension = "md" + description = "Contribution guidelines" + required = true + always_overwrite = true + template = "templates/docs/required/template-CONTRIBUTING.md" + audience = "contributor" + }, + { + name = "update.xml" + extension = "xml" + description = "Joomla extension update server manifest — lists releases for Joomla auto-update; must be kept in sync with manifest.xml version" + required = true + always_overwrite = false + audience = "developer" + template = "templates/joomla/update.xml.template" + stub_content = <<-MOKO_END + + + + {{EXTENSION_NAME}} + {{REPO_NAME}} — Moko Consulting Joomla extension + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + {{VERSION}} + {{REPO_URL}}/releases/tag/{{VERSION}} + + {{DOWNLOAD_URL}} + + + 7.4 + Moko Consulting + {{MAINTAINER_URL}} + + + MOKO_END + }, + { + name = "phpstan.neon" + extension = "neon" + description = "PHPStan static analysis config with Joomla framework class stubs" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/phpstan.joomla.neon" + }, + { + name = "Makefile" + description = "Build automation using MokoStandards templates" + required = true + always_overwrite = true + audience = "developer" + source_path = "templates/makefiles" + source_filename = "Makefile.joomla.template" + source_type = "template" + destination_path = "." + destination_filename = "Makefile" + create_path = false + template = "templates/makefiles/Makefile.joomla.template" + }, + { + name = ".gitignore" + extension = "gitignore" + description = "Git ignore patterns for Joomla development - preserved during sync operations" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/.gitignore.joomla" + validation_rules = [ + { + type = "content-pattern" + description = "Must contain sftp-config pattern to ignore SFTP sync configuration files" + pattern = "sftp-config" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.css pattern to ignore custom user CSS overrides" + pattern = "user\\.css" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.js pattern to ignore custom user JavaScript overrides" + pattern = "user\\.js" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain modulebuilder.txt pattern to ignore Joomla Module Builder artifacts" + pattern = "modulebuilder\\.txt" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain colors_custom.css pattern to ignore custom color scheme overrides" + pattern = "colors_custom\\.css" + severity = "error" + } + ] + }, + { + name = ".gitattributes" + extension = "gitattributes" + description = "Git attributes configuration" + required = true + audience = "developer" + }, + { + name = ".editorconfig" + extension = "editorconfig" + description = "Editor configuration for consistent coding style - preserved during sync" + required = true + always_overwrite = false + audience = "developer" + }, + { + name = "composer.json" + extension = "json" + description = "Composer manifest — requires mokoconsulting-tech/enterprise for CLI scripts and tooling" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/composer.joomla.json" + }, + { + name = ".mokostandards" + extension = "yml" + description = "MokoStandards governance attachment — links this repo back to the standards source" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/mokostandards.yml.template" + }, + { + name = "GOVERNANCE.md" + extension = "md" + description = "Project governance rules, roles, and decision process — auto-maintained by MokoStandards" + required = true + always_overwrite = false + protected = true + audience = "all" + template = "templates/docs/required/GOVERNANCE.md" + } + ] + + directories = [ + { + name = "site" + path = "site" + description = "Component frontend (site) code" + required = true + purpose = "Contains frontend component code deployed to site" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main site controller" + required = true + audience = "developer" + }, + { + name = "manifest.xml" + extension = "xml" + description = "Component manifest for site" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "site/controllers" + description = "Site controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "site/models" + description = "Site models" + requirement_status = "suggested" + }, + { + name = "views" + path = "site/views" + description = "Site views" + required = true + } + ] + }, + { + name = "admin" + path = "admin" + description = "Component backend (admin) code" + required = true + purpose = "Contains backend component code for administrator" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main admin controller" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "admin/controllers" + description = "Admin controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "admin/models" + description = "Admin models" + requirement_status = "suggested" + }, + { + name = "views" + path = "admin/views" + description = "Admin views" + required = true + }, + { + name = "sql" + path = "admin/sql" + description = "Database schema files" + requirement_status = "suggested" + } + ] + }, + { + name = "media" + path = "media" + description = "Media files (CSS, JS, images)" + requirement_status = "suggested" + purpose = "Contains static assets" + subdirectories = [ + { + name = "css" + path = "media/css" + description = "Stylesheets" + requirement_status = "suggested" + }, + { + name = "js" + path = "media/js" + description = "JavaScript files" + requirement_status = "suggested" + }, + { + name = "images" + path = "media/images" + description = "Image files" + requirement_status = "suggested" + } + ] + }, + { + name = "language" + path = "language" + description = "Language translation files" + required = true + purpose = "Contains language INI files" + }, + { + name = "docs" + path = "docs" + description = "Developer and technical documentation" + required = true + purpose = "Contains technical documentation, API docs, architecture diagrams" + files = [ + { + name = "index.md" + extension = "md" + description = "Documentation index" + required = true + }, + { + name = "update-server.md" + extension = "md" + description = "Joomla update server (update.xml) documentation" + required = true + always_overwrite = true + template = "templates/docs/required/template-update-server-joomla.md" + } + ] + }, + { + name = "scripts" + path = "scripts" + description = "Repo-specific scripts — not managed by MokoStandards sync" + required = false + purpose = "Optional directory for repo-specific build helpers and one-off scripts. MokoStandards tools are installed via Composer (mokoconsulting-tech/enterprise) and called through vendor/bin/." + files = [ + { + name = "MokoStandards.override.xml" + extension = "xml" + description = "MokoStandards sync override configuration - preserved during sync" + requirement_status = "optional" + always_overwrite = false + audience = "developer" + } + ] + }, + { + name = "tests" + path = "tests" + description = "Test files" + required = true + purpose = "Contains unit tests, integration tests, and test fixtures" + subdirectories = [ + { + name = "unit" + path = "tests/unit" + description = "Unit tests" + required = true + }, + { + name = "integration" + path = "tests/integration" + description = "Integration tests" + requirement_status = "suggested" + } + ] + }, + { + name = ".github" + path = ".github" + description = "GitHub-specific configuration" + requirement_status = "suggested" + purpose = "Contains GitHub Actions workflows and configuration" + files = [ + { + name = "copilot.yml" + extension = "yml" + description = "GitHub Copilot allowed domains configuration" + requirement_status = "required" + always_overwrite = true + template = ".github/copilot.yml" + }, + { + name = "copilot-instructions.md" + extension = "md" + description = "GitHub Copilot custom instructions enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "copilot-instructions.md" + template = "templates/github/copilot-instructions.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # {{REPO_NAME}} — GitHub Copilot Custom Instructions + + ## What This Repo Is + + This is a **Moko Consulting MokoWaaS** (Joomla) repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync. + + Repository URL: {{REPO_URL}} + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Platform: **Joomla 4.x / MokoWaaS** + + --- + + ## Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. JavaScript may be used for frontend enhancements. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + ## File Header — Always Required on New Files + + Every new file needs a copyright header as its first content. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /path/to/file.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown:** + ```markdown + + ``` + + **YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. JSON files are exempt. + + --- + + ## Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`. + - The `VERSION: XX.YY.ZZ` field in `README.md` governs all other version references. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. + + ```xml + + 01.02.04 + + + + + {{EXTENSION_NAME}} + 01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + + + + ``` + + --- + + ## Joomla Extension Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required, see below) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images (deployed to /media/{{EXTENSION_ELEMENT}}/) + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ + │ ├── copilot-instructions.md # This file + │ └── CLAUDE.md + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + ├── LICENSE # GPL-3.0-or-later + └── Makefile # Build automation + ``` + + --- + + ## update.xml — Required in Repo Root + + `update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. + + The `manifest.xml` must reference it via: + ```xml + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. + - The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. + - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). + - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. + + --- + + ## manifest.xml Rules + + - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). + - `` tag must be kept in sync with `README.md` version and `update.xml`. + - Must include `` block pointing to this repo's `update.xml`. + - Must include `` and `` sections. + - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. + + --- + + ## GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these in workflows + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + ## MokoStandards Reference + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies: + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + + --- + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `MyController` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + --- + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + --- + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + ## Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed manifest.xml | Update `update.xml` version; bump README.md version | + | New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + ## Key Constraints + + - Never commit directly to `main` — all changes go via PR, squash-merged + - Never skip the FILE INFORMATION block on a new file + - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files + - Never hardcode version numbers in body text — update `README.md` and let automation propagate + - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` + - Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync + MOKO_END + }, + { + name = "CLAUDE.md" + extension = "md" + description = "Claude AI assistant context enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "CLAUDE.md" + template = "templates/github/CLAUDE.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{REPO_DESCRIPTION}}` | First paragraph of `README.md` body, or the GitHub repo description | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # What This Repo Is + + **{{REPO_NAME}}** is a Moko Consulting **MokoWaaS** (Joomla) extension repository. + + {{REPO_DESCRIPTION}} + + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Repository URL: {{REPO_URL}} + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) — the single source of truth for coding standards, file-header policies, GitHub Actions workflows, and Terraform configuration templates across all Moko Consulting repositories. + + --- + + # Repo Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ # CI/CD workflows (synced from MokoStandards) + │ ├── copilot-instructions.md + │ └── CLAUDE.md # This file + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + └── LICENSE # GPL-3.0-or-later + ``` + + --- + + # Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + # Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it to all `FILE INFORMATION` headers automatically on merge. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a version number in body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + Three files must **always have the same version**: + + | File | Where the version lives | + |------|------------------------| + | `README.md` | `FILE INFORMATION` block + badge | + | `manifest.xml` | `` tag | + | `update.xml` | `` in the most recent `` block | + + The `make release` command / release workflow syncs all three automatically. + + --- + + # update.xml — Required in Repo Root + + `update.xml` is the Joomla update server manifest. It allows Joomla installations to check for new versions of this extension via: + + ```xml + + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release prepends a new `` block at the top — older entries are preserved. + - `` in `update.xml` must exactly match `` in `manifest.xml` and `README.md`. + - `` must be a publicly accessible GitHub Releases asset URL. + - `` — backslash is literal (Joomla regex syntax). + + Example `update.xml` entry for a new release: + ```xml + + + {{EXTENSION_NAME}} + {{REPO_NAME}} + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + 01.02.04 + {{REPO_URL}}/releases/tag/01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + 7.4 + Moko Consulting + https://mokoconsulting.tech + + + ``` + + --- + + # File Header Requirements + + Every new file **must** have a copyright header as its first content. JSON files, binary files, generated files, and third-party files are exempt. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /site/controllers/item.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of file purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown / YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. + + --- + + # Coding Standards + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `ItemModel` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + # GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + # Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed `manifest.xml` | Sync version to `update.xml` and `README.md` | + | New release | Prepend `` to `update.xml`; update `CHANGELOG.md`; bump `README.md` | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + # What NOT to Do + + - **Never commit directly to `main`** — all changes go through a PR. + - **Never hardcode version numbers** in body text — update `README.md` and let automation propagate. + - **Never let `manifest.xml`, `update.xml`, and `README.md` versions diverge.** + - **Never skip the FILE INFORMATION block** on a new source file. + - **Never use bare `catch (\Throwable $e) {}`** — always log or re-throw. + - **Never mix tabs and spaces** within a file — follow `.editorconfig`. + - **Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows** — always use `secrets.GH_TOKEN`. + - **Never remove `defined('_JEXEC') or die;`** from web-accessible PHP files. + + --- + + # PR Checklist + + Before opening a PR, verify: + + - [ ] Patch version bumped in `README.md` (e.g. `01.02.03` → `01.02.04`) + - [ ] If this is a release: `manifest.xml` version updated; `update.xml` updated with new entry + - [ ] FILE INFORMATION headers updated in modified files + - [ ] CHANGELOG.md updated + - [ ] Tests pass + + --- + + # Key Policy Documents (MokoStandards) + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + MOKO_END + } + ] + subdirectories = [ + { + name = "workflows" + path = ".github/workflows" + description = "GitHub Actions workflows" + requirement_status = "required" + files = [ + { + name = "ci-joomla.yml" + extension = "yml" + description = "Joomla-specific CI workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/ci-joomla.yml.template" + }, + { + name = "codeql-analysis.yml" + extension = "yml" + description = "CodeQL security analysis workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/generic/codeql-analysis.yml.template" + }, + { + name = "standards-compliance.yml" + extension = "yml" + description = "MokoStandards compliance validation" + requirement_status = "required" + always_overwrite = true + template = ".github/workflows/standards-compliance.yml" + }, + { + name = "enterprise-firewall-setup.yml" + extension = "yml" + description = "Enterprise firewall configuration for trusted domain access" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/enterprise-firewall-setup.yml.template" + }, + { + name = "deploy-dev.yml" + extension = "yml" + description = "SFTP deployment of src/ to the development server" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-dev.yml.template" + }, + { + name = "deploy-demo.yml" + extension = "yml" + description = "SFTP deployment of src/ to the demo server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-demo.yml.template" + }, + { + name = "deploy-rs.yml" + extension = "yml" + description = "SFTP deployment of src/ to the release staging server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-rs.yml.template" + }, + { + name = "sync-version-on-merge.yml" + extension = "yml" + description = "Auto-bump patch version on merge and propagate to all file headers" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/sync-version-on-merge.yml.template" + }, + { + name = "auto-release.yml" + extension = "yml" + description = "Auto-create GitHub Release on push to main with version from README.md" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-release.yml.template" + }, + { + name = "repository-cleanup.yml" + extension = "yml" + description = "Scheduled cleanup: delete retired workflows, stale branches, old workflow runs" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/repository-cleanup.yml.template" + }, + { + name = "auto-dev-issue.yml" + extension = "yml" + description = "Auto-create tracking issue when a dev/** branch is pushed" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-dev-issue.yml.template" + }, + { + name = "repo_health.yml" + extension = "yml" + description = "Joomla-specific repository health check workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/repo_health.yml.template" + } + ] + }, + { + name = "ISSUE_TEMPLATE" + path = ".github/ISSUE_TEMPLATE" + description = "GitHub issue templates synced from MokoStandards" + requirement_status = "required" + files = [ + { + name = "config.yml" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/config.yml" + }, + { + name = "adr.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/adr.md" + }, + { + name = "bug_report.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/bug_report.md" + }, + { + name = "documentation.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/documentation.md" + }, + { + name = "enterprise_support.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/enterprise_support.md" + }, + { + name = "feature_request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/feature_request.md" + }, + { + name = "firewall-request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/firewall-request.md" + }, + { + name = "question.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/question.md" + }, + { + name = "request-license.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/request-license.md" + }, + { + name = "rfc.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/rfc.md" + }, + { + name = "security.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/security.md" + }, + { + name = "joomla_issue.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/joomla_issue.md" + } + ] + } + ] + } + ] + + repository_requirements = { + secrets = [ + { + name = "GH_TOKEN" + description = "Org-level GitHub PAT for automation" + required = true + scope = "org" + }, + { + name = "DEV_FTP_KEY" + description = "SSH private key for SFTP dev deployment (preferred); if DEV_FTP_PASSWORD is also set it is used as the key passphrase, with password-only as fallback" + required = false + scope = "org" + }, + { + name = "DEV_FTP_PASSWORD" + description = "SFTP password for dev deployment; used as SSH key passphrase when DEV_FTP_KEY is also set, and as standalone fallback if key auth fails" + required = false + scope = "org" + note = "At least one of DEV_FTP_KEY or DEV_FTP_PASSWORD must be configured" + } + ] + + variables = [ + { + name = "DEV_FTP_HOST" + description = "Dev server hostname; may include port suffix (e.g. dev.example.com or dev.example.com:2222)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PATH" + description = "Base remote path for SFTP deployment (e.g. /var/www/html)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_USERNAME" + description = "SFTP username for dev server authentication" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PORT" + description = "Explicit SFTP port override; if omitted the port is parsed from DEV_FTP_HOST or defaults to 22" + required = false + scope = "org" + }, + { + name = "DEV_FTP_SUFFIX" + description = "Per-repo path suffix appended to DEV_FTP_PATH (e.g. /my-extension)" + required = false + scope = "repo" + } + ] + } + } +} diff --git a/definitions/sync/MokoStandards-Template-Joomla-Plugin.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Plugin.def.tf new file mode 100644 index 0000000..71c6a40 --- /dev/null +++ b/definitions/sync/MokoStandards-Template-Joomla-Plugin.def.tf @@ -0,0 +1,1335 @@ +/** + * Repository Sync Tracking Definition: mokoconsulting-tech/MokoStandards-Template-Joomla-Plugin + * + * Auto-generated by MokoStandards bulk sync on 2026-04-02T15:31:55+00:00 + * Platform : waas-component + * Description: A repo template for a Joomla Plugin coding project according to MokoStandards + * + * DO NOT EDIT MANUALLY — this file is regenerated on every successful sync. + * To change what gets synced, edit api/definitions/default/waas-component.tf + * and re-run the bulk-repo-sync workflow. + */ + +locals { + sync_record = { + metadata = { + repo = "mokoconsulting-tech/MokoStandards-Template-Joomla-Plugin" + default_branch = "main" + detected_platform = "waas-component" + description = "A repo template for a Joomla Plugin coding project according to MokoStandards" + sync_timestamp = "2026-04-02T15:31:55+00:00" + source_repo = "mokoconsulting-tech/MokoStandards" + base_definition = "api/definitions/default/waas-component.tf" + } + + sync_stats = { + total_files = 41 + created_files = 3 + updated_files = 35 + skipped_files = 3 + } + + synced_files = [ + { path = "LICENSE" action = "updated" }, + { path = "SECURITY.md" action = "updated" }, + { path = "CODE_OF_CONDUCT.md" action = "updated" }, + { path = "CONTRIBUTING.md" action = "updated" }, + { path = "update.xml" action = "updated" }, + { path = "phpstan.neon" action = "updated" }, + { path = "Makefile" action = "updated" }, + { path = ".gitignore" action = "updated" }, + { path = "composer.json" action = "updated" }, + { path = ".mokostandards" action = "created" }, + { path = "docs/update-server.md" action = "created" }, + { path = ".github/copilot.yml" action = "updated" }, + { path = ".github/copilot-instructions.md" action = "updated" }, + { path = ".github/CLAUDE.md" action = "updated" }, + { path = ".github/workflows/codeql-analysis.yml" action = "updated" }, + { path = ".github/workflows/standards-compliance.yml" action = "updated" }, + { path = ".github/workflows/enterprise-firewall-setup.yml" action = "updated" }, + { path = ".github/workflows/deploy-dev.yml" action = "updated" }, + { path = ".github/workflows/deploy-demo.yml" action = "updated" }, + { path = ".github/workflows/deploy-rs.yml" action = "updated" }, + { path = ".github/workflows/sync-version-on-merge.yml" action = "updated" }, + { path = ".github/workflows/auto-release.yml" action = "updated" }, + { path = ".github/workflows/repository-cleanup.yml" action = "updated" }, + { path = ".github/workflows/auto-dev-issue.yml" action = "updated" }, + { path = ".github/workflows/repo_health.yml" action = "created" }, + { path = ".github/ISSUE_TEMPLATE/config.yml" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/adr.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/bug_report.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/documentation.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/enterprise_support.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/feature_request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/firewall-request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/question.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/request-license.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/rfc.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/security.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/joomla_issue.md" action = "updated" }, + { path = ".github/CODEOWNERS" action = "updated" }, + { path = ".github/.mokostandards" action = "migrated from root" }, + ] + + skipped_files = [ + { path = "GOVERNANCE.md" reason = "Preserved (always_overwrite=false)" }, + { path = ".github/workflows/ci-joomla.yml" reason = "Source file not found" }, + { path = ".github/workflows/custom/README.md" reason = "README — never overwritten" }, + ] + } +} + +# ---- Base platform definition (reference copy) ---- +/** + * MokoWaaS Component Structure Definition + * Standard repository structure for MokoWaaS (Joomla) components + * + * Copyright (C) 2026 Moko Consulting + * SPDX-License-Identifier: GPL-3.0-or-later + * Version: 05.00.00 + * Schema Version: 1.0 + */ + +locals { + repository_structure = { + metadata = { + name = "MokoWaaS Component" + description = "Standard repository structure for MokoWaaS (Joomla) components" + repository_type = "waas-component" + platform = "mokowaas" + last_updated = "2026-01-15T00:00:00Z" + maintainer = "Moko Consulting" + version = "05.00.00" + schema_version = "1.0" + } + + root_files = [ + { + name = "README.md" + extension = "md" + description = "Developer-focused documentation for contributors and maintainers" + required = true + always_overwrite = false + protected = true + audience = "developer" + }, + { + name = "LICENSE" + extension = "" + description = "License file (GPL-3.0-or-later) - Default for Joomla/WaaS components" + required = true + audience = "general" + template = "templates/licenses/GPL-3.0" + license_type = "GPL-3.0-or-later" + }, + { + name = "CHANGELOG.md" + extension = "md" + description = "Version history and changes" + required = true + audience = "general" + }, + { + name = "SECURITY.md" + extension = "md" + description = "Security policy and vulnerability reporting" + required = true + always_overwrite = true + template = "templates/docs/required/template-SECURITY.md" + audience = "general" + }, + { + name = "CODE_OF_CONDUCT.md" + extension = "md" + description = "Community code of conduct" + required = true + always_overwrite = true + template = "templates/docs/extra/template-CODE_OF_CONDUCT.md" + always_overwrite = true + audience = "contributor" + }, + { + name = "ROADMAP.md" + extension = "md" + description = "Project roadmap with version goals and milestones" + required = false + audience = "general" + }, + { + name = "CONTRIBUTING.md" + extension = "md" + description = "Contribution guidelines" + required = true + always_overwrite = true + template = "templates/docs/required/template-CONTRIBUTING.md" + audience = "contributor" + }, + { + name = "update.xml" + extension = "xml" + description = "Joomla extension update server manifest — lists releases for Joomla auto-update; must be kept in sync with manifest.xml version" + required = true + always_overwrite = false + audience = "developer" + template = "templates/joomla/update.xml.template" + stub_content = <<-MOKO_END + + + + {{EXTENSION_NAME}} + {{REPO_NAME}} — Moko Consulting Joomla extension + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + {{VERSION}} + {{REPO_URL}}/releases/tag/{{VERSION}} + + {{DOWNLOAD_URL}} + + + 7.4 + Moko Consulting + {{MAINTAINER_URL}} + + + MOKO_END + }, + { + name = "phpstan.neon" + extension = "neon" + description = "PHPStan static analysis config with Joomla framework class stubs" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/phpstan.joomla.neon" + }, + { + name = "Makefile" + description = "Build automation using MokoStandards templates" + required = true + always_overwrite = true + audience = "developer" + source_path = "templates/makefiles" + source_filename = "Makefile.joomla.template" + source_type = "template" + destination_path = "." + destination_filename = "Makefile" + create_path = false + template = "templates/makefiles/Makefile.joomla.template" + }, + { + name = ".gitignore" + extension = "gitignore" + description = "Git ignore patterns for Joomla development - preserved during sync operations" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/.gitignore.joomla" + validation_rules = [ + { + type = "content-pattern" + description = "Must contain sftp-config pattern to ignore SFTP sync configuration files" + pattern = "sftp-config" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.css pattern to ignore custom user CSS overrides" + pattern = "user\\.css" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.js pattern to ignore custom user JavaScript overrides" + pattern = "user\\.js" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain modulebuilder.txt pattern to ignore Joomla Module Builder artifacts" + pattern = "modulebuilder\\.txt" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain colors_custom.css pattern to ignore custom color scheme overrides" + pattern = "colors_custom\\.css" + severity = "error" + } + ] + }, + { + name = ".gitattributes" + extension = "gitattributes" + description = "Git attributes configuration" + required = true + audience = "developer" + }, + { + name = ".editorconfig" + extension = "editorconfig" + description = "Editor configuration for consistent coding style - preserved during sync" + required = true + always_overwrite = false + audience = "developer" + }, + { + name = "composer.json" + extension = "json" + description = "Composer manifest — requires mokoconsulting-tech/enterprise for CLI scripts and tooling" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/composer.joomla.json" + }, + { + name = ".mokostandards" + extension = "yml" + description = "MokoStandards governance attachment — links this repo back to the standards source" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/mokostandards.yml.template" + }, + { + name = "GOVERNANCE.md" + extension = "md" + description = "Project governance rules, roles, and decision process — auto-maintained by MokoStandards" + required = true + always_overwrite = false + protected = true + audience = "all" + template = "templates/docs/required/GOVERNANCE.md" + } + ] + + directories = [ + { + name = "site" + path = "site" + description = "Component frontend (site) code" + required = true + purpose = "Contains frontend component code deployed to site" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main site controller" + required = true + audience = "developer" + }, + { + name = "manifest.xml" + extension = "xml" + description = "Component manifest for site" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "site/controllers" + description = "Site controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "site/models" + description = "Site models" + requirement_status = "suggested" + }, + { + name = "views" + path = "site/views" + description = "Site views" + required = true + } + ] + }, + { + name = "admin" + path = "admin" + description = "Component backend (admin) code" + required = true + purpose = "Contains backend component code for administrator" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main admin controller" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "admin/controllers" + description = "Admin controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "admin/models" + description = "Admin models" + requirement_status = "suggested" + }, + { + name = "views" + path = "admin/views" + description = "Admin views" + required = true + }, + { + name = "sql" + path = "admin/sql" + description = "Database schema files" + requirement_status = "suggested" + } + ] + }, + { + name = "media" + path = "media" + description = "Media files (CSS, JS, images)" + requirement_status = "suggested" + purpose = "Contains static assets" + subdirectories = [ + { + name = "css" + path = "media/css" + description = "Stylesheets" + requirement_status = "suggested" + }, + { + name = "js" + path = "media/js" + description = "JavaScript files" + requirement_status = "suggested" + }, + { + name = "images" + path = "media/images" + description = "Image files" + requirement_status = "suggested" + } + ] + }, + { + name = "language" + path = "language" + description = "Language translation files" + required = true + purpose = "Contains language INI files" + }, + { + name = "docs" + path = "docs" + description = "Developer and technical documentation" + required = true + purpose = "Contains technical documentation, API docs, architecture diagrams" + files = [ + { + name = "index.md" + extension = "md" + description = "Documentation index" + required = true + }, + { + name = "update-server.md" + extension = "md" + description = "Joomla update server (update.xml) documentation" + required = true + always_overwrite = true + template = "templates/docs/required/template-update-server-joomla.md" + } + ] + }, + { + name = "scripts" + path = "scripts" + description = "Repo-specific scripts — not managed by MokoStandards sync" + required = false + purpose = "Optional directory for repo-specific build helpers and one-off scripts. MokoStandards tools are installed via Composer (mokoconsulting-tech/enterprise) and called through vendor/bin/." + files = [ + { + name = "MokoStandards.override.xml" + extension = "xml" + description = "MokoStandards sync override configuration - preserved during sync" + requirement_status = "optional" + always_overwrite = false + audience = "developer" + } + ] + }, + { + name = "tests" + path = "tests" + description = "Test files" + required = true + purpose = "Contains unit tests, integration tests, and test fixtures" + subdirectories = [ + { + name = "unit" + path = "tests/unit" + description = "Unit tests" + required = true + }, + { + name = "integration" + path = "tests/integration" + description = "Integration tests" + requirement_status = "suggested" + } + ] + }, + { + name = ".github" + path = ".github" + description = "GitHub-specific configuration" + requirement_status = "suggested" + purpose = "Contains GitHub Actions workflows and configuration" + files = [ + { + name = "copilot.yml" + extension = "yml" + description = "GitHub Copilot allowed domains configuration" + requirement_status = "required" + always_overwrite = true + template = ".github/copilot.yml" + }, + { + name = "copilot-instructions.md" + extension = "md" + description = "GitHub Copilot custom instructions enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "copilot-instructions.md" + template = "templates/github/copilot-instructions.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # {{REPO_NAME}} — GitHub Copilot Custom Instructions + + ## What This Repo Is + + This is a **Moko Consulting MokoWaaS** (Joomla) repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync. + + Repository URL: {{REPO_URL}} + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Platform: **Joomla 4.x / MokoWaaS** + + --- + + ## Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. JavaScript may be used for frontend enhancements. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + ## File Header — Always Required on New Files + + Every new file needs a copyright header as its first content. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /path/to/file.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown:** + ```markdown + + ``` + + **YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. JSON files are exempt. + + --- + + ## Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`. + - The `VERSION: XX.YY.ZZ` field in `README.md` governs all other version references. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. + + ```xml + + 01.02.04 + + + + + {{EXTENSION_NAME}} + 01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + + + + ``` + + --- + + ## Joomla Extension Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required, see below) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images (deployed to /media/{{EXTENSION_ELEMENT}}/) + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ + │ ├── copilot-instructions.md # This file + │ └── CLAUDE.md + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + ├── LICENSE # GPL-3.0-or-later + └── Makefile # Build automation + ``` + + --- + + ## update.xml — Required in Repo Root + + `update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. + + The `manifest.xml` must reference it via: + ```xml + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. + - The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. + - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). + - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. + + --- + + ## manifest.xml Rules + + - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). + - `` tag must be kept in sync with `README.md` version and `update.xml`. + - Must include `` block pointing to this repo's `update.xml`. + - Must include `` and `` sections. + - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. + + --- + + ## GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these in workflows + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + ## MokoStandards Reference + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies: + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + + --- + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `MyController` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + --- + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + --- + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + ## Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed manifest.xml | Update `update.xml` version; bump README.md version | + | New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + ## Key Constraints + + - Never commit directly to `main` — all changes go via PR, squash-merged + - Never skip the FILE INFORMATION block on a new file + - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files + - Never hardcode version numbers in body text — update `README.md` and let automation propagate + - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` + - Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync + MOKO_END + }, + { + name = "CLAUDE.md" + extension = "md" + description = "Claude AI assistant context enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "CLAUDE.md" + template = "templates/github/CLAUDE.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{REPO_DESCRIPTION}}` | First paragraph of `README.md` body, or the GitHub repo description | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # What This Repo Is + + **{{REPO_NAME}}** is a Moko Consulting **MokoWaaS** (Joomla) extension repository. + + {{REPO_DESCRIPTION}} + + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Repository URL: {{REPO_URL}} + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) — the single source of truth for coding standards, file-header policies, GitHub Actions workflows, and Terraform configuration templates across all Moko Consulting repositories. + + --- + + # Repo Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ # CI/CD workflows (synced from MokoStandards) + │ ├── copilot-instructions.md + │ └── CLAUDE.md # This file + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + └── LICENSE # GPL-3.0-or-later + ``` + + --- + + # Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + # Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it to all `FILE INFORMATION` headers automatically on merge. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a version number in body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + Three files must **always have the same version**: + + | File | Where the version lives | + |------|------------------------| + | `README.md` | `FILE INFORMATION` block + badge | + | `manifest.xml` | `` tag | + | `update.xml` | `` in the most recent `` block | + + The `make release` command / release workflow syncs all three automatically. + + --- + + # update.xml — Required in Repo Root + + `update.xml` is the Joomla update server manifest. It allows Joomla installations to check for new versions of this extension via: + + ```xml + + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release prepends a new `` block at the top — older entries are preserved. + - `` in `update.xml` must exactly match `` in `manifest.xml` and `README.md`. + - `` must be a publicly accessible GitHub Releases asset URL. + - `` — backslash is literal (Joomla regex syntax). + + Example `update.xml` entry for a new release: + ```xml + + + {{EXTENSION_NAME}} + {{REPO_NAME}} + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + 01.02.04 + {{REPO_URL}}/releases/tag/01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + 7.4 + Moko Consulting + https://mokoconsulting.tech + + + ``` + + --- + + # File Header Requirements + + Every new file **must** have a copyright header as its first content. JSON files, binary files, generated files, and third-party files are exempt. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /site/controllers/item.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of file purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown / YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. + + --- + + # Coding Standards + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `ItemModel` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + # GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + # Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed `manifest.xml` | Sync version to `update.xml` and `README.md` | + | New release | Prepend `` to `update.xml`; update `CHANGELOG.md`; bump `README.md` | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + # What NOT to Do + + - **Never commit directly to `main`** — all changes go through a PR. + - **Never hardcode version numbers** in body text — update `README.md` and let automation propagate. + - **Never let `manifest.xml`, `update.xml`, and `README.md` versions diverge.** + - **Never skip the FILE INFORMATION block** on a new source file. + - **Never use bare `catch (\Throwable $e) {}`** — always log or re-throw. + - **Never mix tabs and spaces** within a file — follow `.editorconfig`. + - **Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows** — always use `secrets.GH_TOKEN`. + - **Never remove `defined('_JEXEC') or die;`** from web-accessible PHP files. + + --- + + # PR Checklist + + Before opening a PR, verify: + + - [ ] Patch version bumped in `README.md` (e.g. `01.02.03` → `01.02.04`) + - [ ] If this is a release: `manifest.xml` version updated; `update.xml` updated with new entry + - [ ] FILE INFORMATION headers updated in modified files + - [ ] CHANGELOG.md updated + - [ ] Tests pass + + --- + + # Key Policy Documents (MokoStandards) + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + MOKO_END + } + ] + subdirectories = [ + { + name = "workflows" + path = ".github/workflows" + description = "GitHub Actions workflows" + requirement_status = "required" + files = [ + { + name = "ci-joomla.yml" + extension = "yml" + description = "Joomla-specific CI workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/ci-joomla.yml.template" + }, + { + name = "codeql-analysis.yml" + extension = "yml" + description = "CodeQL security analysis workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/generic/codeql-analysis.yml.template" + }, + { + name = "standards-compliance.yml" + extension = "yml" + description = "MokoStandards compliance validation" + requirement_status = "required" + always_overwrite = true + template = ".github/workflows/standards-compliance.yml" + }, + { + name = "enterprise-firewall-setup.yml" + extension = "yml" + description = "Enterprise firewall configuration for trusted domain access" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/enterprise-firewall-setup.yml.template" + }, + { + name = "deploy-dev.yml" + extension = "yml" + description = "SFTP deployment of src/ to the development server" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-dev.yml.template" + }, + { + name = "deploy-demo.yml" + extension = "yml" + description = "SFTP deployment of src/ to the demo server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-demo.yml.template" + }, + { + name = "deploy-rs.yml" + extension = "yml" + description = "SFTP deployment of src/ to the release staging server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-rs.yml.template" + }, + { + name = "sync-version-on-merge.yml" + extension = "yml" + description = "Auto-bump patch version on merge and propagate to all file headers" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/sync-version-on-merge.yml.template" + }, + { + name = "auto-release.yml" + extension = "yml" + description = "Auto-create GitHub Release on push to main with version from README.md" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-release.yml.template" + }, + { + name = "repository-cleanup.yml" + extension = "yml" + description = "Scheduled cleanup: delete retired workflows, stale branches, old workflow runs" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/repository-cleanup.yml.template" + }, + { + name = "auto-dev-issue.yml" + extension = "yml" + description = "Auto-create tracking issue when a dev/** branch is pushed" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-dev-issue.yml.template" + }, + { + name = "repo_health.yml" + extension = "yml" + description = "Joomla-specific repository health check workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/repo_health.yml.template" + } + ] + }, + { + name = "ISSUE_TEMPLATE" + path = ".github/ISSUE_TEMPLATE" + description = "GitHub issue templates synced from MokoStandards" + requirement_status = "required" + files = [ + { + name = "config.yml" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/config.yml" + }, + { + name = "adr.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/adr.md" + }, + { + name = "bug_report.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/bug_report.md" + }, + { + name = "documentation.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/documentation.md" + }, + { + name = "enterprise_support.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/enterprise_support.md" + }, + { + name = "feature_request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/feature_request.md" + }, + { + name = "firewall-request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/firewall-request.md" + }, + { + name = "question.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/question.md" + }, + { + name = "request-license.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/request-license.md" + }, + { + name = "rfc.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/rfc.md" + }, + { + name = "security.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/security.md" + }, + { + name = "joomla_issue.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/joomla_issue.md" + } + ] + } + ] + } + ] + + repository_requirements = { + secrets = [ + { + name = "GH_TOKEN" + description = "Org-level GitHub PAT for automation" + required = true + scope = "org" + }, + { + name = "DEV_FTP_KEY" + description = "SSH private key for SFTP dev deployment (preferred); if DEV_FTP_PASSWORD is also set it is used as the key passphrase, with password-only as fallback" + required = false + scope = "org" + }, + { + name = "DEV_FTP_PASSWORD" + description = "SFTP password for dev deployment; used as SSH key passphrase when DEV_FTP_KEY is also set, and as standalone fallback if key auth fails" + required = false + scope = "org" + note = "At least one of DEV_FTP_KEY or DEV_FTP_PASSWORD must be configured" + } + ] + + variables = [ + { + name = "DEV_FTP_HOST" + description = "Dev server hostname; may include port suffix (e.g. dev.example.com or dev.example.com:2222)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PATH" + description = "Base remote path for SFTP deployment (e.g. /var/www/html)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_USERNAME" + description = "SFTP username for dev server authentication" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PORT" + description = "Explicit SFTP port override; if omitted the port is parsed from DEV_FTP_HOST or defaults to 22" + required = false + scope = "org" + }, + { + name = "DEV_FTP_SUFFIX" + description = "Per-repo path suffix appended to DEV_FTP_PATH (e.g. /my-extension)" + required = false + scope = "repo" + } + ] + } + } +} diff --git a/definitions/sync/MokoStandards-Template-Joomla-Template.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Template.def.tf new file mode 100644 index 0000000..dc0876c --- /dev/null +++ b/definitions/sync/MokoStandards-Template-Joomla-Template.def.tf @@ -0,0 +1,1335 @@ +/** + * Repository Sync Tracking Definition: mokoconsulting-tech/MokoStandards-Template-Joomla-Template + * + * Auto-generated by MokoStandards bulk sync on 2026-04-02T15:28:58+00:00 + * Platform : waas-component + * Description: A repo template for a Joomla Template coding project according to MokoStandards + * + * DO NOT EDIT MANUALLY — this file is regenerated on every successful sync. + * To change what gets synced, edit api/definitions/default/waas-component.tf + * and re-run the bulk-repo-sync workflow. + */ + +locals { + sync_record = { + metadata = { + repo = "mokoconsulting-tech/MokoStandards-Template-Joomla-Template" + default_branch = "main" + detected_platform = "waas-component" + description = "A repo template for a Joomla Template coding project according to MokoStandards" + sync_timestamp = "2026-04-02T15:28:58+00:00" + source_repo = "mokoconsulting-tech/MokoStandards" + base_definition = "api/definitions/default/waas-component.tf" + } + + sync_stats = { + total_files = 41 + created_files = 6 + updated_files = 32 + skipped_files = 3 + } + + synced_files = [ + { path = "LICENSE" action = "updated" }, + { path = "SECURITY.md" action = "created" }, + { path = "CODE_OF_CONDUCT.md" action = "created" }, + { path = "CONTRIBUTING.md" action = "created" }, + { path = "update.xml" action = "updated" }, + { path = "phpstan.neon" action = "updated" }, + { path = "Makefile" action = "updated" }, + { path = ".gitignore" action = "updated" }, + { path = "composer.json" action = "updated" }, + { path = ".mokostandards" action = "created" }, + { path = "docs/update-server.md" action = "created" }, + { path = ".github/copilot.yml" action = "updated" }, + { path = ".github/copilot-instructions.md" action = "updated" }, + { path = ".github/CLAUDE.md" action = "updated" }, + { path = ".github/workflows/codeql-analysis.yml" action = "updated" }, + { path = ".github/workflows/standards-compliance.yml" action = "updated" }, + { path = ".github/workflows/enterprise-firewall-setup.yml" action = "updated" }, + { path = ".github/workflows/deploy-dev.yml" action = "updated" }, + { path = ".github/workflows/deploy-demo.yml" action = "updated" }, + { path = ".github/workflows/deploy-rs.yml" action = "updated" }, + { path = ".github/workflows/sync-version-on-merge.yml" action = "updated" }, + { path = ".github/workflows/auto-release.yml" action = "updated" }, + { path = ".github/workflows/repository-cleanup.yml" action = "updated" }, + { path = ".github/workflows/auto-dev-issue.yml" action = "updated" }, + { path = ".github/workflows/repo_health.yml" action = "created" }, + { path = ".github/ISSUE_TEMPLATE/config.yml" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/adr.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/bug_report.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/documentation.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/enterprise_support.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/feature_request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/firewall-request.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/question.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/request-license.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/rfc.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/security.md" action = "updated" }, + { path = ".github/ISSUE_TEMPLATE/joomla_issue.md" action = "updated" }, + { path = ".github/CODEOWNERS" action = "updated" }, + { path = ".github/.mokostandards" action = "migrated from root" }, + ] + + skipped_files = [ + { path = "GOVERNANCE.md" reason = "Preserved (always_overwrite=false)" }, + { path = ".github/workflows/ci-joomla.yml" reason = "Source file not found" }, + { path = ".github/workflows/custom/README.md" reason = "README — never overwritten" }, + ] + } +} + +# ---- Base platform definition (reference copy) ---- +/** + * MokoWaaS Component Structure Definition + * Standard repository structure for MokoWaaS (Joomla) components + * + * Copyright (C) 2026 Moko Consulting + * SPDX-License-Identifier: GPL-3.0-or-later + * Version: 05.00.00 + * Schema Version: 1.0 + */ + +locals { + repository_structure = { + metadata = { + name = "MokoWaaS Component" + description = "Standard repository structure for MokoWaaS (Joomla) components" + repository_type = "waas-component" + platform = "mokowaas" + last_updated = "2026-01-15T00:00:00Z" + maintainer = "Moko Consulting" + version = "05.00.00" + schema_version = "1.0" + } + + root_files = [ + { + name = "README.md" + extension = "md" + description = "Developer-focused documentation for contributors and maintainers" + required = true + always_overwrite = false + protected = true + audience = "developer" + }, + { + name = "LICENSE" + extension = "" + description = "License file (GPL-3.0-or-later) - Default for Joomla/WaaS components" + required = true + audience = "general" + template = "templates/licenses/GPL-3.0" + license_type = "GPL-3.0-or-later" + }, + { + name = "CHANGELOG.md" + extension = "md" + description = "Version history and changes" + required = true + audience = "general" + }, + { + name = "SECURITY.md" + extension = "md" + description = "Security policy and vulnerability reporting" + required = true + always_overwrite = true + template = "templates/docs/required/template-SECURITY.md" + audience = "general" + }, + { + name = "CODE_OF_CONDUCT.md" + extension = "md" + description = "Community code of conduct" + required = true + always_overwrite = true + template = "templates/docs/extra/template-CODE_OF_CONDUCT.md" + always_overwrite = true + audience = "contributor" + }, + { + name = "ROADMAP.md" + extension = "md" + description = "Project roadmap with version goals and milestones" + required = false + audience = "general" + }, + { + name = "CONTRIBUTING.md" + extension = "md" + description = "Contribution guidelines" + required = true + always_overwrite = true + template = "templates/docs/required/template-CONTRIBUTING.md" + audience = "contributor" + }, + { + name = "update.xml" + extension = "xml" + description = "Joomla extension update server manifest — lists releases for Joomla auto-update; must be kept in sync with manifest.xml version" + required = true + always_overwrite = false + audience = "developer" + template = "templates/joomla/update.xml.template" + stub_content = <<-MOKO_END + + + + {{EXTENSION_NAME}} + {{REPO_NAME}} — Moko Consulting Joomla extension + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + {{VERSION}} + {{REPO_URL}}/releases/tag/{{VERSION}} + + {{DOWNLOAD_URL}} + + + 7.4 + Moko Consulting + {{MAINTAINER_URL}} + + + MOKO_END + }, + { + name = "phpstan.neon" + extension = "neon" + description = "PHPStan static analysis config with Joomla framework class stubs" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/phpstan.joomla.neon" + }, + { + name = "Makefile" + description = "Build automation using MokoStandards templates" + required = true + always_overwrite = true + audience = "developer" + source_path = "templates/makefiles" + source_filename = "Makefile.joomla.template" + source_type = "template" + destination_path = "." + destination_filename = "Makefile" + create_path = false + template = "templates/makefiles/Makefile.joomla.template" + }, + { + name = ".gitignore" + extension = "gitignore" + description = "Git ignore patterns for Joomla development - preserved during sync operations" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/.gitignore.joomla" + validation_rules = [ + { + type = "content-pattern" + description = "Must contain sftp-config pattern to ignore SFTP sync configuration files" + pattern = "sftp-config" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.css pattern to ignore custom user CSS overrides" + pattern = "user\\.css" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain user.js pattern to ignore custom user JavaScript overrides" + pattern = "user\\.js" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain modulebuilder.txt pattern to ignore Joomla Module Builder artifacts" + pattern = "modulebuilder\\.txt" + severity = "error" + }, + { + type = "content-pattern" + description = "Must contain colors_custom.css pattern to ignore custom color scheme overrides" + pattern = "colors_custom\\.css" + severity = "error" + } + ] + }, + { + name = ".gitattributes" + extension = "gitattributes" + description = "Git attributes configuration" + required = true + audience = "developer" + }, + { + name = ".editorconfig" + extension = "editorconfig" + description = "Editor configuration for consistent coding style - preserved during sync" + required = true + always_overwrite = false + audience = "developer" + }, + { + name = "composer.json" + extension = "json" + description = "Composer manifest — requires mokoconsulting-tech/enterprise for CLI scripts and tooling" + required = true + always_overwrite = false + audience = "developer" + template = "templates/configs/composer.joomla.json" + }, + { + name = ".mokostandards" + extension = "yml" + description = "MokoStandards governance attachment — links this repo back to the standards source" + required = true + always_overwrite = true + audience = "developer" + template = "templates/configs/mokostandards.yml.template" + }, + { + name = "GOVERNANCE.md" + extension = "md" + description = "Project governance rules, roles, and decision process — auto-maintained by MokoStandards" + required = true + always_overwrite = false + protected = true + audience = "all" + template = "templates/docs/required/GOVERNANCE.md" + } + ] + + directories = [ + { + name = "site" + path = "site" + description = "Component frontend (site) code" + required = true + purpose = "Contains frontend component code deployed to site" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main site controller" + required = true + audience = "developer" + }, + { + name = "manifest.xml" + extension = "xml" + description = "Component manifest for site" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "site/controllers" + description = "Site controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "site/models" + description = "Site models" + requirement_status = "suggested" + }, + { + name = "views" + path = "site/views" + description = "Site views" + required = true + } + ] + }, + { + name = "admin" + path = "admin" + description = "Component backend (admin) code" + required = true + purpose = "Contains backend component code for administrator" + files = [ + { + name = "controller.php" + extension = "php" + description = "Main admin controller" + required = true + audience = "developer" + } + ] + subdirectories = [ + { + name = "controllers" + path = "admin/controllers" + description = "Admin controllers" + requirement_status = "suggested" + }, + { + name = "models" + path = "admin/models" + description = "Admin models" + requirement_status = "suggested" + }, + { + name = "views" + path = "admin/views" + description = "Admin views" + required = true + }, + { + name = "sql" + path = "admin/sql" + description = "Database schema files" + requirement_status = "suggested" + } + ] + }, + { + name = "media" + path = "media" + description = "Media files (CSS, JS, images)" + requirement_status = "suggested" + purpose = "Contains static assets" + subdirectories = [ + { + name = "css" + path = "media/css" + description = "Stylesheets" + requirement_status = "suggested" + }, + { + name = "js" + path = "media/js" + description = "JavaScript files" + requirement_status = "suggested" + }, + { + name = "images" + path = "media/images" + description = "Image files" + requirement_status = "suggested" + } + ] + }, + { + name = "language" + path = "language" + description = "Language translation files" + required = true + purpose = "Contains language INI files" + }, + { + name = "docs" + path = "docs" + description = "Developer and technical documentation" + required = true + purpose = "Contains technical documentation, API docs, architecture diagrams" + files = [ + { + name = "index.md" + extension = "md" + description = "Documentation index" + required = true + }, + { + name = "update-server.md" + extension = "md" + description = "Joomla update server (update.xml) documentation" + required = true + always_overwrite = true + template = "templates/docs/required/template-update-server-joomla.md" + } + ] + }, + { + name = "scripts" + path = "scripts" + description = "Repo-specific scripts — not managed by MokoStandards sync" + required = false + purpose = "Optional directory for repo-specific build helpers and one-off scripts. MokoStandards tools are installed via Composer (mokoconsulting-tech/enterprise) and called through vendor/bin/." + files = [ + { + name = "MokoStandards.override.xml" + extension = "xml" + description = "MokoStandards sync override configuration - preserved during sync" + requirement_status = "optional" + always_overwrite = false + audience = "developer" + } + ] + }, + { + name = "tests" + path = "tests" + description = "Test files" + required = true + purpose = "Contains unit tests, integration tests, and test fixtures" + subdirectories = [ + { + name = "unit" + path = "tests/unit" + description = "Unit tests" + required = true + }, + { + name = "integration" + path = "tests/integration" + description = "Integration tests" + requirement_status = "suggested" + } + ] + }, + { + name = ".github" + path = ".github" + description = "GitHub-specific configuration" + requirement_status = "suggested" + purpose = "Contains GitHub Actions workflows and configuration" + files = [ + { + name = "copilot.yml" + extension = "yml" + description = "GitHub Copilot allowed domains configuration" + requirement_status = "required" + always_overwrite = true + template = ".github/copilot.yml" + }, + { + name = "copilot-instructions.md" + extension = "md" + description = "GitHub Copilot custom instructions enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "copilot-instructions.md" + template = "templates/github/copilot-instructions.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # {{REPO_NAME}} — GitHub Copilot Custom Instructions + + ## What This Repo Is + + This is a **Moko Consulting MokoWaaS** (Joomla) repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync. + + Repository URL: {{REPO_URL}} + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Platform: **Joomla 4.x / MokoWaaS** + + --- + + ## Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. JavaScript may be used for frontend enhancements. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + ## File Header — Always Required on New Files + + Every new file needs a copyright header as its first content. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /path/to/file.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown:** + ```markdown + + ``` + + **YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. JSON files are exempt. + + --- + + ## Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`. + - The `VERSION: XX.YY.ZZ` field in `README.md` governs all other version references. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. + + ```xml + + 01.02.04 + + + + + {{EXTENSION_NAME}} + 01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + + + + ``` + + --- + + ## Joomla Extension Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required, see below) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images (deployed to /media/{{EXTENSION_ELEMENT}}/) + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ + │ ├── copilot-instructions.md # This file + │ └── CLAUDE.md + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + ├── LICENSE # GPL-3.0-or-later + └── Makefile # Build automation + ``` + + --- + + ## update.xml — Required in Repo Root + + `update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. + + The `manifest.xml` must reference it via: + ```xml + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. + - The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. + - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). + - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. + + --- + + ## manifest.xml Rules + + - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). + - `` tag must be kept in sync with `README.md` version and `update.xml`. + - Must include `` block pointing to this repo's `update.xml`. + - Must include `` and `` sections. + - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. + + --- + + ## GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these in workflows + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + ## MokoStandards Reference + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies: + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + + --- + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `MyController` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + --- + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + --- + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + ## Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed manifest.xml | Update `update.xml` version; bump README.md version | + | New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + ## Key Constraints + + - Never commit directly to `main` — all changes go via PR, squash-merged + - Never skip the FILE INFORMATION block on a new file + - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files + - Never hardcode version numbers in body text — update `README.md` and let automation propagate + - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` + - Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync + MOKO_END + }, + { + name = "CLAUDE.md" + extension = "md" + description = "Claude AI assistant context enforcing MokoStandards — Joomla/WaaS edition" + requirement_status = "required" + always_overwrite = false + destination_path = ".github" + destination_filename = "CLAUDE.md" + template = "templates/github/CLAUDE.joomla.md.template" + stub_content = <<-MOKO_END + > [!IMPORTANT] + > **🔧 AI Self-Update Required on First Use** + > + > This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system + > replaces them automatically at sync time; if you can still see them, sync has not yet run for + > this repository — or this is a brand-new repo. + > + > **On your very first interaction in this repository, before answering any other question:** + > + > 1. Check whether any `{{TOKEN}}` placeholders remain in this file. + > 2. If they do, locate the values as described in the table below and replace every occurrence + > in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`. + > 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]` + > through the closing `> ---` line) in both files. + > 4. Tell the developer: *"I've self-updated the AI context files with this repository's + > values — all set."* + > + > | Placeholder | Where to find the value | + > |---|---| + > | `{{REPO_NAME}}` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) | + > | `{{REPO_URL}}` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/` | + > | `{{REPO_DESCRIPTION}}` | First paragraph of `README.md` body, or the GitHub repo description | + > | `{{EXTENSION_NAME}}` | The `` element in `manifest.xml` at the repository root | + > | `{{EXTENSION_TYPE}}` | The `type` attribute of the `` tag in `manifest.xml` (`component`, `module`, `plugin`, or `template`) | + > | `{{EXTENSION_ELEMENT}}` | The `` tag in `manifest.xml`, or the filename prefix (e.g. `com_myextension`, `mod_mymodule`) | + > + > --- + + # What This Repo Is + + **{{REPO_NAME}}** is a Moko Consulting **MokoWaaS** (Joomla) extension repository. + + {{REPO_DESCRIPTION}} + + Extension name: **{{EXTENSION_NAME}}** + Extension type: **{{EXTENSION_TYPE}}** (`{{EXTENSION_ELEMENT}}`) + Repository URL: {{REPO_URL}} + + This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) — the single source of truth for coding standards, file-header policies, GitHub Actions workflows, and Terraform configuration templates across all Moko Consulting repositories. + + --- + + # Repo Structure + + ``` + {{REPO_NAME}}/ + ├── manifest.xml # Joomla installer manifest (root — required) + ├── update.xml # Update server manifest (root — required) + ├── site/ # Frontend (site) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ └── views/ + ├── admin/ # Backend (admin) code + │ ├── controller.php + │ ├── controllers/ + │ ├── models/ + │ ├── views/ + │ └── sql/ + ├── language/ # Language INI files + ├── media/ # CSS, JS, images + ├── docs/ # Technical documentation + ├── tests/ # Test suite + ├── .github/ + │ ├── workflows/ # CI/CD workflows (synced from MokoStandards) + │ ├── copilot-instructions.md + │ └── CLAUDE.md # This file + ├── README.md # Version source of truth + ├── CHANGELOG.md + ├── CONTRIBUTING.md + └── LICENSE # GPL-3.0-or-later + ``` + + --- + + # Primary Language + + **PHP** (≥ 7.4) is the primary language for this Joomla extension. YAML uses 2-space indentation. All other text files use tabs per `.editorconfig`. + + --- + + # Version Management + + **`README.md` is the single source of truth for the repository version.** + + - **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03` → `01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it to all `FILE INFORMATION` headers automatically on merge. + - Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `01.02.03`). + - Never hardcode a version number in body text — use the badge or FILE INFORMATION header only. + + ### Joomla Version Alignment + + Three files must **always have the same version**: + + | File | Where the version lives | + |------|------------------------| + | `README.md` | `FILE INFORMATION` block + badge | + | `manifest.xml` | `` tag | + | `update.xml` | `` in the most recent `` block | + + The `make release` command / release workflow syncs all three automatically. + + --- + + # update.xml — Required in Repo Root + + `update.xml` is the Joomla update server manifest. It allows Joomla installations to check for new versions of this extension via: + + ```xml + + + + {{REPO_URL}}/raw/main/update.xml + + + ``` + + **Rules:** + - Every release prepends a new `` block at the top — older entries are preserved. + - `` in `update.xml` must exactly match `` in `manifest.xml` and `README.md`. + - `` must be a publicly accessible GitHub Releases asset URL. + - `` — backslash is literal (Joomla regex syntax). + + Example `update.xml` entry for a new release: + ```xml + + + {{EXTENSION_NAME}} + {{REPO_NAME}} + {{EXTENSION_ELEMENT}} + {{EXTENSION_TYPE}} + 01.02.04 + {{REPO_URL}}/releases/tag/01.02.04 + + + {{REPO_URL}}/releases/download/01.02.04/{{EXTENSION_ELEMENT}}-01.02.04.zip + + + + 7.4 + Moko Consulting + https://mokoconsulting.tech + + + ``` + + --- + + # File Header Requirements + + Every new file **must** have a copyright header as its first content. JSON files, binary files, generated files, and third-party files are exempt. + + **PHP:** + ```php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: {{REPO_NAME}}.{{EXTENSION_TYPE}} + * INGROUP: {{REPO_NAME}} + * REPO: {{REPO_URL}} + * PATH: /site/controllers/item.php + * VERSION: XX.YY.ZZ + * BRIEF: One-line description of file purpose + */ + + defined('_JEXEC') or die; + ``` + + **Markdown / YAML / Shell / XML:** Use the appropriate comment syntax with the same fields. + + --- + + # Coding Standards + + ## Naming Conventions + + | Context | Convention | Example | + |---------|-----------|---------| + | PHP class | `PascalCase` | `ItemModel` | + | PHP method / function | `camelCase` | `getItems()` | + | PHP variable | `$snake_case` | `$item_id` | + | PHP constant | `UPPER_SNAKE_CASE` | `MAX_ITEMS` | + | PHP class file | `PascalCase.php` | `ItemModel.php` | + | YAML workflow | `kebab-case.yml` | `ci-joomla.yml` | + | Markdown doc | `kebab-case.md` | `installation-guide.md` | + + ## Commit Messages + + Format: `(): ` — imperative, lower-case subject, no trailing period. + + Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build` + + ## Branch Naming + + Format: `/[/description]` + + Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `dependabot/` + + --- + + # GitHub Actions — Token Usage + + Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). + + ```yaml + # ✅ Correct + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ``` + + ```yaml + # ❌ Wrong — never use these + token: ${{ github.token }} + token: ${{ secrets.GITHUB_TOKEN }} + ``` + + --- + + # Keeping Documentation Current + + | Change type | Documentation to update | + |-------------|------------------------| + | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | + | New or changed `manifest.xml` | Sync version to `update.xml` and `README.md` | + | New release | Prepend `` to `update.xml`; update `CHANGELOG.md`; bump `README.md` | + | New or changed workflow | `docs/workflows/.md` | + | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | + | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | + + --- + + # What NOT to Do + + - **Never commit directly to `main`** — all changes go through a PR. + - **Never hardcode version numbers** in body text — update `README.md` and let automation propagate. + - **Never let `manifest.xml`, `update.xml`, and `README.md` versions diverge.** + - **Never skip the FILE INFORMATION block** on a new source file. + - **Never use bare `catch (\Throwable $e) {}`** — always log or re-throw. + - **Never mix tabs and spaces** within a file — follow `.editorconfig`. + - **Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows** — always use `secrets.GH_TOKEN`. + - **Never remove `defined('_JEXEC') or die;`** from web-accessible PHP files. + + --- + + # PR Checklist + + Before opening a PR, verify: + + - [ ] Patch version bumped in `README.md` (e.g. `01.02.03` → `01.02.04`) + - [ ] If this is a release: `manifest.xml` version updated; `update.xml` updated with new entry + - [ ] FILE INFORMATION headers updated in modified files + - [ ] CHANGELOG.md updated + - [ ] Tests pass + + --- + + # Key Policy Documents (MokoStandards) + + | Document | Purpose | + |----------|---------| + | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type | + | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions | + | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow | + | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR conventions | + | [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md | + | [joomla-development-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/waas/joomla-development-guide.md) | MokoWaaS Joomla extension development guide | + MOKO_END + } + ] + subdirectories = [ + { + name = "workflows" + path = ".github/workflows" + description = "GitHub Actions workflows" + requirement_status = "required" + files = [ + { + name = "ci-joomla.yml" + extension = "yml" + description = "Joomla-specific CI workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/ci-joomla.yml.template" + }, + { + name = "codeql-analysis.yml" + extension = "yml" + description = "CodeQL security analysis workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/generic/codeql-analysis.yml.template" + }, + { + name = "standards-compliance.yml" + extension = "yml" + description = "MokoStandards compliance validation" + requirement_status = "required" + always_overwrite = true + template = ".github/workflows/standards-compliance.yml" + }, + { + name = "enterprise-firewall-setup.yml" + extension = "yml" + description = "Enterprise firewall configuration for trusted domain access" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/enterprise-firewall-setup.yml.template" + }, + { + name = "deploy-dev.yml" + extension = "yml" + description = "SFTP deployment of src/ to the development server" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-dev.yml.template" + }, + { + name = "deploy-demo.yml" + extension = "yml" + description = "SFTP deployment of src/ to the demo server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-demo.yml.template" + }, + { + name = "deploy-rs.yml" + extension = "yml" + description = "SFTP deployment of src/ to the release staging server on merge to main" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/deploy-rs.yml.template" + }, + { + name = "sync-version-on-merge.yml" + extension = "yml" + description = "Auto-bump patch version on merge and propagate to all file headers" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/sync-version-on-merge.yml.template" + }, + { + name = "auto-release.yml" + extension = "yml" + description = "Auto-create GitHub Release on push to main with version from README.md" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-release.yml.template" + }, + { + name = "repository-cleanup.yml" + extension = "yml" + description = "Scheduled cleanup: delete retired workflows, stale branches, old workflow runs" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/repository-cleanup.yml.template" + }, + { + name = "auto-dev-issue.yml" + extension = "yml" + description = "Auto-create tracking issue when a dev/** branch is pushed" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/shared/auto-dev-issue.yml.template" + }, + { + name = "repo_health.yml" + extension = "yml" + description = "Joomla-specific repository health check workflow" + requirement_status = "required" + always_overwrite = true + template = "templates/workflows/joomla/repo_health.yml.template" + } + ] + }, + { + name = "ISSUE_TEMPLATE" + path = ".github/ISSUE_TEMPLATE" + description = "GitHub issue templates synced from MokoStandards" + requirement_status = "required" + files = [ + { + name = "config.yml" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/config.yml" + }, + { + name = "adr.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/adr.md" + }, + { + name = "bug_report.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/bug_report.md" + }, + { + name = "documentation.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/documentation.md" + }, + { + name = "enterprise_support.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/enterprise_support.md" + }, + { + name = "feature_request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/feature_request.md" + }, + { + name = "firewall-request.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/firewall-request.md" + }, + { + name = "question.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/question.md" + }, + { + name = "request-license.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/request-license.md" + }, + { + name = "rfc.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/rfc.md" + }, + { + name = "security.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/security.md" + }, + { + name = "joomla_issue.md" + always_overwrite = true + template = "templates/github/ISSUE_TEMPLATE/joomla_issue.md" + } + ] + } + ] + } + ] + + repository_requirements = { + secrets = [ + { + name = "GH_TOKEN" + description = "Org-level GitHub PAT for automation" + required = true + scope = "org" + }, + { + name = "DEV_FTP_KEY" + description = "SSH private key for SFTP dev deployment (preferred); if DEV_FTP_PASSWORD is also set it is used as the key passphrase, with password-only as fallback" + required = false + scope = "org" + }, + { + name = "DEV_FTP_PASSWORD" + description = "SFTP password for dev deployment; used as SSH key passphrase when DEV_FTP_KEY is also set, and as standalone fallback if key auth fails" + required = false + scope = "org" + note = "At least one of DEV_FTP_KEY or DEV_FTP_PASSWORD must be configured" + } + ] + + variables = [ + { + name = "DEV_FTP_HOST" + description = "Dev server hostname; may include port suffix (e.g. dev.example.com or dev.example.com:2222)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PATH" + description = "Base remote path for SFTP deployment (e.g. /var/www/html)" + required = true + scope = "org" + }, + { + name = "DEV_FTP_USERNAME" + description = "SFTP username for dev server authentication" + required = true + scope = "org" + }, + { + name = "DEV_FTP_PORT" + description = "Explicit SFTP port override; if omitted the port is parsed from DEV_FTP_HOST or defaults to 22" + required = false + scope = "org" + }, + { + name = "DEV_FTP_SUFFIX" + description = "Per-repo path suffix appended to DEV_FTP_PATH (e.g. /my-extension)" + required = false + scope = "repo" + } + ] + } + } +} diff --git a/definitions/sync/MokoTesting.def.tf b/definitions/sync/MokoTesting.def.tf index 6d7e9ab..1f727c8 100644 --- a/definitions/sync/MokoTesting.def.tf +++ b/definitions/sync/MokoTesting.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoWaaS.def.tf b/definitions/sync/MokoWaaS.def.tf index f95873d..bef35e3 100644 --- a/definitions/sync/MokoWaaS.def.tf +++ b/definitions/sync/MokoWaaS.def.tf @@ -86,7 +86,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -99,7 +99,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoWaaSAnnounce.def.tf b/definitions/sync/MokoWaaSAnnounce.def.tf index 464953f..507ce57 100644 --- a/definitions/sync/MokoWaaSAnnounce.def.tf +++ b/definitions/sync/MokoWaaSAnnounce.def.tf @@ -86,7 +86,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -99,7 +99,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoWaaSBrand.def.tf b/definitions/sync/MokoWaaSBrand.def.tf index 03128c2..c5263d9 100644 --- a/definitions/sync/MokoWaaSBrand.def.tf +++ b/definitions/sync/MokoWaaSBrand.def.tf @@ -76,7 +76,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -89,7 +89,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/MokoWinSetup.def.tf b/definitions/sync/MokoWinSetup.def.tf index aac801d..2da4aa4 100644 --- a/definitions/sync/MokoWinSetup.def.tf +++ b/definitions/sync/MokoWinSetup.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/PLG_FINDER_MOKOVMSMARTSEARCH.def.tf b/definitions/sync/PLG_FINDER_MOKOVMSMARTSEARCH.def.tf index 4b4a6ba..e6d262e 100644 --- a/definitions/sync/PLG_FINDER_MOKOVMSMARTSEARCH.def.tf +++ b/definitions/sync/PLG_FINDER_MOKOVMSMARTSEARCH.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/client-clarksvillefurs.def.tf b/definitions/sync/client-clarksvillefurs.def.tf index 6fc01ee..56f964f 100644 --- a/definitions/sync/client-clarksvillefurs.def.tf +++ b/definitions/sync/client-clarksvillefurs.def.tf @@ -112,7 +112,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -125,7 +125,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/client-kiddieland.def.tf b/definitions/sync/client-kiddieland.def.tf index 4bfa5d9..8f63902 100644 --- a/definitions/sync/client-kiddieland.def.tf +++ b/definitions/sync/client-kiddieland.def.tf @@ -99,7 +99,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -112,7 +112,7 @@ locals { platform = "multi-platform" last_updated = "2026-01-16T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/definitions/sync/client-vexcreations.def.tf b/definitions/sync/client-vexcreations.def.tf index fac8cf5..b831647 100644 --- a/definitions/sync/client-vexcreations.def.tf +++ b/definitions/sync/client-vexcreations.def.tf @@ -86,7 +86,7 @@ locals { * * Copyright (C) 2026 Moko Consulting * SPDX-License-Identifier: GPL-3.0-or-later - * Version: 04.05.00 + * Version: 05.00.00 * Schema Version: 1.0 */ @@ -99,7 +99,7 @@ locals { platform = "mokowaas" last_updated = "2026-01-15T00:00:00Z" maintainer = "Moko Consulting" - version = "04.05.00" + version = "05.00.00" schema_version = "1.0" } diff --git a/monitoring/grafana/moko-waas-dashboard.json b/monitoring/grafana/moko-waas-dashboard.json new file mode 100644 index 0000000..30edeb4 --- /dev/null +++ b/monitoring/grafana/moko-waas-dashboard.json @@ -0,0 +1,986 @@ +{ + "description": "Unified Panopticon monitoring for all Joomla client sites", + "editable": true, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 100, + "title": "Site Status", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "0": { + "color": "red", + "text": "DOWN" + }, + "1": { + "color": "green", + "text": "UP" + } + }, + "type": "value" + } + ], + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 1, + "w": 12, + "h": 4 + }, + "id": 1, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "probe_success{site_name=~\"$site\", job=\"blackbox-http\"}", + "legendFormat": "{{site_name}}" + } + ], + "title": "Site Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "0": { + "color": "orange", + "text": "OFFLINE" + }, + "1": { + "color": "green", + "text": "ONLINE" + } + }, + "type": "value" + } + ], + "noValue": "N/A", + "thresholds": { + "steps": [ + { + "color": "orange", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "x": 12, + "y": 1, + "w": 12, + "h": 4 + }, + "id": 2, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_site_online{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Joomla Online", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 200 + }, + { + "color": "yellow", + "value": 300 + }, + { + "color": "orange", + "value": 400 + }, + { + "color": "red", + "value": 500 + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 5, + "w": 12, + "h": 4 + }, + "id": 3, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "probe_http_status_code{site_name=~\"$site\", job=\"blackbox-http\"}", + "legendFormat": "{{site_name}}" + } + ], + "title": "HTTP Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 14 + }, + { + "color": "green", + "value": 30 + } + ] + }, + "unit": "d" + } + }, + "gridPos": { + "x": 12, + "y": 5, + "w": 12, + "h": 4 + }, + "id": 4, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "(probe_ssl_earliest_cert_expiry{site_name=~\"$site\"} - time()) / 86400", + "legendFormat": "{{site_name}}" + } + ], + "title": "SSL Days", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "0": { + "color": "red", + "text": "NO" + }, + "1": { + "color": "green", + "text": "OK" + } + }, + "type": "value" + } + ], + "noValue": "N/A", + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 9, + "w": 12, + "h": 4 + }, + "id": 5, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_site_api_reachable{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "API Reachable", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "noValue": "Never", + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "dateTimeFromNow" + } + }, + "gridPos": { + "x": 12, + "y": 9, + "w": 12, + "h": 4 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_monitor_last_scrape{site=~\"$site\"} * 1000", + "legendFormat": "{{site}}" + } + ], + "title": "Last Check", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 101, + "title": "Joomla Core & Updates", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 14, + "w": 12, + "h": 4 + }, + "id": 10, + "options": { + "colorMode": "background", + "graphMode": "none", + "textMode": "name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_core_version_info{site=~\"$site\"}", + "legendFormat": "{{site}} {{version}}" + } + ], + "title": "Joomla Version", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "0": { + "color": "green", + "text": "CURRENT" + }, + "1": { + "color": "red", + "text": "UPDATE" + } + }, + "type": "value" + } + ], + "noValue": "?", + "thresholds": { + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "x": 12, + "y": 14, + "w": 12, + "h": 4 + }, + "id": 11, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_core_update_available{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Core Update", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "noValue": "N/A", + "thresholds": { + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 18, + "w": 12, + "h": 4 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_extensions_total{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Extensions", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "noValue": "N/A", + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + } + ] + } + } + }, + "gridPos": { + "x": 12, + "y": 18, + "w": 12, + "h": 4 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_extensions_enabled{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Enabled", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "noValue": "N/A", + "thresholds": { + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "orange", + "value": 20 + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 22, + "w": 12, + "h": 4 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_extensions_disabled{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Disabled", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 102, + "title": "Performance", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "unit": "s" + } + }, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 27 + }, + "id": 20, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "probe_http_duration_seconds{site_name=~\"$site\", job=\"blackbox-http\", phase=\"transfer\"}", + "legendFormat": "{{site_name}} transfer" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "probe_http_duration_seconds{site_name=~\"$site\", job=\"blackbox-http\", phase=\"processing\"}", + "legendFormat": "{{site_name}} processing" + } + ], + "title": "Response Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "max": 10, + "min": 0, + "thresholds": { + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "yellow", + "value": 2 + }, + { + "color": "red", + "value": 5 + } + ] + }, + "unit": "s" + } + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 27 + }, + "id": 22, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "probe_duration_seconds{site_name=~\"$site\", job=\"blackbox-http\"}", + "legendFormat": "{{site_name}}" + } + ], + "title": "Total Duration", + "type": "gauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 104, + "title": "Backup Status", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "0": { + "color": "red", + "text": "FAILED" + }, + "1": { + "color": "green", + "text": "OK" + } + }, + "type": "value" + } + ], + "noValue": "No Data", + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 36, + "w": 12, + "h": 4 + }, + "id": 40, + "options": { + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_backup_status{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Last Backup", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "noValue": "?", + "thresholds": { + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "yellow", + "value": 172800 + }, + { + "color": "red", + "value": 604800 + } + ] + }, + "unit": "s" + } + }, + "gridPos": { + "x": 12, + "y": 36, + "w": 12, + "h": 4 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_backup_age_seconds{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Backup Age", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "noValue": "N/A", + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "x": 0, + "y": 40, + "w": 12, + "h": 4 + }, + "id": 42, + "options": { + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "joomla_backup_records_total{site=~\"$site\"}", + "legendFormat": "{{site}}" + } + ], + "title": "Records", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 103, + "title": "Uptime History", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "custom": { + "fillOpacity": 10, + "lineWidth": 2 + }, + "max": 1, + "min": 0, + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.95 + }, + { + "color": "green", + "value": 0.99 + } + ] + }, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 30, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "expr": "avg_over_time(probe_success{site_name=~\"$site\", job=\"blackbox-http\"}[1h])", + "legendFormat": "{{site_name}}" + } + ], + "title": "Availability (30d)", + "type": "timeseries" + } + ], + "refresh": "5m", + "tags": [ + "waas", + "joomla", + "panopticon" + ], + "templating": { + "list": [ + { + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "includeAll": true, + "label": "Site", + "multi": true, + "name": "site", + "query": "label_values(probe_success{job=\"blackbox-http\"}, site_name)", + "refresh": 2, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timezone": "browser", + "title": "MokoWaaS -- Joomla Sites", + "uid": "moko-waas", + "version": 1 +}