feat: initial scaffold

This commit is contained in:
2026-06-27 20:20:33 +00:00
parent 0cfa9a3293
commit ba2ef062a6
15 changed files with 435 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
.claude/
.mcp.json
TODO.md
*.min.css
*.min.js
+20
View File
@@ -0,0 +1,20 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
INGROUP: MokoSuiteLogistics.Documentation
BRIEF: Version history using Keep a Changelog
-->
# Changelog
## [Unreleased]
### Added
- **Repository** -- initial repo creation with scaffolding
- **System Plugin** -- Extension class, service provider
- **SQL Schema** -- 8 tables
- **Admin Component** -- 6 views: Dashboard, Shipments, Routes, Carriers, Warehouses, Packages
- **Webservices Plugin** -- 6 API routes
- **Configuration** -- basic settings fieldset
- **Access Control** -- core permissions
- **Language Files** -- en-GB translations
+30
View File
@@ -0,0 +1,30 @@
# MokoSuiteLogistics
Layer 2 — Fleet logistics, shipment tracking, route planning, warehouse management
## Quick Reference
| Field | Value |
|---|---|
| **Package** | `pkg_mokosuitelogistics` |
| **Layer** | 2 (requires: Client, CRM) |
| **Language** | PHP 8.3+ |
| **Branch** | develop on `dev`, merge to `main` (protected) |
## Architecture
Joomla **package** -- Layer 2 add-on. CRM contacts as shippers/consignees, shipment tracking with multi-stop routes, warehouse zone management.
## Rules
- **Never commit** `.claude/`, `.mcp.json`, `TODO.md`, `*.min.css`/`*.min.js`
- **Attribution**: `Authored-by: Moko Consulting`
- **Workflow directory**: `.mokogitea/`
- **Standards**: [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoCLI/wiki)
- **Changelog**: `[Unreleased]` only -- release system assigns versions
## Coding Standards
- PHP 8.3+ / Joomla 6 patterns
- `$this->getDatabase()` in models, `Factory::getContainer()->get(DatabaseInterface::class)` in helpers
- `Factory::getApplication()->getIdentity()` for user
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<access component="com_mokosuitelogistics">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" />
<action name="core.manage" title="JACTION_MANAGE" />
<action name="core.create" title="JACTION_CREATE" />
<action name="core.delete" title="JACTION_DELETE" />
<action name="core.edit" title="JACTION_EDIT" />
<action name="core.edit.state" title="JACTION_EDITSTATE" />
</section>
</access>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<fieldset name="component" label="COM_MOKOSUITELOGISTICS_CONFIG">
<field name="items_per_page" type="number" default="20" label="Items Per Page" min="5" max="100" />
</fieldset>
</config>
@@ -0,0 +1,30 @@
<?php
/**
* @copyright (C) 2026 Moko Consulting
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\MVCComponent;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Router\ApiRouter;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
return $component;
}
);
}
};
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" method="upgrade">
<name>com_mokosuitelogistics</name>
<version>0.0.0</version>
<creationDate>2026-06</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>(C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>Layer 2 — Fleet logistics, shipment tracking, route planning, warehouse management</description>
<namespace path="src">MokoConsulting\Component\MokoSuiteLogistics</namespace>
<administration>
<files folder="admin">
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
<folder>language</folder>
<filename>access.xml</filename>
<filename>config.xml</filename>
</files>
<menu>MokoSuiteLogistics</menu>
<submenu>
<menu link="option=com_mokosuitelogistics&amp;view=logisticsdashboard">Dashboard</menu>
<menu link="option=com_mokosuitelogistics&amp;view=logisticsshipments">Shipments</menu>
<menu link="option=com_mokosuitelogistics&amp;view=logisticsroutes">Routes</menu>
<menu link="option=com_mokosuitelogistics&amp;view=logisticscarriers">Carriers</menu>
<menu link="option=com_mokosuitelogistics&amp;view=logisticswarehouses">Warehouses</menu>
<menu link="option=com_mokosuitelogistics&amp;view=logisticspackages">Packages</menu>
</submenu>
</administration>
</extension>
@@ -0,0 +1,3 @@
PLG_SYSTEM_MOKOSUITELOGISTICS="Logistics"
PLG_SYSTEM_MOKOSUITELOGISTICS_DESCRIPTION="MokoSuiteLogistics system plugin"
PLG_SYSTEM_MOKOSUITELOGISTICS_ENABLED="Enable MokoSuiteLogistics"
@@ -0,0 +1,3 @@
PLG_SYSTEM_MOKOSUITELOGISTICS="Logistics"
PLG_SYSTEM_MOKOSUITELOGISTICS_DESCRIPTION="MokoSuiteLogistics system plugin"
PLG_SYSTEM_MOKOSUITELOGISTICS_ENABLED="Enable MokoSuiteLogistics"
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_mokosuitelogistics</name>
<version>0.0.0</version>
<creationDate>2026-06</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>(C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>MokoSuiteLogistics system plugin -- schema owner and bootstrap</description>
<namespace path="src">MokoConsulting\Plugin\System\MokoSuiteLogistics</namespace>
<files>
<folder>src</folder>
<folder>services</folder>
<folder>sql</folder>
<folder>language</folder>
</files>
<install>
<sql>
<file driver="mysql" charset="utf8mb4">sql/install.mysql.sql</file>
</sql>
</install>
<uninstall>
<sql>
<file driver="mysql" charset="utf8mb4">sql/uninstall.mysql.sql</file>
</sql>
</uninstall>
<languages folder="language">
<language tag="en-GB">en-GB/plg_system_mokosuitelogistics.ini</language>
<language tag="en-GB">en-GB/plg_system_mokosuitelogistics.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field name="enabled" type="radio" label="PLG_SYSTEM_MOKOSUITELOGISTICS_ENABLED" default="1" class="btn-group">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>
@@ -0,0 +1,31 @@
<?php
/**
* @copyright (C) 2026 Moko Consulting
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use MokoConsulting\Plugin\System\MokoSuiteLogistics\Extension\Logistics;
return new class implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Logistics($dispatcher, (array) PluginHelper::getPlugin('system', 'mokosuitelogistics'));
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};
@@ -0,0 +1,172 @@
-- MokoSuiteLogistics Schema
-- Copyright (C) 2026 Moko Consulting
-- SPDX-License-Identifier: GPL-3.0-or-later
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_carriers` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`contact_id` INT UNSIGNED NULL COMMENT 'FK to CRM contacts',
`name` VARCHAR(255) NOT NULL,
`code` VARCHAR(50) NOT NULL,
`carrier_type` ENUM('ground','air','sea','rail','courier') NOT NULL DEFAULT 'ground',
`tracking_url_template` VARCHAR(500) NULL,
`phone` VARCHAR(50) NULL,
`email` VARCHAR(255) NULL,
`status` ENUM('active','inactive','suspended') NOT NULL DEFAULT 'active',
`notes` TEXT NULL,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_code` (`code`),
KEY `idx_status` (`status`),
KEY `idx_contact` (`contact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_warehouses` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`code` VARCHAR(50) NOT NULL,
`address` TEXT NULL,
`city` VARCHAR(100) NULL,
`state` VARCHAR(100) NULL,
`postal_code` VARCHAR(20) NULL,
`country` VARCHAR(100) NULL,
`capacity_sqft` DECIMAL(12,2) NULL,
`manager_contact_id` INT UNSIGNED NULL COMMENT 'FK to CRM contacts',
`status` ENUM('active','inactive','maintenance') NOT NULL DEFAULT 'active',
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_code` (`code`),
KEY `idx_status` (`status`),
KEY `idx_manager_contact` (`manager_contact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_warehouse_zones` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`warehouse_id` INT UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL,
`zone_type` ENUM('receiving','storage','picking','packing','shipping','cold','hazmat') NOT NULL DEFAULT 'storage',
`capacity` INT UNSIGNED NULL,
`current_utilization` INT UNSIGNED NOT NULL DEFAULT 0,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_warehouse` (`warehouse_id`),
KEY `idx_zone_type` (`zone_type`),
CONSTRAINT `fk_zone_warehouse` FOREIGN KEY (`warehouse_id`) REFERENCES `#__mokosuitelogistics_warehouses`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_shipments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`shipment_number` VARCHAR(50) NOT NULL,
`shipper_contact_id` INT UNSIGNED NULL COMMENT 'FK to CRM contacts',
`consignee_contact_id` INT UNSIGNED NULL COMMENT 'FK to CRM contacts',
`carrier_id` INT UNSIGNED NULL,
`warehouse_id` INT UNSIGNED NULL,
`origin_address` TEXT NULL,
`destination_address` TEXT NULL,
`shipment_type` ENUM('inbound','outbound','transfer','return') NOT NULL DEFAULT 'outbound',
`status` ENUM('draft','booked','picked_up','in_transit','out_for_delivery','delivered','cancelled','returned') NOT NULL DEFAULT 'draft',
`priority` ENUM('standard','express','overnight','freight') NOT NULL DEFAULT 'standard',
`weight_kg` DECIMAL(10,3) NULL,
`volume_cbm` DECIMAL(10,4) NULL,
`estimated_pickup` DATETIME NULL,
`estimated_delivery` DATETIME NULL,
`actual_pickup` DATETIME NULL,
`actual_delivery` DATETIME NULL,
`tracking_number` VARCHAR(255) NULL,
`shipping_cost` DECIMAL(10,2) NULL,
`insurance_value` DECIMAL(10,2) NULL,
`notes` TEXT NULL,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_shipment_number` (`shipment_number`),
KEY `idx_status` (`status`),
KEY `idx_shipper_contact` (`shipper_contact_id`),
KEY `idx_consignee_contact` (`consignee_contact_id`),
KEY `idx_carrier` (`carrier_id`),
KEY `idx_warehouse` (`warehouse_id`),
KEY `idx_estimated_delivery` (`estimated_delivery`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_routes` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`carrier_id` INT UNSIGNED NULL,
`route_type` ENUM('scheduled','on_demand','dedicated') NOT NULL DEFAULT 'scheduled',
`status` ENUM('active','inactive','planned') NOT NULL DEFAULT 'planned',
`distance_km` DECIMAL(10,2) NULL,
`estimated_duration_hours` DECIMAL(6,2) NULL,
`notes` TEXT NULL,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_carrier` (`carrier_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_route_stops` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`route_id` INT UNSIGNED NOT NULL,
`stop_number` INT UNSIGNED NOT NULL,
`location_name` VARCHAR(255) NOT NULL,
`address` TEXT NULL,
`latitude` DECIMAL(10,7) NULL,
`longitude` DECIMAL(10,7) NULL,
`stop_type` ENUM('pickup','dropoff','waypoint','rest') NOT NULL DEFAULT 'dropoff',
`estimated_arrival` DATETIME NULL,
`estimated_departure` DATETIME NULL,
`actual_arrival` DATETIME NULL,
`actual_departure` DATETIME NULL,
`notes` TEXT NULL,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_route` (`route_id`),
KEY `idx_stop_number` (`route_id`, `stop_number`),
CONSTRAINT `fk_stop_route` FOREIGN KEY (`route_id`) REFERENCES `#__mokosuitelogistics_routes`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_packages` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`shipment_id` INT UNSIGNED NOT NULL,
`package_number` VARCHAR(50) NOT NULL,
`description` VARCHAR(255) NULL,
`weight_kg` DECIMAL(10,3) NULL,
`length_cm` DECIMAL(8,2) NULL,
`width_cm` DECIMAL(8,2) NULL,
`height_cm` DECIMAL(8,2) NULL,
`declared_value` DECIMAL(10,2) NULL,
`is_fragile` TINYINT(1) NOT NULL DEFAULT 0,
`is_hazmat` TINYINT(1) NOT NULL DEFAULT 0,
`barcode` VARCHAR(255) NULL,
`status` ENUM('created','labeled','in_transit','delivered','damaged','lost') NOT NULL DEFAULT 'created',
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_package_number` (`package_number`),
KEY `idx_shipment` (`shipment_id`),
KEY `idx_status` (`status`),
KEY `idx_barcode` (`barcode`),
CONSTRAINT `fk_package_shipment` FOREIGN KEY (`shipment_id`) REFERENCES `#__mokosuitelogistics_shipments`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuitelogistics_tracking_events` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`shipment_id` INT UNSIGNED NOT NULL,
`package_id` INT UNSIGNED NULL,
`event_type` ENUM('created','picked_up','in_transit','at_hub','out_for_delivery','delivered','exception','returned') NOT NULL,
`location` VARCHAR(255) NULL,
`latitude` DECIMAL(10,7) NULL,
`longitude` DECIMAL(10,7) NULL,
`description` TEXT NULL,
`event_time` DATETIME NOT NULL,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_shipment` (`shipment_id`),
KEY `idx_package` (`package_id`),
KEY `idx_event_type` (`event_type`),
KEY `idx_event_time` (`event_time`),
CONSTRAINT `fk_tracking_shipment` FOREIGN KEY (`shipment_id`) REFERENCES `#__mokosuitelogistics_shipments`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -0,0 +1,8 @@
DROP TABLE IF EXISTS `#__mokosuitelogistics_tracking_events`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_packages`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_route_stops`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_routes`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_shipments`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_warehouse_zones`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_warehouses`;
DROP TABLE IF EXISTS `#__mokosuitelogistics_carriers`;
@@ -0,0 +1,20 @@
<?php
/**
* @copyright (C) 2026 Moko Consulting
* @license GPL-3.0-or-later
*/
namespace MokoConsulting\Plugin\System\MokoSuiteLogistics\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
final class Logistics extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [];
}
}
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="package" method="upgrade">
<name>MokoSuiteLogistics</name>
<packagename>mokosuitelogistics</packagename>
<version>0.0.0</version>
<creationDate>2026-06</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>(C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>Layer 2 — Fleet logistics, shipment tracking, route planning, warehouse management</description>
<files>
<file type="plugin" id="mokosuitelogistics" group="system">plg_system_mokosuitelogistics.zip</file>
<file type="component" id="mokosuitelogistics">com_mokosuitelogistics.zip</file>
<file type="plugin" id="mokosuitelogistics" group="webservices">plg_webservices_mokosuitelogistics.zip</file>
</files>
<updateservers>
<server type="extension" name="MokoSuiteLogistics Updates">https://git.mokoconsulting.tech/api/packages/MokoConsulting/generic/updates/mokosuitelogistics/updates.xml</server>
</updateservers>
</extension>