diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b919835 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.claude/ +.mcp.json +TODO.md +*.min.css +*.min.js diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1e0448f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ + + +# 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 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..eaf695b --- /dev/null +++ b/CLAUDE.md @@ -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 diff --git a/source/packages/com_mokosuitelogistics/admin/access.xml b/source/packages/com_mokosuitelogistics/admin/access.xml new file mode 100644 index 0000000..98f1236 --- /dev/null +++ b/source/packages/com_mokosuitelogistics/admin/access.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + +
+
diff --git a/source/packages/com_mokosuitelogistics/admin/config.xml b/source/packages/com_mokosuitelogistics/admin/config.xml new file mode 100644 index 0000000..ddda8e7 --- /dev/null +++ b/source/packages/com_mokosuitelogistics/admin/config.xml @@ -0,0 +1,6 @@ + + +
+ +
+
diff --git a/source/packages/com_mokosuitelogistics/admin/services/provider.php b/source/packages/com_mokosuitelogistics/admin/services/provider.php new file mode 100644 index 0000000..a7e02a6 --- /dev/null +++ b/source/packages/com_mokosuitelogistics/admin/services/provider.php @@ -0,0 +1,30 @@ +set( + ComponentInterface::class, + function (Container $container) { + $component = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class)); + $component->setMVCFactory($container->get(MVCFactoryInterface::class)); + return $component; + } + ); + } +}; diff --git a/source/packages/com_mokosuitelogistics/mokosuitelogistics.xml b/source/packages/com_mokosuitelogistics/mokosuitelogistics.xml new file mode 100644 index 0000000..0179e6e --- /dev/null +++ b/source/packages/com_mokosuitelogistics/mokosuitelogistics.xml @@ -0,0 +1,32 @@ + + + com_mokosuitelogistics + 0.0.0 + 2026-06 + Moko Consulting + hello@mokoconsulting.tech + https://mokoconsulting.tech + (C) 2026 Moko Consulting + GPL-3.0-or-later + Layer 2 — Fleet logistics, shipment tracking, route planning, warehouse management + MokoConsulting\Component\MokoSuiteLogistics + + + services + src + tmpl + language + access.xml + config.xml + + MokoSuiteLogistics + + Dashboard + Shipments + Routes + Carriers + Warehouses + Packages + + + diff --git a/source/packages/plg_system_mokosuitelogistics/language/en-GB/plg_system_mokosuitelogistics.ini b/source/packages/plg_system_mokosuitelogistics/language/en-GB/plg_system_mokosuitelogistics.ini new file mode 100644 index 0000000..d8af8a0 --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/language/en-GB/plg_system_mokosuitelogistics.ini @@ -0,0 +1,3 @@ +PLG_SYSTEM_MOKOSUITELOGISTICS="Logistics" +PLG_SYSTEM_MOKOSUITELOGISTICS_DESCRIPTION="MokoSuiteLogistics system plugin" +PLG_SYSTEM_MOKOSUITELOGISTICS_ENABLED="Enable MokoSuiteLogistics" diff --git a/source/packages/plg_system_mokosuitelogistics/language/en-GB/plg_system_mokosuitelogistics.sys.ini b/source/packages/plg_system_mokosuitelogistics/language/en-GB/plg_system_mokosuitelogistics.sys.ini new file mode 100644 index 0000000..d8af8a0 --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/language/en-GB/plg_system_mokosuitelogistics.sys.ini @@ -0,0 +1,3 @@ +PLG_SYSTEM_MOKOSUITELOGISTICS="Logistics" +PLG_SYSTEM_MOKOSUITELOGISTICS_DESCRIPTION="MokoSuiteLogistics system plugin" +PLG_SYSTEM_MOKOSUITELOGISTICS_ENABLED="Enable MokoSuiteLogistics" diff --git a/source/packages/plg_system_mokosuitelogistics/mokosuitelogistics.xml b/source/packages/plg_system_mokosuitelogistics/mokosuitelogistics.xml new file mode 100644 index 0000000..7b93a00 --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/mokosuitelogistics.xml @@ -0,0 +1,43 @@ + + + plg_system_mokosuitelogistics + 0.0.0 + 2026-06 + Moko Consulting + hello@mokoconsulting.tech + https://mokoconsulting.tech + (C) 2026 Moko Consulting + GPL-3.0-or-later + MokoSuiteLogistics system plugin -- schema owner and bootstrap + MokoConsulting\Plugin\System\MokoSuiteLogistics + + src + services + sql + language + + + + sql/install.mysql.sql + + + + + sql/uninstall.mysql.sql + + + + en-GB/plg_system_mokosuitelogistics.ini + en-GB/plg_system_mokosuitelogistics.sys.ini + + + +
+ + + + +
+
+
+
diff --git a/source/packages/plg_system_mokosuitelogistics/services/provider.php b/source/packages/plg_system_mokosuitelogistics/services/provider.php new file mode 100644 index 0000000..281d8e8 --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/services/provider.php @@ -0,0 +1,31 @@ +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; + } + ); + } +}; diff --git a/source/packages/plg_system_mokosuitelogistics/sql/install.mysql.sql b/source/packages/plg_system_mokosuitelogistics/sql/install.mysql.sql new file mode 100644 index 0000000..7043444 --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/sql/install.mysql.sql @@ -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; diff --git a/source/packages/plg_system_mokosuitelogistics/sql/uninstall.mysql.sql b/source/packages/plg_system_mokosuitelogistics/sql/uninstall.mysql.sql new file mode 100644 index 0000000..0f24cf1 --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/sql/uninstall.mysql.sql @@ -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`; diff --git a/source/packages/plg_system_mokosuitelogistics/src/Extension/Logistics.php b/source/packages/plg_system_mokosuitelogistics/src/Extension/Logistics.php new file mode 100644 index 0000000..44b061a --- /dev/null +++ b/source/packages/plg_system_mokosuitelogistics/src/Extension/Logistics.php @@ -0,0 +1,20 @@ + + + MokoSuiteLogistics + mokosuitelogistics + 0.0.0 + 2026-06 + Moko Consulting + hello@mokoconsulting.tech + https://mokoconsulting.tech + (C) 2026 Moko Consulting + GPL-3.0-or-later + Layer 2 — Fleet logistics, shipment tracking, route planning, warehouse management + + plg_system_mokosuitelogistics.zip + com_mokosuitelogistics.zip + plg_webservices_mokosuitelogistics.zip + + + https://git.mokoconsulting.tech/api/packages/MokoConsulting/generic/updates/mokosuitelogistics/updates.xml + +