diff --git a/.gitea/.mokostandards b/.gitea/.mokostandards
index 80141b0..671d30a 100644
--- a/.gitea/.mokostandards
+++ b/.gitea/.mokostandards
@@ -1 +1,61 @@
-platform: default-repository
+
+
+
+
+
+ MokoStandards-API
+ MokoConsulting
+ MokoStandards Enterprise API — PHP implementation (Composer package: mokoconsulting-tech/enterprise)
+ GNU General Public License v3
+
+ coding
+ standards
+
+
+
+
+ standards-repository
+ 04.07.00
+ https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
+
+
+
+ PHP
+ php:>=8.1
+ composer
+ bin/moko-enterprise
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/automation/enrich_mokostandards_xml.php b/automation/enrich_mokostandards_xml.php
new file mode 100644
index 0000000..69c830e
--- /dev/null
+++ b/automation/enrich_mokostandards_xml.php
@@ -0,0 +1,308 @@
+#!/usr/bin/env php
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Enrich XML .mokostandards manifests with repo-specific build, deploy, and script details.
+ *
+ * Runs AFTER push_mokostandards_xml.php. Clones each repo, inspects its contents,
+ * and updates the manifest with discovered build/deploy/scripts config.
+ *
+ * Usage:
+ * php automation/enrich_mokostandards_xml.php [--dry-run] [--repo NAME] [--skip NAME,NAME]
+ *
+ * Note: This script uses proc_open for shell commands. All arguments are escaped
+ * via escapeshellarg(). No user-supplied input reaches the shell unescaped.
+ */
+
+declare(strict_types=1);
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use MokoEnterprise\MokoStandardsParser;
+
+$giteaUrl = rtrim(getenv('GITEA_URL') ?: 'https://git.mokoconsulting.tech', '/');
+$giteaOrg = getenv('GITEA_ORG') ?: 'MokoConsulting';
+$token = getenv('GA_TOKEN') ?: getenv('GH_TOKEN') ?: '';
+
+$dryRun = in_array('--dry-run', $argv, true);
+$repoFilter = null;
+$skipRepos = [];
+foreach ($argv as $i => $arg) {
+ if ($arg === '--repo' && isset($argv[$i + 1])) $repoFilter = $argv[$i + 1];
+ if ($arg === '--skip' && isset($argv[$i + 1])) $skipRepos = array_map('trim', explode(',', $argv[$i + 1]));
+}
+
+$parser = new MokoStandardsParser();
+$tmpBase = sys_get_temp_dir() . '/moko-enrich-' . getmypid();
+
+function safeExec(string $command, string $cwd = '.'): array {
+ $proc = proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $cwd);
+ if (!is_resource($proc)) return [1, "proc_open failed"];
+ $stdout = stream_get_contents($pipes[1]);
+ $stderr = stream_get_contents($pipes[2]);
+ fclose($pipes[1]); fclose($pipes[2]);
+ return [proc_close($proc), trim($stdout . "\n" . $stderr)];
+}
+
+function rmTree(string $dir): void {
+ if (!is_dir($dir)) return;
+ $it = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
+ $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
+ foreach ($files as $file) {
+ if ($file->isDir()) @rmdir($file->getPathname());
+ else { @chmod($file->getPathname(), 0777); @unlink($file->getPathname()); }
+ }
+ @rmdir($dir);
+}
+
+function gitCmd(string $workDir, string ...$args): array {
+ $cmd = 'git';
+ foreach ($args as $a) $cmd .= ' ' . escapeshellarg($a);
+ return safeExec($cmd, $workDir);
+}
+
+function fetchRepos(string $url, string $org, string $token): array {
+ $repos = []; $page = 1;
+ do {
+ $ch = curl_init("{$url}/api/v1/orgs/{$org}/repos?page={$page}&limit=50");
+ curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: token {$token}"], CURLOPT_TIMEOUT => 30]);
+ $body = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
+ if ($code !== 200) break;
+ $batch = json_decode($body, true); if (empty($batch)) break;
+ $repos = array_merge($repos, $batch); $page++;
+ } while (count($batch) >= 50);
+ return $repos;
+}
+
+function inspectRepo(string $workDir, string $platform): array {
+ $enrichment = [];
+ $build = [];
+
+ // Detect entry point
+ if (is_dir("{$workDir}/src")) {
+ foreach (glob("{$workDir}/src/*.xml") ?: [] as $xf) {
+ $c = file_get_contents($xf);
+ if (str_contains($c, ' $pd, 'version' => $composer['require'][$pd], 'type' => 'platform'];
+ }
+ if (isset($composer['require']['mokoconsulting-tech/enterprise']))
+ $deps[] = ['name' => 'mokoconsulting-tech/enterprise', 'version' => $composer['require']['mokoconsulting-tech/enterprise'], 'type' => 'composer'];
+ if (!empty($deps)) $build['dependencies'] = $deps;
+ }
+
+ // Artifact from Makefile
+ if (file_exists("{$workDir}/Makefile")) {
+ $mk = file_get_contents("{$workDir}/Makefile");
+ if (preg_match('/\bdist\/(\S+\.zip)\b/', $mk, $m)) $build['artifact'] = ['format' => 'zip', 'path' => 'dist/', 'filename' => $m[1]];
+ }
+
+ if (!empty($build)) $enrichment['build'] = $build;
+
+ // Deploy targets from workflows
+ $targets = [];
+ $wfDir = is_dir("{$workDir}/.gitea/workflows") ? "{$workDir}/.gitea/workflows" : "{$workDir}/.github/workflows";
+ if (is_dir($wfDir)) {
+ foreach (['deploy-dev', 'deploy-demo', 'deploy-rs'] as $dn) {
+ $wf = "{$wfDir}/{$dn}.yml";
+ if (!file_exists($wf)) continue;
+ $wc = file_get_contents($wf);
+ $t = ['name' => str_replace('deploy-', '', $dn)];
+ if (str_contains($wc, 'sftp') || str_contains($wc, 'SFTP')) $t['method'] = 'sftp';
+ elseif (str_contains($wc, 'rsync')) $t['method'] = 'rsync';
+ if (str_contains($wc, 'src/')) $t['src_dir'] = 'src/';
+ if (preg_match('/branches:\s*\n\s*-\s*["\']?([^"\'}\s]+)/', $wc, $m)) $t['branch'] = $m[1];
+ $targets[] = $t;
+ }
+ }
+ if (!empty($targets)) $enrichment['deploy'] = $targets;
+
+ // Scripts from Makefile + composer
+ $scripts = [];
+ if (file_exists("{$workDir}/Makefile")) {
+ $mk = file_get_contents("{$workDir}/Makefile");
+ $known = ['build'=>'build','test'=>'test','lint'=>'lint','clean'=>'build','package'=>'build','validate'=>'validate','release'=>'release'];
+ if (preg_match_all('/^([a-zA-Z_-]+)\s*:/m', $mk, $matches)) {
+ foreach ($matches[1] as $tgt) {
+ $tl = strtolower($tgt);
+ if (isset($known[$tl])) $scripts[] = ['name'=>$tl, 'phase'=>$known[$tl], 'command'=>"make {$tgt}", 'desc'=>ucfirst($tl).' via make', 'runner'=>'make'];
+ }
+ }
+ }
+ if (file_exists("{$workDir}/composer.json")) {
+ $composer = json_decode(file_get_contents("{$workDir}/composer.json"), true) ?: [];
+ $km = ['test'=>'test','lint'=>'lint','cs'=>'lint','phpcs'=>'lint','phpstan'=>'lint','validate'=>'validate'];
+ foreach ($composer['scripts'] ?? [] as $sn => $cmd) {
+ $sl = strtolower($sn);
+ foreach ($km as $match => $phase) {
+ if (str_contains($sl, $match)) {
+ $exists = false;
+ foreach ($scripts as $s) { if ($s['name'] === $sl) { $exists = true; break; } }
+ if (!$exists) $scripts[] = ['name'=>$sn, 'phase'=>$phase, 'command'=>"composer run {$sn}", 'desc'=>is_string($cmd)?$cmd:"Run {$sn}", 'runner'=>'composer'];
+ break;
+ }
+ }
+ }
+ }
+ if (!empty($scripts)) $enrichment['scripts'] = $scripts;
+
+ return $enrichment;
+}
+
+function enrichManifestXml(string $xml, array $enrichment): string {
+ $dom = new DOMDocument('1.0', 'UTF-8');
+ $dom->preserveWhiteSpace = false;
+ $dom->formatOutput = true;
+ if (!$dom->loadXML($xml)) return $xml;
+
+ $ns = MokoStandardsParser::NAMESPACE_URI;
+ $root = $dom->documentElement;
+
+ foreach (['build', 'deploy', 'scripts'] as $tag) {
+ $toRemove = [];
+ $existing = $root->getElementsByTagNameNS($ns, $tag);
+ for ($i = 0; $i < $existing->length; $i++) $toRemove[] = $existing->item($i);
+ foreach ($toRemove as $node) $root->removeChild($node);
+ }
+
+ if (!empty($enrichment['build'])) {
+ $build = $dom->createElementNS($ns, 'build');
+ $b = $enrichment['build'];
+ foreach (['language', 'runtime'] as $f) { if (isset($b[$f])) $build->appendChild($dom->createElementNS($ns, $f, htmlspecialchars($b[$f], ENT_XML1))); }
+ if (isset($b['package_type'])) $build->appendChild($dom->createElementNS($ns, 'package-type', htmlspecialchars($b['package_type'], ENT_XML1)));
+ if (isset($b['entry_point'])) $build->appendChild($dom->createElementNS($ns, 'entry-point', htmlspecialchars($b['entry_point'], ENT_XML1)));
+ if (isset($b['artifact'])) {
+ $art = $dom->createElementNS($ns, 'artifact');
+ foreach (['format','path','filename'] as $af) { if (isset($b['artifact'][$af])) $art->appendChild($dom->createElementNS($ns, $af, htmlspecialchars($b['artifact'][$af], ENT_XML1))); }
+ $build->appendChild($art);
+ }
+ if (isset($b['dependencies'])) {
+ $deps = $dom->createElementNS($ns, 'dependencies');
+ foreach ($b['dependencies'] as $d) {
+ $req = $dom->createElementNS($ns, 'requires', '');
+ $req->setAttribute('name', $d['name']);
+ if (isset($d['version'])) $req->setAttribute('version', $d['version']);
+ if (isset($d['type'])) $req->setAttribute('type', $d['type']);
+ $deps->appendChild($req);
+ }
+ $build->appendChild($deps);
+ }
+ $root->appendChild($build);
+ }
+
+ if (!empty($enrichment['deploy'])) {
+ $deploy = $dom->createElementNS($ns, 'deploy');
+ foreach ($enrichment['deploy'] as $t) {
+ $target = $dom->createElementNS($ns, 'target');
+ $target->setAttribute('name', $t['name']);
+ $target->appendChild($dom->createElementNS($ns, 'host', '${{ secrets.' . strtoupper($t['name']) . '_HOST }}'));
+ $target->appendChild($dom->createElementNS($ns, 'path', '${{ secrets.' . strtoupper($t['name']) . '_PATH }}'));
+ if (isset($t['method'])) $target->appendChild($dom->createElementNS($ns, 'method', $t['method']));
+ if (isset($t['branch'])) $target->appendChild($dom->createElementNS($ns, 'branch', htmlspecialchars($t['branch'], ENT_XML1)));
+ if (isset($t['src_dir'])) $target->appendChild($dom->createElementNS($ns, 'src-dir', htmlspecialchars($t['src_dir'], ENT_XML1)));
+ $deploy->appendChild($target);
+ }
+ $root->appendChild($deploy);
+ }
+
+ if (!empty($enrichment['scripts'])) {
+ $scriptsEl = $dom->createElementNS($ns, 'scripts');
+ foreach ($enrichment['scripts'] as $s) {
+ $script = $dom->createElementNS($ns, 'script');
+ $script->setAttribute('name', $s['name']);
+ if (isset($s['phase'])) $script->setAttribute('phase', $s['phase']);
+ $script->appendChild($dom->createElementNS($ns, 'command', htmlspecialchars($s['command'], ENT_XML1)));
+ if (isset($s['desc'])) $script->appendChild($dom->createElementNS($ns, 'description', htmlspecialchars($s['desc'], ENT_XML1)));
+ if (isset($s['runner'])) $script->appendChild($dom->createElementNS($ns, 'runner', htmlspecialchars($s['runner'], ENT_XML1)));
+ $scriptsEl->appendChild($script);
+ }
+ $root->appendChild($scriptsEl);
+ }
+
+ return $dom->saveXML();
+}
+
+// ── Main ─────────────────────────────────────────────────────────────────
+echo "=== MokoStandards XML Manifest Enrichment ===\n";
+echo "Mode: " . ($dryRun ? "DRY RUN" : "LIVE") . "\n";
+if (!empty($skipRepos)) echo "Skipping: " . implode(', ', $skipRepos) . "\n";
+echo "\n";
+
+if (empty($token)) { fprintf(STDERR, "ERROR: GA_TOKEN required\n"); exit(1); }
+
+$repos = fetchRepos($giteaUrl, $giteaOrg, $token);
+echo "Found " . count($repos) . " repositories\n\n";
+
+$stats = ['enriched' => 0, 'skipped' => 0, 'failed' => 0];
+
+foreach ($repos as $repo) {
+ $name = $repo['name'];
+ if ($repoFilter && $name !== $repoFilter) continue;
+ if (in_array($name, $skipRepos, true)) { echo " {$name} ... SKIP (excluded)\n"; $stats['skipped']++; continue; }
+ if ($repo['archived'] ?? false) { $stats['skipped']++; continue; }
+
+ $defaultBranch = $repo['default_branch'] ?? 'main';
+ $httpsUrl = $repo['clone_url'] ?? "{$giteaUrl}/{$giteaOrg}/{$name}.git";
+ $authedUrl = preg_replace('#^https://#', "https://gitea-actions:{$token}@", $httpsUrl);
+
+ echo " {$name} ... ";
+
+ $workDir = "{$tmpBase}/{$name}";
+ @mkdir($workDir, 0755, true);
+ [$ret] = safeExec('git clone --depth 1 --branch ' . escapeshellarg($defaultBranch) . ' ' . escapeshellarg($authedUrl) . ' ' . escapeshellarg($workDir));
+ if ($ret !== 0) { echo "FAIL (clone)\n"; $stats['failed']++; continue; }
+
+ $manifestPath = "{$workDir}/.gitea/.mokostandards";
+ if (!file_exists($manifestPath) || !str_contains(file_get_contents($manifestPath), 'extractPlatform($existingXml) ?? 'default-repository';
+ $enrichment = inspectRepo($workDir, $platform);
+
+ if (!isset($enrichment['build'])) $enrichment['build'] = [];
+ $enrichment['build']['language'] = $enrichment['build']['language'] ?? $repo['language'] ?? MokoStandardsParser::platformLanguage($platform);
+ $enrichment['build']['package_type'] = $enrichment['build']['package_type'] ?? MokoStandardsParser::platformPackageType($platform);
+
+ $enrichedXml = enrichManifestXml($existingXml, $enrichment);
+ $dc = count($enrichment['deploy'] ?? []);
+ $sc = count($enrichment['scripts'] ?? []);
+ $details = "deploy={$dc} scripts={$sc}";
+
+ if ($dryRun) { echo "WOULD ENRICH [{$details}]\n"; $stats['enriched']++; rmTree($workDir); continue; }
+
+ file_put_contents($manifestPath, $enrichedXml);
+ gitCmd($workDir, 'config', 'user.name', 'gitea-actions[bot]');
+ gitCmd($workDir, 'config', 'user.email', 'gitea-actions[bot]@git.mokoconsulting.tech');
+ gitCmd($workDir, 'add', '.gitea/.mokostandards');
+
+ [$cr, $co] = gitCmd($workDir, 'commit', '-m', "chore: enrich .mokostandards with build/deploy/scripts\n\nAuto-detected: {$details}");
+ if ($cr !== 0) { echo "SKIP (no diff)\n"; $stats['skipped']++; rmTree($workDir); continue; }
+
+ [$pr] = gitCmd($workDir, 'push', 'origin', $defaultBranch);
+ if ($pr !== 0) { echo "FAIL (push)\n"; $stats['failed']++; }
+ else { echo "ENRICHED [{$details}]\n"; $stats['enriched']++; }
+
+ rmTree($workDir);
+}
+
+@rmdir($tmpBase);
+echo "\n=== Summary ===\nEnriched: {$stats['enriched']}\nSkipped: {$stats['skipped']}\nFailed: {$stats['failed']}\n";
diff --git a/automation/push_mokostandards_xml.php b/automation/push_mokostandards_xml.php
new file mode 100644
index 0000000..23587e9
--- /dev/null
+++ b/automation/push_mokostandards_xml.php
@@ -0,0 +1,308 @@
+#!/usr/bin/env php
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Push XML .mokostandards manifest to all governed repositories.
+ *
+ * Uses git SSH to bypass the Gitea reverse-proxy WAF that blocks
+ * API requests to paths containing ".gitea".
+ *
+ * Usage:
+ * php automation/push_mokostandards_xml.php [--dry-run] [--repo NAME] [--force]
+ */
+
+declare(strict_types=1);
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use MokoEnterprise\MokoStandardsParser;
+
+// ── Configuration ────────────────────────────────────────────────────────
+$giteaUrl = rtrim(getenv('GITEA_URL') ?: 'https://git.mokoconsulting.tech', '/');
+$giteaOrg = getenv('GITEA_ORG') ?: 'MokoConsulting';
+$token = getenv('GA_TOKEN') ?: getenv('GH_TOKEN') ?: '';
+$sshBase = 'ssh://gitea@git.mokoconsulting.tech:2222';
+
+// ── CLI args ─────────────────────────────────────────────────────────────
+$dryRun = in_array('--dry-run', $argv, true);
+$force = in_array('--force', $argv, true);
+$repoFilter = null;
+$skipRepos = [];
+foreach ($argv as $i => $arg) {
+ if ($arg === '--repo' && isset($argv[$i + 1])) {
+ $repoFilter = $argv[$i + 1];
+ }
+ if ($arg === '--skip' && isset($argv[$i + 1])) {
+ $skipRepos = array_map('trim', explode(',', $argv[$i + 1]));
+ }
+}
+
+$parser = new MokoStandardsParser();
+$tmpBase = sys_get_temp_dir() . '/moko-manifest-push-' . getmypid();
+
+// ── Platform detection heuristics (mirrors RepositorySynchronizer) ───────
+$CRM_PLATFORM_REPOS = ['MokoDolibarr', 'MokoDoliMods'];
+
+function detectPlatform(array $repo): string {
+ global $CRM_PLATFORM_REPOS;
+ $name = $repo['name'] ?? '';
+ $nameLower = strtolower($name);
+ $description = strtolower($repo['description'] ?? '');
+ $topics = $repo['topics'] ?? [];
+
+ if (in_array($name, $CRM_PLATFORM_REPOS, true)) return 'crm-platform';
+ if (in_array('dolibarr-platform', $topics)) return 'crm-platform';
+ if (in_array('joomla-template', $topics)) return 'joomla-template';
+ if (in_array('joomla', $topics) || in_array('joomla-extension', $topics)) return 'waas-component';
+ if (in_array('dolibarr', $topics) || in_array('dolibarr-module', $topics)) return 'crm-module';
+
+ if (str_contains($nameLower, 'template') && (str_contains($nameLower, 'joomla') || str_contains($nameLower, 'tpl'))) return 'joomla-template';
+ if (str_contains($nameLower, 'joomla') || str_contains($nameLower, 'waas')) return 'waas-component';
+ if (str_contains($nameLower, 'doli') || str_contains($nameLower, 'crm')) return 'crm-module';
+
+ if (str_contains($description, 'joomla template')) return 'joomla-template';
+ if (str_contains($description, 'joomla') || str_contains($description, 'component')) return 'waas-component';
+ if (str_contains($description, 'dolibarr') || str_contains($description, 'module')) return 'crm-module';
+
+ if (str_contains($nameLower, 'standard')) return 'standards-repository';
+ return 'default-repository';
+}
+
+/**
+ * Safe shell execution — uses proc_open with explicit arguments to avoid injection.
+ * @return array{int, string}
+ */
+function safeExec(string $command, string $cwd = '.'): array {
+ $proc = proc_open(
+ $command,
+ [1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
+ $pipes,
+ $cwd
+ );
+ if (!is_resource($proc)) {
+ return [1, "proc_open failed for: {$command}"];
+ }
+ $stdout = stream_get_contents($pipes[1]);
+ $stderr = stream_get_contents($pipes[2]);
+ fclose($pipes[1]);
+ fclose($pipes[2]);
+ $code = proc_close($proc);
+ return [$code, trim($stdout . "\n" . $stderr)];
+}
+
+/** Recursively remove a directory (cross-platform). */
+function rmTree(string $dir): void {
+ if (!is_dir($dir)) return;
+ $it = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
+ $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
+ foreach ($files as $file) {
+ if ($file->isDir()) {
+ @rmdir($file->getPathname());
+ } else {
+ // Clear read-only flag (git objects on Windows)
+ @chmod($file->getPathname(), 0777);
+ @unlink($file->getPathname());
+ }
+ }
+ @rmdir($dir);
+}
+
+/**
+ * Run a git command safely in a given working directory.
+ * @return array{int, string}
+ */
+function gitCmd(string $workDir, string ...$args): array {
+ $cmd = 'git';
+ foreach ($args as $a) {
+ $cmd .= ' ' . escapeshellarg($a);
+ }
+ return safeExec($cmd, $workDir);
+}
+
+// ── Fetch all repos via API ──────────────────────────────────────────────
+function fetchRepos(string $url, string $org, string $token): array {
+ $repos = [];
+ $page = 1;
+ do {
+ $ch = curl_init("{$url}/api/v1/orgs/{$org}/repos?page={$page}&limit=50");
+ curl_setopt_array($ch, [
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => ["Authorization: token {$token}"],
+ CURLOPT_TIMEOUT => 30,
+ ]);
+ $body = curl_exec($ch);
+ $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+
+ if ($code !== 200) {
+ fprintf(STDERR, "API error (HTTP %d) fetching repos page %d\n", $code, $page);
+ break;
+ }
+
+ $batch = json_decode($body, true);
+ if (empty($batch)) break;
+ $repos = array_merge($repos, $batch);
+ $page++;
+ } while (count($batch) >= 50);
+
+ return $repos;
+}
+
+// ── Main ─────────────────────────────────────────────────────────────────
+echo "=== MokoStandards XML Manifest Push ===\n";
+echo "Org: {$giteaOrg}\n";
+echo "Mode: " . ($dryRun ? "DRY RUN" : "LIVE") . "\n";
+if ($repoFilter) echo "Filter: {$repoFilter}\n";
+echo "\n";
+
+if (empty($token)) {
+ fprintf(STDERR, "ERROR: GA_TOKEN or GH_TOKEN environment variable required\n");
+ exit(1);
+}
+
+$repos = fetchRepos($giteaUrl, $giteaOrg, $token);
+echo "Found " . count($repos) . " repositories\n\n";
+
+$stats = ['created' => 0, 'updated' => 0, 'skipped' => 0, 'failed' => 0];
+
+foreach ($repos as $repo) {
+ $name = $repo['name'];
+ if ($repoFilter && $name !== $repoFilter) continue;
+ if (in_array($name, $skipRepos, true)) {
+ echo " SKIP {$name} (excluded)\n";
+ $stats['skipped']++;
+ continue;
+ }
+ if ($repo['archived'] ?? false) {
+ echo " SKIP {$name} (archived)\n";
+ $stats['skipped']++;
+ continue;
+ }
+
+ $platform = detectPlatform($repo);
+ $defaultBranch = $repo['default_branch'] ?? 'main';
+ // Prefer HTTPS with token (SSH port 2222 may be blocked); fall back to SSH
+ $httpsUrl = $repo['clone_url'] ?? "{$giteaUrl}/{$giteaOrg}/{$name}.git";
+ // Embed token in HTTPS URL for push auth
+ $authedUrl = preg_replace('#^https://#', "https://gitea-actions:{$token}@", $httpsUrl);
+
+ echo " {$name} [{$platform}] ... ";
+
+ // Generate XML manifest
+ $xmlContent = $parser->generate([
+ 'name' => $name,
+ 'org' => $giteaOrg,
+ 'platform' => $platform,
+ 'standards_version' => '04.07.00',
+ 'description' => $repo['description'] ?? '',
+ 'license' => 'GPL-3.0-or-later',
+ 'topics' => $repo['topics'] ?? [],
+ 'language' => $repo['language'] ?? MokoStandardsParser::platformLanguage($platform),
+ 'package_type' => MokoStandardsParser::platformPackageType($platform),
+ 'last_synced' => date('c'),
+ ]);
+
+ if ($dryRun) {
+ echo "WOULD WRITE ({$platform})\n";
+ $stats['created']++;
+ continue;
+ }
+
+ // Clone shallow via HTTPS (token-authed)
+ $workDir = "{$tmpBase}/{$name}";
+ @mkdir($workDir, 0755, true);
+
+ [$ret, $out] = safeExec(
+ 'git clone --depth 1 --branch ' . escapeshellarg($defaultBranch) . ' '
+ . escapeshellarg($authedUrl) . ' ' . escapeshellarg($workDir)
+ );
+ if ($ret !== 0) {
+ echo "FAIL (clone)\n";
+ fprintf(STDERR, " %s\n", $out);
+ $stats['failed']++;
+ continue;
+ }
+
+ // Check if already XML and up-to-date
+ $manifestPath = "{$workDir}/.gitea/.mokostandards";
+ $existingIsXml = file_exists($manifestPath) && str_contains(file_get_contents($manifestPath), 'extractPlatform(file_get_contents($manifestPath));
+ if ($existingPlatform === $platform) {
+ echo "SKIP (already XML)\n";
+ $stats['skipped']++;
+ rmTree($workDir);
+ continue;
+ }
+ }
+
+ // Write manifest
+ @mkdir("{$workDir}/.gitea", 0755, true);
+ file_put_contents($manifestPath, $xmlContent);
+
+ // Delete legacy files if present
+ $legacyDeleted = [];
+ foreach (['.mokostandards', '.github/.mokostandards'] as $legacy) {
+ $legacyPath = "{$workDir}/{$legacy}";
+ if (file_exists($legacyPath)) {
+ unlink($legacyPath);
+ $legacyDeleted[] = $legacy;
+ }
+ }
+
+ // Commit
+ $isNew = !$existingIsXml;
+ $commitMsg = $isNew
+ ? 'chore: add XML .mokostandards manifest'
+ : 'chore: update .mokostandards to XML format';
+ if (!empty($legacyDeleted)) {
+ $commitMsg .= "\n\nRemoved legacy: " . implode(', ', $legacyDeleted);
+ }
+
+ gitCmd($workDir, 'config', 'user.name', 'gitea-actions[bot]');
+ gitCmd($workDir, 'config', 'user.email', 'gitea-actions[bot]@git.mokoconsulting.tech');
+ gitCmd($workDir, 'add', '.gitea/.mokostandards');
+ foreach ($legacyDeleted as $lf) {
+ gitCmd($workDir, 'add', $lf);
+ }
+
+ [$commitRet, $commitOut] = gitCmd($workDir, 'commit', '-m', $commitMsg);
+ if ($commitRet !== 0 && str_contains($commitOut, 'nothing to commit')) {
+ echo "SKIP (no changes)\n";
+ $stats['skipped']++;
+ rmTree($workDir);
+ continue;
+ }
+ if ($commitRet !== 0) {
+ echo "FAIL (commit)\n";
+ fprintf(STDERR, " %s\n", $commitOut);
+ $stats['failed']++;
+ rmTree($workDir);
+ continue;
+ }
+
+ [$pushRet, $pushOut] = gitCmd($workDir, 'push', 'origin', $defaultBranch);
+ if ($pushRet !== 0) {
+ echo "FAIL (push)\n";
+ fprintf(STDERR, " %s\n", $pushOut);
+ $stats['failed']++;
+ } else {
+ $action = $isNew ? 'CREATED' : 'UPDATED';
+ echo "{$action}\n";
+ $stats[$isNew ? 'created' : 'updated']++;
+ }
+
+ // Cleanup
+ rmTree($workDir);
+}
+
+// Cleanup tmp base
+@rmdir($tmpBase);
+
+echo "\n=== Summary ===\n";
+echo "Created: {$stats['created']}\n";
+echo "Updated: {$stats['updated']}\n";
+echo "Skipped: {$stats['skipped']}\n";
+echo "Failed: {$stats['failed']}\n";
diff --git a/definitions/sync/MokoStandards-Template-Joomla-Component.def.tf b/definitions/sync/MokoStandards-Template-Joomla-Component.def.tf
deleted file mode 100644
index a3eb128..0000000
--- a/definitions/sync/MokoStandards-Template-Joomla-Component.def.tf
+++ /dev/null
@@ -1,1335 +0,0 @@
-/**
- * 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 = "updates.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: 04.05.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 = "04.05.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 = "updates.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/updates.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 (updates.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 `updates.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)
- ├── updates.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
- ```
-
- ---
-
- ## updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below.
- - The `` in `updates.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 `updates.xml`.
- - Must include `` block pointing to this repo's `updates.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 `updates.xml` version; bump README.md version |
- | New release | Prepend `` block to `updates.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, `updates.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)
- ├── updates.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 |
- | `updates.xml` | `` in the most recent `` block |
-
- The `make release` command / release workflow syncs all three automatically.
-
- ---
-
- # updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release prepends a new `` block at the top — older entries are preserved.
- - `` in `updates.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 `updates.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 `updates.xml` and `README.md` |
- | New release | Prepend `` to `updates.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`, `updates.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; `updates.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
deleted file mode 100644
index a1267f6..0000000
--- a/definitions/sync/MokoStandards-Template-Joomla-Library.def.tf
+++ /dev/null
@@ -1,1335 +0,0 @@
-/**
- * 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 = "updates.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: 04.05.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 = "04.05.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 = "updates.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/updates.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 (updates.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 `updates.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)
- ├── updates.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
- ```
-
- ---
-
- ## updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below.
- - The `` in `updates.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 `updates.xml`.
- - Must include `` block pointing to this repo's `updates.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 `updates.xml` version; bump README.md version |
- | New release | Prepend `` block to `updates.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, `updates.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)
- ├── updates.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 |
- | `updates.xml` | `` in the most recent `` block |
-
- The `make release` command / release workflow syncs all three automatically.
-
- ---
-
- # updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release prepends a new `` block at the top — older entries are preserved.
- - `` in `updates.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 `updates.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 `updates.xml` and `README.md` |
- | New release | Prepend `` to `updates.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`, `updates.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; `updates.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
deleted file mode 100644
index 3b632a3..0000000
--- a/definitions/sync/MokoStandards-Template-Joomla-Module.def.tf
+++ /dev/null
@@ -1,1335 +0,0 @@
-/**
- * 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 = "updates.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: 04.05.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 = "04.05.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 = "updates.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/updates.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 (updates.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 `updates.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)
- ├── updates.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
- ```
-
- ---
-
- ## updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below.
- - The `` in `updates.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 `updates.xml`.
- - Must include `` block pointing to this repo's `updates.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 `updates.xml` version; bump README.md version |
- | New release | Prepend `` block to `updates.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, `updates.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)
- ├── updates.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 |
- | `updates.xml` | `` in the most recent `` block |
-
- The `make release` command / release workflow syncs all three automatically.
-
- ---
-
- # updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release prepends a new `` block at the top — older entries are preserved.
- - `` in `updates.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 `updates.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 `updates.xml` and `README.md` |
- | New release | Prepend `` to `updates.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`, `updates.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; `updates.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
deleted file mode 100644
index 4a2d0f2..0000000
--- a/definitions/sync/MokoStandards-Template-Joomla-Package.def.tf
+++ /dev/null
@@ -1,1335 +0,0 @@
-/**
- * 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 = "updates.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: 04.05.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 = "04.05.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 = "updates.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/updates.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 (updates.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 `updates.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)
- ├── updates.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
- ```
-
- ---
-
- ## updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below.
- - The `` in `updates.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 `updates.xml`.
- - Must include `` block pointing to this repo's `updates.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 `updates.xml` version; bump README.md version |
- | New release | Prepend `` block to `updates.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, `updates.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)
- ├── updates.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 |
- | `updates.xml` | `` in the most recent `` block |
-
- The `make release` command / release workflow syncs all three automatically.
-
- ---
-
- # updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release prepends a new `` block at the top — older entries are preserved.
- - `` in `updates.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 `updates.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 `updates.xml` and `README.md` |
- | New release | Prepend `` to `updates.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`, `updates.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; `updates.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
deleted file mode 100644
index a2d07ac..0000000
--- a/definitions/sync/MokoStandards-Template-Joomla-Plugin.def.tf
+++ /dev/null
@@ -1,1335 +0,0 @@
-/**
- * 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 = "updates.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: 04.05.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 = "04.05.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 = "updates.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/updates.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 (updates.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 `updates.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)
- ├── updates.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
- ```
-
- ---
-
- ## updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below.
- - The `` in `updates.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 `updates.xml`.
- - Must include `` block pointing to this repo's `updates.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 `updates.xml` version; bump README.md version |
- | New release | Prepend `` block to `updates.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, `updates.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)
- ├── updates.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 |
- | `updates.xml` | `` in the most recent `` block |
-
- The `make release` command / release workflow syncs all three automatically.
-
- ---
-
- # updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release prepends a new `` block at the top — older entries are preserved.
- - `` in `updates.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 `updates.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 `updates.xml` and `README.md` |
- | New release | Prepend `` to `updates.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`, `updates.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; `updates.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
deleted file mode 100644
index 3cecda3..0000000
--- a/definitions/sync/MokoStandards-Template-Joomla-Template.def.tf
+++ /dev/null
@@ -1,1335 +0,0 @@
-/**
- * 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 = "updates.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: 04.05.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 = "04.05.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 = "updates.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/updates.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 (updates.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 `updates.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)
- ├── updates.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
- ```
-
- ---
-
- ## updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below.
- - The `` in `updates.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 `updates.xml`.
- - Must include `` block pointing to this repo's `updates.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 `updates.xml` version; bump README.md version |
- | New release | Prepend `` block to `updates.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, `updates.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)
- ├── updates.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 |
- | `updates.xml` | `` in the most recent `` block |
-
- The `make release` command / release workflow syncs all three automatically.
-
- ---
-
- # updates.xml — Required in Repo Root
-
- `updates.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/updates.xml
-
-
- ```
-
- **Rules:**
- - Every release prepends a new `` block at the top — older entries are preserved.
- - `` in `updates.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 `updates.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 `updates.xml` and `README.md` |
- | New release | Prepend `` to `updates.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`, `updates.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; `updates.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/docs/WORKFLOW_STANDARDS.md b/docs/WORKFLOW_STANDARDS.md
index 2dd4d3d..47aab46 100644
--- a/docs/WORKFLOW_STANDARDS.md
+++ b/docs/WORKFLOW_STANDARDS.md
@@ -7,14 +7,23 @@
```
Template Repos (canonical source) → Production Repos (synced copies)
───────────────────────────────────── ──────────────────────────────────
-MokoStandards-Template-Joomla-* → MokoOnyx, MokoCassiopeia, MokoJGDPC, etc.
+MokoStandards-Template-Joomla → MokoOnyx, MokoCassiopeia, MokoJGDPC, etc.
MokoStandards-Template-Dolibarr → MokoCRM, MokoDoliForm, MokoDoliAuth, etc.
MokoStandards-Template-Generic → MokoISOUpdatePortable, etc.
-MokoStandards-Template-Client → client-*, etc.
+MokoStandards-Template-Client → client-clarksvillefurs, client-kiddieland
```
**MokoOnyx** is the living reference implementation for Joomla workflows. Template repos are the canonical source for distribution. The MokoStandards-API repo does NOT store workflow templates — it only has `bulk-repo-sync.yml` for its own CI.
+## Template Repos
+
+| Repo | Purpose | Types |
+|------|---------|-------|
+| `MokoStandards-Template-Joomla` | All Joomla extension types in one repo | plugin, template, module, component, package, library |
+| `MokoStandards-Template-Dolibarr` | Dolibarr module scaffold | — |
+| `MokoStandards-Template-Generic` | Non-platform projects | — |
+| `MokoStandards-Template-Client` | Client Joomla sites with media sync | — |
+
## Standard Workflow Suite
### Joomla Repositories (10 workflows)
@@ -104,16 +113,16 @@ These secrets and variables are set at the MokoConsulting org level and availabl
To update workflows across all repos from the canonical template:
```bash
-# Joomla repos — sync from MokoOnyx
-for REPO in MokoOnyx MokoCassiopeia MokoJGDPC MokoJoomHero ...; do
+# Joomla repos — sync from unified template
+for REPO in MokoOnyx MokoCassiopeia MokoJGDPC MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce MokoDPCalendarAPI; do
cd /a/$REPO
rm -f .gitea/workflows/*.yml
- cp /a/MokoStandards-Template-Joomla-Plugin/.gitea/workflows/*.yml .gitea/workflows/
+ cp /a/MokoStandards-Template-Joomla/.gitea/workflows/*.yml .gitea/workflows/
git add .gitea/workflows/ && git commit -m "chore: sync workflows" && git push
done
# Dolibarr repos — sync from Dolibarr template
-for REPO in MokoCRM MokoDoliForm MokoDoliAuth ...; do
+for REPO in MokoCRM MokoDoliForm MokoDoliAuth MokoDolibarr ...; do
cd /a/$REPO
rm -f .gitea/workflows/*.yml
cp /a/MokoStandards-Template-Dolibarr/.gitea/workflows/*.yml .gitea/workflows/
@@ -140,5 +149,6 @@ done
| 2026-05-02 | Added workflows to all 22 Dolibarr production repos |
| 2026-05-02 | Moved canonical source from API repo to template repos |
| 2026-05-02 | Added sync-media.yml to Client template (bidirectional SFTP) |
-| 2026-05-02 | Deployed workflows to 22 Dolibarr production repos |
-| 2026-05-02 | Deployed workflows to 2 client repos (clarksvillefurs, kiddieland) |
+| 2026-05-02 | Deployed workflows to client repos (clarksvillefurs, kiddieland) |
+| 2026-05-02 | Consolidated 6 Joomla template repos → `MokoStandards-Template-Joomla` |
+| 2026-05-02 | Deleted individual template repos (Plugin, Template, Module, Component, Package, Library) |
diff --git a/docs/standards/mokostandards-file-spec.md b/docs/standards/mokostandards-file-spec.md
new file mode 100644
index 0000000..68ab19e
--- /dev/null
+++ b/docs/standards/mokostandards-file-spec.md
@@ -0,0 +1,243 @@
+# `.mokostandards` File Specification
+
+> **Version:** 1.0
+> **Status:** Active
+> **Schema:** [`mokostandards-schema.xsd`](mokostandards-schema.xsd)
+> **Last Updated:** 2026-05-02
+
+## Overview
+
+The `.mokostandards` file is the **repository manifest** for every repo governed by [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards). It lives at `.gitea/.mokostandards` (no file extension) and uses **XML format** internally.
+
+The file serves three purposes:
+
+1. **Identity** — declares the repo's name, organization, description, license, and topics.
+2. **Governance binding** — ties the repo to a specific MokoStandards platform definition, enabling the bulk sync to know which files, workflows, and templates to enforce.
+3. **Repo-specific configuration** — captures build/deploy targets, automation scripts, and per-repo sync overrides so that tooling (CI, `make`, `composer run`) can operate without guessing.
+
+## Location
+
+```
+.gitea/.mokostandards ← primary (Gitea-hosted repos)
+```
+
+Legacy locations (`.mokostandards` at repo root, `.github/.mokostandards`) are auto-migrated by the bulk sync into `.gitea/.mokostandards`.
+
+## Format
+
+The file is well-formed XML with no `.xml` extension. It uses the namespace `https://standards.mokoconsulting.tech/mokostandards/1.0` and is validated against `mokostandards-schema.xsd`.
+
+## Sections
+
+### `` — Required
+
+| Element | Required | Description |
+|---------------|----------|-------------|
+| `` | yes | Repository name (e.g. `MokoCRM`) |
+| `` | yes | Organization slug (e.g. `MokoConsulting`) |
+| `` | no | Human-readable project description |
+| `` | no | License name; optional `spdx` attribute for the SPDX identifier |
+| `