refactor: simplify platform types across definitions and sync engine

Old → New:
  crm-module → dolibarr
  crm-platform → platform
  waas-component → joomla
  joomla-template → joomla (merged)
  default-repository → generic
  standards-repository → standards
  client-site → client
  generic-repository → generic

Updated: definitions, RepositorySynchronizer.php, WORKFLOW_STANDARDS.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Miller
2026-05-05 15:29:57 -05:00
parent bcfd1fb029
commit 57d05a74bd
10 changed files with 33 additions and 1698 deletions
@@ -13,7 +13,7 @@ locals {
metadata = {
name = "Client Joomla Site"
description = "Standard repository structure for client Joomla site projects (overrides, media, configuration)"
repository_type = "client-site"
repository_type = "client"
platform = "mokowaas"
last_updated = "2026-05-04T00:00:00Z"
maintainer = "Moko Consulting"
@@ -13,7 +13,7 @@ locals {
metadata = {
name = "MokoCRM Module"
description = "Standard repository structure for MokoCRM (Dolibarr) modules"
repository_type = "crm-module"
repository_type = "dolibarr"
platform = "dolibarr"
last_updated = "2026-01-07T00:00:00Z"
maintainer = "Moko Consulting"
File diff suppressed because it is too large Load Diff
-499
View File
@@ -1,499 +0,0 @@
/**
* MokoWaaS Joomla Template Structure Definition
* Standard repository structure for Joomla template projects
*
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Version: 04.06.10
* Schema Version: 1.0
*/
locals {
repository_structure = {
metadata = {
name = "Joomla Template"
description = "Standard repository structure for Joomla templates (site or administrator)"
repository_type = "joomla-template"
platform = "mokowaas"
last_updated = "2026-04-14T00:00:00Z"
maintainer = "Moko Consulting"
version = "04.06.10"
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 templates"
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"
audience = "contributor"
},
{
name = "CONTRIBUTING.md"
extension = "md"
description = "Contribution guidelines"
required = true
always_overwrite = true
template = "templates/docs/required/template-CONTRIBUTING.md"
audience = "contributor"
},
{
name = "templateDetails.xml"
extension = "xml"
description = "Joomla template manifest — declares template metadata, positions, styles, and dependencies"
required = true
always_overwrite = false
audience = "developer"
stub_content = <<-MOKO_END
<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site" method="upgrade">
<name>{{TEMPLATE_NAME}}</name>
<creationDate>{{CREATION_DATE}}</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
<license>GPL-3.0-or-later</license>
<version>{{VERSION}}</version>
<description>{{REPO_DESCRIPTION}}</description>
<files>
<filename>index.php</filename>
<filename>component.php</filename>
<filename>error.php</filename>
<filename>offline.php</filename>
<filename>templateDetails.xml</filename>
<folder>html</folder>
<folder>css</folder>
<folder>js</folder>
<folder>images</folder>
<folder>language</folder>
</files>
<media destination="templates/site/{{TEMPLATE_SHORT_NAME}}" folder="media">
<folder>css</folder>
<folder>js</folder>
<folder>images</folder>
<folder>scss</folder>
</media>
<positions>
<position>topbar</position>
<position>navbar</position>
<position>hero</position>
<position>breadcrumbs</position>
<position>sidebar-left</position>
<position>sidebar-right</position>
<position>main-top</position>
<position>main-bottom</position>
<position>footer</position>
<position>debug</position>
</positions>
<updateservers>
<server type="extension" priority="1" name="{{TEMPLATE_NAME}} Update Server">
https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/raw/branch/main/updates.xml
</server>
<server type="extension" priority="2" name="{{TEMPLATE_NAME}} Update Server">
https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/main/updates.xml
</server>
</updateservers>
<config>
<fields name="params">
<fieldset name="basic">
<field name="logoFile" type="media" label="Logo" />
<field name="siteTitle" type="text" label="Site Title" default="" />
<field name="siteDescription" type="text" label="Site Description" default="" />
<field name="colorScheme" type="list" label="Color Scheme" default="light">
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="auto">Auto (system preference)</option>
</field>
</fieldset>
<fieldset name="advanced">
<field name="fluidContainer" type="radio" label="Fluid Container" default="0">
<option value="0">No</option>
<option value="1">Yes</option>
</field>
</fieldset>
</fields>
</config>
</extension>
MOKO_END
},
{
name = "updates.xml"
extension = "xml"
description = "Joomla template update server manifest — polled by Joomla for new versions (dual-platform: Gitea priority 1, GitHub priority 2)"
required = true
always_overwrite = false
audience = "developer"
stub_content = <<-MOKO_END
<updates>
<update>
<name>{{TEMPLATE_NAME}}</name>
<description>{{REPO_DESCRIPTION}}</description>
<element>tpl_{{TEMPLATE_SHORT_NAME}}</element>
<type>template</type>
<version>{{VERSION}}</version>
<downloads>
<downloadurl type="full" format="zip">
https://git.mokoconsulting.tech/mokoconsulting-tech/{{REPO_NAME}}/releases/download/v{{VERSION}}/{{TEMPLATE_SHORT_NAME}}.zip
</downloadurl>
<downloadurl type="full" format="zip">
https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/download/v{{VERSION}}/{{TEMPLATE_SHORT_NAME}}.zip
</downloadurl>
</downloads>
<targetplatform name="joomla" version="[56].*"/>
<php_minimum>8.1</php_minimum>
</update>
</updates>
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 for Joomla template packaging"
required = true
always_overwrite = true
audience = "developer"
template = "templates/makefiles/Makefile.joomla.template"
},
{
name = ".gitignore"
extension = "gitignore"
description = "Git ignore patterns for Joomla template development"
required = true
always_overwrite = false
audience = "developer"
template = "templates/configs/.gitignore.joomla"
},
{
name = ".editorconfig"
extension = "editorconfig"
description = "Editor configuration for consistent coding style"
required = true
always_overwrite = true
template = "templates/configs/.editorconfig"
audience = "developer"
},
{
name = ".ftpignore"
extension = "ftpignore"
description = "FTP/SFTP ignore patterns for deploy-joomla.php"
required = false
always_overwrite = false
audience = "developer"
},
]
subdirectories = [
{
name = "src"
description = "Template source files — maps to templates/{name}/ on the Joomla server"
required = true
files = [
{
name = "index.php"
description = "Main template entry point"
required = true
always_overwrite = false
stub_content = <<-MOKO_END
<?php
/**
* @package Joomla.Site
* @subpackage Templates.{{TEMPLATE_SHORT_NAME}}
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Document\HtmlDocument;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
/** @var HtmlDocument $this */
$app = Factory::getApplication();
$wa = $this->getWebAssetManager();
$doc = $app->getDocument();
$lang = $app->getLanguage();
// Load template CSS/JS via Web Asset Manager
$wa->useStyle('template.{{TEMPLATE_SHORT_NAME}}.css');
$wa->useScript('template.{{TEMPLATE_SHORT_NAME}}.js');
?>
<!DOCTYPE html>
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
<head>
<jdoc:include type="metas" />
<jdoc:include type="styles" />
<jdoc:include type="scripts" />
</head>
<body class="site <?php echo $this->direction === 'rtl' ? 'rtl' : 'ltr'; ?>">
<header>
<jdoc:include type="modules" name="topbar" style="none" />
<jdoc:include type="modules" name="navbar" style="none" />
</header>
<jdoc:include type="modules" name="hero" style="none" />
<jdoc:include type="modules" name="breadcrumbs" style="none" />
<main>
<jdoc:include type="modules" name="main-top" style="html5" />
<jdoc:include type="message" />
<jdoc:include type="component" />
<jdoc:include type="modules" name="main-bottom" style="html5" />
</main>
<footer>
<jdoc:include type="modules" name="footer" style="none" />
</footer>
<jdoc:include type="modules" name="debug" style="none" />
</body>
</html>
MOKO_END
},
{
name = "error.php"
description = "Error page template (404, 500, etc.)"
required = true
always_overwrite = false
},
{
name = "offline.php"
description = "Offline page template shown when site is in maintenance mode"
required = true
always_overwrite = false
},
{
name = "component.php"
description = "Component-only template (print view / raw output)"
required = false
always_overwrite = false
},
]
},
{
name = "src/html"
description = "Template overrides for Joomla component/module views"
required = true
files = [
{
name = "index.html"
description = "Prevents directory listing"
required = true
always_overwrite = true
stub_content = "<!DOCTYPE html><title></title>"
},
]
},
{
name = "src/css"
description = "Compiled CSS files"
required = true
files = []
},
{
name = "src/js"
description = "JavaScript files"
required = true
files = []
},
{
name = "src/images"
description = "Template images and icons"
required = true
files = [
{
name = "template_preview.png"
description = "Template preview screenshot shown in Joomla admin"
required = false
always_overwrite = false
},
{
name = "template_thumbnail.png"
description = "Template thumbnail shown in template list"
required = false
always_overwrite = false
},
]
},
{
name = "src/language/en-GB"
description = "English language files for the template"
required = true
files = [
{
name = "tpl_{{TEMPLATE_SHORT_NAME}}.ini"
description = "Main language strings"
required = true
always_overwrite = false
},
{
name = "tpl_{{TEMPLATE_SHORT_NAME}}.sys.ini"
description = "System language strings (used in admin template manager)"
required = true
always_overwrite = false
},
]
},
{
name = "media"
description = "Template media files — maps to media/templates/site/{name}/ on the Joomla server"
required = true
files = []
},
{
name = "media/css"
description = "Compiled CSS assets served from /media/"
required = true
files = []
},
{
name = "media/js"
description = "JavaScript assets served from /media/"
required = true
files = []
},
{
name = "media/images"
description = "Image assets served from /media/"
required = true
files = []
},
{
name = "media/scss"
description = "SCSS source files (compiled to media/css/)"
required = false
files = []
},
{
name = ".gitea/workflows"
description = "Gitea Actions CI/CD workflows"
required = true
files = [
{
name = "auto-release.yml"
description = "Automated release — builds zip, creates Gitea release, updates SHA in updates.xml. Triggered by push to main (stable) or pre-release tags (development, alpha, beta, rc)"
required = true
always_overwrite = true
template = "workflows/auto-release.yml"
},
{
name = "ci-joomla.yml"
description = "Continuous integration — PHP linting, PHPStan static analysis, coding standards checks"
required = true
always_overwrite = true
template = "workflows/ci-joomla.yml"
},
{
name = "pre-release.yml"
description = "Manual pre-release — builds dev/alpha/beta/rc packages with patch version bump"
required = true
always_overwrite = true
template = "workflows/pre-release.yml"
},
{
name = "deploy-manual.yml"
description = "Manual deployment — allows selecting target environment and branch for on-demand deploys"
required = true
always_overwrite = true
template = "workflows/deploy-manual.yml"
},
{
name = "repo-health.yml"
description = "Repository health checks — validates required files, structure compliance, and standards alignment"
required = true
always_overwrite = true
template = "workflows/repo-health.yml"
},
{
name = "update-server.yml"
description = "Update server maintenance — validates updates.xml format and ensures download URLs are reachable"
required = true
always_overwrite = true
template = "workflows/update-server.yml"
},
{
name = "pr-check.yml"
description = "PR gate — validates PHP syntax, manifest XML, and package build before merge to main"
required = true
always_overwrite = true
template = "workflows/pr-check.yml"
},
{
name = "security-audit.yml"
description = "Dependency vulnerability scanning — weekly schedule and on PR when lock files change"
required = true
always_overwrite = true
template = "workflows/security-audit.yml"
},
{
name = "notify.yml"
description = "Push notifications via ntfy on release success or workflow failure"
required = true
always_overwrite = true
template = "workflows/notify.yml"
},
{
name = "cleanup.yml"
description = "Scheduled cleanup — delete merged branches and old workflow runs weekly"
required = true
always_overwrite = true
template = "workflows/cleanup.yml"
},
]
},
]
}
}
@@ -13,7 +13,7 @@ locals {
metadata = {
name = "MokoWaaS Component"
description = "Standard repository structure for MokoWaaS (Joomla) components"
repository_type = "waas-component"
repository_type = "joomla"
platform = "mokowaas"
last_updated = "2026-01-15T00:00:00Z"
maintainer = "Moko Consulting"
@@ -2,7 +2,7 @@
* Dolibarr Platform Structure Definition
* Standard repository structure for the full Dolibarr ERP/CRM installation
*
* This is distinct from crm-module it defines the ENTIRE Dolibarr platform
* This is distinct from dolibarr it defines the ENTIRE Dolibarr platform
* (htdocs/, not src/). It does NOT have a module descriptor, numero, or
* publish-to-mokodolimods workflow.
*
@@ -17,7 +17,7 @@ locals {
metadata = {
name = "Dolibarr Platform"
description = "Full Dolibarr ERP/CRM installation — htdocs/ root, not a module"
repository_type = "crm-platform"
repository_type = "platform"
platform = "dolibarr"
last_updated = "2026-03-31T00:00:00Z"
maintainer = "Moko Consulting"
+1 -1
View File
@@ -176,5 +176,5 @@ done
| 2026-05-02 | Release naming: includes extension element name (e.g. "mokodpcalendarapi 03.00.00 (stable)") |
| 2026-05-02 | Stable releases overwrite (not append) |
| 2026-05-04 | Removed updates.xml + update-server.yml from client repos (sites, not extensions) |
| 2026-05-04 | Added client-site.tf definition in MokoStandards-API |
| 2026-05-04 | Added client.tf definition in MokoStandards-API |
| 2026-05-05 | Version policy: stable=minor bump, pre-release=patch bump (was major/patch) |
+27 -27
View File
@@ -275,7 +275,7 @@ class RepositorySynchronizer
*
* @param string $org
* @param string $repo
* @param string $platform Detected platform slug (e.g. 'crm-module')
* @param string $platform Detected platform slug (e.g. 'dolibarr')
* @param array $repoInfo Raw GitHub API repository object
* @param array $summary Sync result from createSyncPR: {copied[], skipped[], total}
* @return bool
@@ -298,7 +298,7 @@ class RepositorySynchronizer
$repoRoot = dirname(dirname(__DIR__));
$baseDefPath = "{$repoRoot}/definitions/default/{$platform}.tf";
if (!file_exists($baseDefPath)) {
$baseDefPath = "{$repoRoot}/definitions/default/default-repository.tf";
$baseDefPath = "{$repoRoot}/definitions/default/generic.tf";
}
$baseDefinition = file_get_contents($baseDefPath) ?: '';
@@ -469,48 +469,48 @@ HCL;
// Explicit platform repos — full Dolibarr installation, not a module
if (in_array($name, self::CRM_PLATFORM_REPOS, true)) {
return 'crm-platform';
return 'platform';
}
if (in_array('dolibarr-platform', $topics)) {
return 'crm-platform';
return 'platform';
}
// Check topics first — templates before generic joomla
if (in_array('joomla-template', $topics)) {
return 'joomla-template';
if (in_array('joomla', $topics)) {
return 'joomla';
}
if (in_array('joomla', $topics) || in_array('joomla-extension', $topics)) {
return 'waas-component';
return 'joomla';
}
if (in_array('dolibarr', $topics) || in_array('dolibarr-module', $topics)) {
return 'crm-module';
return 'dolibarr';
}
// Check name patterns — templates before generic joomla
if (str_contains($nameLower, 'template') && (str_contains($nameLower, 'joomla') || str_contains($nameLower, 'tpl'))) {
return 'joomla-template';
return 'joomla';
}
if (str_contains($nameLower, 'joomla') || str_contains($nameLower, 'waas')) {
return 'waas-component';
return 'joomla';
}
if (str_contains($nameLower, 'doli') || str_contains($nameLower, 'crm')) {
return 'crm-module';
return 'dolibarr';
}
// Check description patterns
if (str_contains($description, 'joomla template') || str_contains($description, 'joomla 5 template')
|| str_contains($description, 'joomla 4 template')) {
return 'joomla-template';
return 'joomla';
}
if (str_contains($description, 'joomla') || str_contains($description, 'component')) {
return 'waas-component';
return 'joomla';
}
if (str_contains($description, 'dolibarr') || str_contains($description, 'module')) {
return 'crm-module';
return 'dolibarr';
}
// Default
return 'default-repository';
return 'generic';
}
/**
@@ -518,7 +518,7 @@ HCL;
*
* @param string $org
* @param string $repo
* @param string $platform Detected platform slug (e.g. 'crm-module')
* @param string $platform Detected platform slug (e.g. 'dolibarr')
* @param array<int, array{source?: string, inline_content?: string, destination: string, always_overwrite: bool}> $filesToSync
* @param string $repoRoot Absolute path to the MokoStandards repository root
* @param bool $force When true, overwrite files even when always_overwrite = false
@@ -608,7 +608,7 @@ HCL;
* {{PRIMARY_LANGUAGE}} — dominant language from GitHub
* {{PLATFORM_TYPE}} — human-readable platform label
*
* Dolibarr-specific tokens (crm-module platform only):
* Dolibarr-specific tokens (dolibarr platform only):
* {{MODULE_NAME}} — lowercase module name (e.g. mokocrm)
* {{MODULE_CLASS}} — PascalCase class name (e.g. MokoCRM)
* {{MODULE_ID}} — $this->numero from descriptor (null → left unreplaced)
@@ -1059,8 +1059,8 @@ HCL;
// Determine which template repo to source from
$templateType = match (true) {
in_array($platform, ['crm-module', 'crm-platform']) => 'dolibarr',
in_array($platform, ['waas-component', 'joomla-template']) => 'joomla',
in_array($platform, ['dolibarr', 'platform']) => 'dolibarr',
in_array($platform, ['joomla', 'joomla']) => 'joomla',
str_starts_with($platform, 'client') => 'client',
default => 'generic',
};
@@ -1096,10 +1096,10 @@ HCL;
// Platform-specific gitignore (merged, not replaced)
$gitignoreMap = [
'crm-module' => 'templates/configs/gitignore.dolibarr',
'crm-platform' => 'templates/configs/gitignore.dolibarr',
'waas-component' => 'templates/configs/.gitignore.joomla',
'joomla-template' => 'templates/configs/.gitignore.joomla',
'dolibarr' => 'templates/configs/gitignore.dolibarr',
'platform' => 'templates/configs/gitignore.dolibarr',
'joomla' => 'templates/configs/.gitignore.joomla',
'joomla' => 'templates/configs/.gitignore.joomla',
];
$gitignoreTemplate = $gitignoreMap[$platform] ?? 'templates/configs/gitignore';
$shared[] = [$gitignoreTemplate, '.gitignore'];
@@ -1135,7 +1135,7 @@ HCL;
}
// Create update.txt stub for Dolibarr repos (plain text version file)
if ($platform === 'crm-module') {
if ($platform === 'dolibarr') {
$entries[] = [
'inline_content' => '0.0.0',
'destination' => 'update.txt',
@@ -1289,9 +1289,9 @@ HCL;
// Map platform slug to human-readable label
$platformType = match ($platform) {
'crm-module' => 'Dolibarr module',
'waas-component' => 'Joomla extension',
'default-repository' => 'PHP library',
'dolibarr' => 'Dolibarr module',
'joomla' => 'Joomla extension',
'generic' => 'PHP library',
default => ucfirst(str_replace('-', ' ', $platform)),
};