diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c8a642e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.claude/
+.mcp.json
+TODO.md
+*.min.css
+*.min.js
+vendor/
+node_modules/
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e8b6077
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,19 @@
+
+
+# Changelog
+
+## [Unreleased]
+
+### Added
+- **Repository** -- initial scaffold
+- **System Plugin** -- Extension class, service provider
+- **SQL Schema** -- 8 tables: locations, services, staff, schedules, availability_overrides, bookings, booking_services, waitlist
+- **Admin Component** -- 6 views: dashboard, bookings, services, staff, schedules, locations
+- **Webservices Plugin** -- 7 API routes
+- **Configuration** -- plugin settings across 4 fieldsets
+- **Access Control** -- granular permissions
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..c3d59f0
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,30 @@
+# MokoSuitebooking
+
+Appointment and resource booking for service businesses for Joomla 6.
+
+## Quick Reference
+
+| Field | Value |
+|---|---|
+| **Package** | `pkg_mokosuitebooking` |
+| **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 clients, service catalog with staff scheduling and online booking.
+
+## 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
\ No newline at end of file
diff --git a/README.md b/README.md
index 15091a1..73b9b27 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,45 @@
-# MokoSuiteBooking
+
-MokoSuite Booking — appointment and resource booking for service businesses on Joomla 6
\ No newline at end of file
+# MokoSuite booking
+
+Appointment and resource booking for service businesses for MokoSuite on Joomla 6.
+
+## Overview
+
+MokoSuitebooking is a **Layer 2** extension in the MokoSuite platform, building on MokoSuiteClient (Layer 0) and MokoSuiteCRM (Layer 1).
+
+## Features
+
+- **Service Catalog** -- services with duration, pricing, staff assignment
+- **Online Booking** -- real-time availability with booking widget
+- **Staff Scheduling** -- recurring availability patterns with overrides
+- **Multi-Location** -- support for multiple business locations
+- **Walk-In Queue** -- walk-in queue management
+- **Client History** -- CRM contact-linked visit frequency and spend tracking
+- **Waitlist** -- automated notification when slots open
+- **REST API** -- full CRUD for services, staff, bookings, schedules, locations
+- **Access Control** -- granular permissions
+
+## Requirements
+
+- Joomla 6.x
+- PHP 8.3+
+- MokoSuiteClient (Layer 0)
+- MokoSuiteCRM (Layer 1)
+
+## Installation
+
+Install via Joomla Extension Manager using the package file `pkg_mokosuitebooking.zip`.
+
+## License
+
+GNU General Public License v3.0 or later.
+
+## Links
+
+- [Documentation](https://git.mokoconsulting.tech/MokoConsulting/MokoSuitebooking/wiki)
+- [Issues](https://git.mokoconsulting.tech/MokoConsulting/MokoSuitebooking/issues)
+- [MokoSuite Platform](https://mokoconsulting.tech)
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/access.xml b/source/packages/com_mokosuitebooking/admin/access.xml
new file mode 100644
index 0000000..3b7b618
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/access.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/config.xml b/source/packages/com_mokosuitebooking/admin/config.xml
new file mode 100644
index 0000000..4cf87ad
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/config.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/language/en-GB/com_mokosuitebooking.ini b/source/packages/com_mokosuitebooking/admin/language/en-GB/com_mokosuitebooking.ini
new file mode 100644
index 0000000..13443bb
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/language/en-GB/com_mokosuitebooking.ini
@@ -0,0 +1,9 @@
+; Copyright (C) 2026 Moko Consulting
+; SPDX-License-Identifier: GPL-3.0-or-later
+COM_MOKOSUITEBOOKING="MokoSuite Booking"
+COM_MOKOSUITEBOOKING_DASHBOARD="Dashboard"
+COM_MOKOSUITEBOOKING_BOOKINGS="Bookings"
+COM_MOKOSUITEBOOKING_SERVICES="Services"
+COM_MOKOSUITEBOOKING_STAFF="Staff"
+COM_MOKOSUITEBOOKING_SCHEDULES="Schedules"
+COM_MOKOSUITEBOOKING_LOCATIONS="Locations"
diff --git a/source/packages/com_mokosuitebooking/admin/language/en-GB/com_mokosuitebooking.sys.ini b/source/packages/com_mokosuitebooking/admin/language/en-GB/com_mokosuitebooking.sys.ini
new file mode 100644
index 0000000..8efe74e
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/language/en-GB/com_mokosuitebooking.sys.ini
@@ -0,0 +1,4 @@
+; Copyright (C) 2026 Moko Consulting
+; SPDX-License-Identifier: GPL-3.0-or-later
+COM_MOKOSUITEBOOKING="MokoSuite Booking"
+COM_MOKOSUITEBOOKING_XML_DESCRIPTION="Appointment and resource booking"
diff --git a/source/packages/com_mokosuitebooking/admin/services/provider.php b/source/packages/com_mokosuitebooking/admin/services/provider.php
new file mode 100644
index 0000000..cc30d87
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/services/provider.php
@@ -0,0 +1,28 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Extension\ComponentInterface;
+use Joomla\CMS\Extension\MVCComponent;
+use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
+use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
+use Joomla\CMS\Component\Router\RouterFactoryInterface;
+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) {
+ $c = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class));
+ $c->setMVCFactory($container->get(MVCFactoryInterface::class));
+ $c->setRouterFactory($container->get(RouterFactoryInterface::class));
+ return $c;
+ });
+ }
+};
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/Controller/DisplayController.php b/source/packages/com_mokosuitebooking/admin/src/Controller/DisplayController.php
new file mode 100644
index 0000000..e5303c7
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/Controller/DisplayController.php
@@ -0,0 +1,18 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\Controller;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\Controller\BaseController;
+
+class DisplayController extends BaseController
+{
+ protected $default_view = 'bookingdashboard';
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/Model/BookingDashboardModel.php b/source/packages/com_mokosuitebooking/admin/src/Model/BookingDashboardModel.php
new file mode 100644
index 0000000..09dcebf
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/Model/BookingDashboardModel.php
@@ -0,0 +1,17 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\Model;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\Model\BaseDatabaseModel;
+
+class BookingDashboardModel extends BaseDatabaseModel
+{
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/View/BookingBookings/HtmlView.php b/source/packages/com_mokosuitebooking/admin/src/View/BookingBookings/HtmlView.php
new file mode 100644
index 0000000..4839094
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/View/BookingBookings/HtmlView.php
@@ -0,0 +1,23 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingBookings;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Toolbar\ToolbarHelper;
+
+class HtmlView extends BaseHtmlView
+{
+ public function display($tpl = null): void
+ {
+ ToolbarHelper::title('MokoSuite Booking - Bookings');
+ parent::display($tpl);
+ }
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/View/BookingDashboard/HtmlView.php b/source/packages/com_mokosuitebooking/admin/src/View/BookingDashboard/HtmlView.php
new file mode 100644
index 0000000..fc55501
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/View/BookingDashboard/HtmlView.php
@@ -0,0 +1,23 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingDashboard;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Toolbar\ToolbarHelper;
+
+class HtmlView extends BaseHtmlView
+{
+ public function display($tpl = null): void
+ {
+ ToolbarHelper::title('MokoSuite Booking - Dashboard');
+ parent::display($tpl);
+ }
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/View/BookingLocations/HtmlView.php b/source/packages/com_mokosuitebooking/admin/src/View/BookingLocations/HtmlView.php
new file mode 100644
index 0000000..f24cca7
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/View/BookingLocations/HtmlView.php
@@ -0,0 +1,23 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingLocations;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Toolbar\ToolbarHelper;
+
+class HtmlView extends BaseHtmlView
+{
+ public function display($tpl = null): void
+ {
+ ToolbarHelper::title('MokoSuite Booking - Locations');
+ parent::display($tpl);
+ }
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/View/BookingSchedules/HtmlView.php b/source/packages/com_mokosuitebooking/admin/src/View/BookingSchedules/HtmlView.php
new file mode 100644
index 0000000..fdf500f
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/View/BookingSchedules/HtmlView.php
@@ -0,0 +1,23 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingSchedules;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Toolbar\ToolbarHelper;
+
+class HtmlView extends BaseHtmlView
+{
+ public function display($tpl = null): void
+ {
+ ToolbarHelper::title('MokoSuite Booking - Schedules');
+ parent::display($tpl);
+ }
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/View/BookingServices/HtmlView.php b/source/packages/com_mokosuitebooking/admin/src/View/BookingServices/HtmlView.php
new file mode 100644
index 0000000..1e28e08
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/View/BookingServices/HtmlView.php
@@ -0,0 +1,23 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingServices;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Toolbar\ToolbarHelper;
+
+class HtmlView extends BaseHtmlView
+{
+ public function display($tpl = null): void
+ {
+ ToolbarHelper::title('MokoSuite Booking - Services');
+ parent::display($tpl);
+ }
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/src/View/BookingStaff/HtmlView.php b/source/packages/com_mokosuitebooking/admin/src/View/BookingStaff/HtmlView.php
new file mode 100644
index 0000000..5c9ed61
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/src/View/BookingStaff/HtmlView.php
@@ -0,0 +1,23 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingStaff;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Toolbar\ToolbarHelper;
+
+class HtmlView extends BaseHtmlView
+{
+ public function display($tpl = null): void
+ {
+ ToolbarHelper::title('MokoSuite Booking - Staff');
+ parent::display($tpl);
+ }
+}
\ No newline at end of file
diff --git a/source/packages/com_mokosuitebooking/admin/tmpl/bookingbookings/default.php b/source/packages/com_mokosuitebooking/admin/tmpl/bookingbookings/default.php
new file mode 100644
index 0000000..1db369e
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/tmpl/bookingbookings/default.php
@@ -0,0 +1,11 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+defined('_JEXEC') or die;
+?>
+
+
Bookings
+
Coming soon.
+
diff --git a/source/packages/com_mokosuitebooking/admin/tmpl/bookingdashboard/default.php b/source/packages/com_mokosuitebooking/admin/tmpl/bookingdashboard/default.php
new file mode 100644
index 0000000..a69f273
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/tmpl/bookingdashboard/default.php
@@ -0,0 +1,11 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+defined('_JEXEC') or die;
+?>
+
+
Dashboard
+
Coming soon.
+
diff --git a/source/packages/com_mokosuitebooking/admin/tmpl/bookinglocations/default.php b/source/packages/com_mokosuitebooking/admin/tmpl/bookinglocations/default.php
new file mode 100644
index 0000000..070f7c4
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/tmpl/bookinglocations/default.php
@@ -0,0 +1,11 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+defined('_JEXEC') or die;
+?>
+
+
Locations
+
Coming soon.
+
diff --git a/source/packages/com_mokosuitebooking/admin/tmpl/bookingschedules/default.php b/source/packages/com_mokosuitebooking/admin/tmpl/bookingschedules/default.php
new file mode 100644
index 0000000..5c6526d
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/tmpl/bookingschedules/default.php
@@ -0,0 +1,11 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+defined('_JEXEC') or die;
+?>
+
+
Schedules
+
Coming soon.
+
diff --git a/source/packages/com_mokosuitebooking/admin/tmpl/bookingservices/default.php b/source/packages/com_mokosuitebooking/admin/tmpl/bookingservices/default.php
new file mode 100644
index 0000000..9ae829b
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/tmpl/bookingservices/default.php
@@ -0,0 +1,11 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+defined('_JEXEC') or die;
+?>
+
+
Services
+
Coming soon.
+
diff --git a/source/packages/com_mokosuitebooking/admin/tmpl/bookingstaff/default.php b/source/packages/com_mokosuitebooking/admin/tmpl/bookingstaff/default.php
new file mode 100644
index 0000000..2ca1ab2
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/admin/tmpl/bookingstaff/default.php
@@ -0,0 +1,11 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+defined('_JEXEC') or die;
+?>
+
diff --git a/source/packages/com_mokosuitebooking/mokosuitebooking.xml b/source/packages/com_mokosuitebooking/mokosuitebooking.xml
new file mode 100644
index 0000000..859c553
--- /dev/null
+++ b/source/packages/com_mokosuitebooking/mokosuitebooking.xml
@@ -0,0 +1,36 @@
+
+
+ MokoSuite Booking
+ Moko Consulting
+ hello@mokoconsulting.tech
+ https://mokoconsulting.tech
+ 2026-06-27
+ Copyright (C) 2026 Moko Consulting.
+ GPL-3.0-or-later
+ 06.00.00
+ Appointment and resource booking
+ Moko\Component\MokoSuiteBooking
+
+
+ access.xml
+ config.xml
+ language
+ services
+ src
+ tmpl
+
+
+ en-GB/com_mokosuitebooking.ini
+ en-GB/com_mokosuitebooking.sys.ini
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/packages/plg_system_mokosuitebooking/language/en-GB/plg_system_mokosuitebooking.ini b/source/packages/plg_system_mokosuitebooking/language/en-GB/plg_system_mokosuitebooking.ini
new file mode 100644
index 0000000..764b0bb
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/language/en-GB/plg_system_mokosuitebooking.ini
@@ -0,0 +1,4 @@
+; Copyright (C) 2026 Moko Consulting
+; SPDX-License-Identifier: GPL-3.0-or-later
+PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuite Booking"
+PLG_SYSTEM_MOKOSUITEBOOKING_DESC="Appointment booking helpers and schema"
diff --git a/source/packages/plg_system_mokosuitebooking/language/en-GB/plg_system_mokosuitebooking.sys.ini b/source/packages/plg_system_mokosuitebooking/language/en-GB/plg_system_mokosuitebooking.sys.ini
new file mode 100644
index 0000000..764b0bb
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/language/en-GB/plg_system_mokosuitebooking.sys.ini
@@ -0,0 +1,4 @@
+; Copyright (C) 2026 Moko Consulting
+; SPDX-License-Identifier: GPL-3.0-or-later
+PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuite Booking"
+PLG_SYSTEM_MOKOSUITEBOOKING_DESC="Appointment booking helpers and schema"
diff --git a/source/packages/plg_system_mokosuitebooking/mokosuitebooking.xml b/source/packages/plg_system_mokosuitebooking/mokosuitebooking.xml
new file mode 100644
index 0000000..dd0be81
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/mokosuitebooking.xml
@@ -0,0 +1,59 @@
+
+
+ System - MokoSuite Booking
+ mokosuitebooking
+ Moko Consulting
+ 2026-06-27
+ Copyright (C) 2026 Moko Consulting. All rights reserved.
+ GPL-3.0-or-later
+ hello@mokoconsulting.tech
+ https://mokoconsulting.tech
+ 06.00.00
+ 8.3
+ PLG_SYSTEM_MOKOSUITEBOOKING_DESC
+ Moko\Plugin\System\MokoSuiteBooking
+
+ src
+ services
+ language
+ sql
+
+
+ en-GB/plg_system_mokosuitebooking.ini
+ en-GB/plg_system_mokosuitebooking.sys.ini
+
+ sql/install.mysql.sql
+ sql/uninstall.mysql.sql
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/packages/plg_system_mokosuitebooking/services/provider.php b/source/packages/plg_system_mokosuitebooking/services/provider.php
new file mode 100644
index 0000000..f210625
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/services/provider.php
@@ -0,0 +1,27 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Extension\PluginInterface;
+use Joomla\CMS\Plugin\PluginHelper;
+use Joomla\DI\Container;
+use Joomla\DI\ServiceProviderInterface;
+use Joomla\Event\DispatcherInterface;
+use Moko\Plugin\System\MokoSuiteBooking\Extension\Booking;
+
+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 Booking($dispatcher, (array) PluginHelper::getPlugin('system', 'mokosuitebooking'));
+ $plugin->setApplication(\Joomla\CMS\Factory::getApplication());
+ return $plugin;
+ });
+ }
+};
\ No newline at end of file
diff --git a/source/packages/plg_system_mokosuitebooking/sql/install.mysql.sql b/source/packages/plg_system_mokosuitebooking/sql/install.mysql.sql
new file mode 100644
index 0000000..3b479af
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/sql/install.mysql.sql
@@ -0,0 +1,163 @@
+--
+-- MokoSuite Booking Tables
+--
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_locations` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(255) NOT NULL,
+ `address` VARCHAR(500) NOT NULL DEFAULT '',
+ `city` VARCHAR(100) NOT NULL DEFAULT '',
+ `state` VARCHAR(100) NOT NULL DEFAULT '',
+ `postal_code` VARCHAR(20) NOT NULL DEFAULT '',
+ `country` VARCHAR(100) NOT NULL DEFAULT '',
+ `timezone` VARCHAR(50) NOT NULL DEFAULT 'America/New_York',
+ `phone` VARCHAR(50) NOT NULL DEFAULT '',
+ `email` VARCHAR(255) NOT NULL DEFAULT '',
+ `photo` VARCHAR(500) NOT NULL DEFAULT '',
+ `notes` TEXT,
+ `published` TINYINT NOT NULL DEFAULT 1,
+ `ordering` INT NOT NULL DEFAULT 0,
+ `created` DATETIME NOT NULL,
+ `created_by` INT NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_services` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(255) NOT NULL,
+ `description` TEXT,
+ `category` VARCHAR(100) NOT NULL DEFAULT '',
+ `duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 30,
+ `buffer_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
+ `price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
+ `currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
+ `max_attendees` SMALLINT UNSIGNED NOT NULL DEFAULT 1,
+ `requires_deposit` TINYINT NOT NULL DEFAULT 0,
+ `deposit_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
+ `color` VARCHAR(7) NOT NULL DEFAULT '#3788d8',
+ `photo` VARCHAR(500) NOT NULL DEFAULT '',
+ `published` TINYINT NOT NULL DEFAULT 1,
+ `ordering` INT NOT NULL DEFAULT 0,
+ `created` DATETIME NOT NULL,
+ `created_by` INT NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ KEY `idx_category` (`category`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_staff` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `contact_id` INT DEFAULT NULL,
+ `user_id` INT DEFAULT NULL,
+ `display_name` VARCHAR(255) NOT NULL,
+ `title` VARCHAR(255) NOT NULL DEFAULT '',
+ `email` VARCHAR(255) NOT NULL DEFAULT '',
+ `phone` VARCHAR(50) NOT NULL DEFAULT '',
+ `bio` TEXT,
+ `photo` VARCHAR(500) NOT NULL DEFAULT '',
+ `color` VARCHAR(7) NOT NULL DEFAULT '#3788d8',
+ `services_json` JSON DEFAULT NULL,
+ `locations_json` JSON DEFAULT NULL,
+ `published` TINYINT NOT NULL DEFAULT 1,
+ `ordering` INT NOT NULL DEFAULT 0,
+ `created` DATETIME NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx_contact` (`contact_id`),
+ KEY `idx_user` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_schedules` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `staff_id` INT UNSIGNED NOT NULL,
+ `location_id` INT UNSIGNED DEFAULT NULL,
+ `day_of_week` TINYINT UNSIGNED NOT NULL,
+ `start_time` TIME NOT NULL,
+ `end_time` TIME NOT NULL,
+ `effective_from` DATE DEFAULT NULL,
+ `effective_until` DATE DEFAULT NULL,
+ `published` TINYINT NOT NULL DEFAULT 1,
+ PRIMARY KEY (`id`),
+ KEY `idx_staff` (`staff_id`),
+ KEY `idx_location` (`location_id`),
+ KEY `idx_day` (`day_of_week`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_availability_overrides` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `staff_id` INT UNSIGNED NOT NULL,
+ `override_date` DATE NOT NULL,
+ `available` TINYINT NOT NULL DEFAULT 0,
+ `start_time` TIME DEFAULT NULL,
+ `end_time` TIME DEFAULT NULL,
+ `reason` VARCHAR(255) NOT NULL DEFAULT '',
+ `created` DATETIME NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx_staff_date` (`staff_id`, `override_date`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_bookings` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `booking_ref` VARCHAR(20) NOT NULL,
+ `contact_id` INT DEFAULT NULL,
+ `staff_id` INT UNSIGNED DEFAULT NULL,
+ `location_id` INT UNSIGNED DEFAULT NULL,
+ `customer_name` VARCHAR(255) NOT NULL,
+ `customer_email` VARCHAR(255) NOT NULL DEFAULT '',
+ `customer_phone` VARCHAR(50) NOT NULL DEFAULT '',
+ `booking_date` DATE NOT NULL,
+ `start_time` TIME NOT NULL,
+ `end_time` TIME NOT NULL,
+ `status` ENUM('pending','confirmed','in_progress','completed','cancelled','no_show') NOT NULL DEFAULT 'pending',
+ `total_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
+ `deposit_paid` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
+ `payment_status` ENUM('unpaid','partial','paid','refunded') NOT NULL DEFAULT 'unpaid',
+ `notes` TEXT,
+ `internal_notes` TEXT,
+ `source` ENUM('admin','website','api','walk_in') NOT NULL DEFAULT 'admin',
+ `cancelled_at` DATETIME DEFAULT NULL,
+ `cancellation_reason` VARCHAR(500) NOT NULL DEFAULT '',
+ `reminder_sent` TINYINT NOT NULL DEFAULT 0,
+ `created` DATETIME NOT NULL,
+ `created_by` INT NOT NULL DEFAULT 0,
+ `modified` DATETIME DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_ref` (`booking_ref`),
+ KEY `idx_contact` (`contact_id`),
+ KEY `idx_staff` (`staff_id`),
+ KEY `idx_location` (`location_id`),
+ KEY `idx_date` (`booking_date`),
+ KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_booking_services` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `booking_id` INT UNSIGNED NOT NULL,
+ `service_id` INT UNSIGNED NOT NULL,
+ `staff_id` INT UNSIGNED DEFAULT NULL,
+ `price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
+ `duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 30,
+ PRIMARY KEY (`id`),
+ KEY `idx_booking` (`booking_id`),
+ KEY `idx_service` (`service_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_waitlist` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `contact_id` INT DEFAULT NULL,
+ `service_id` INT UNSIGNED NOT NULL,
+ `staff_id` INT UNSIGNED DEFAULT NULL,
+ `location_id` INT UNSIGNED DEFAULT NULL,
+ `customer_name` VARCHAR(255) NOT NULL,
+ `customer_email` VARCHAR(255) NOT NULL DEFAULT '',
+ `customer_phone` VARCHAR(50) NOT NULL DEFAULT '',
+ `preferred_date_start` DATE DEFAULT NULL,
+ `preferred_date_end` DATE DEFAULT NULL,
+ `preferred_time_start` TIME DEFAULT NULL,
+ `preferred_time_end` TIME DEFAULT NULL,
+ `status` ENUM('waiting','notified','booked','expired','cancelled') NOT NULL DEFAULT 'waiting',
+ `notified_at` DATETIME DEFAULT NULL,
+ `notes` TEXT,
+ `created` DATETIME NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx_service` (`service_id`),
+ KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/source/packages/plg_system_mokosuitebooking/sql/uninstall.mysql.sql b/source/packages/plg_system_mokosuitebooking/sql/uninstall.mysql.sql
new file mode 100644
index 0000000..1b1d773
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/sql/uninstall.mysql.sql
@@ -0,0 +1,12 @@
+--
+-- MokoSuite Booking — Uninstall
+--
+
+DROP TABLE IF EXISTS `#__mokosuitebooking_waitlist`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_booking_services`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_bookings`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_availability_overrides`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_schedules`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_staff`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_services`;
+DROP TABLE IF EXISTS `#__mokosuitebooking_locations`;
\ No newline at end of file
diff --git a/source/packages/plg_system_mokosuitebooking/src/Extension/Booking.php b/source/packages/plg_system_mokosuitebooking/src/Extension/Booking.php
new file mode 100644
index 0000000..a49c2d9
--- /dev/null
+++ b/source/packages/plg_system_mokosuitebooking/src/Extension/Booking.php
@@ -0,0 +1,22 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Plugin\System\MokoSuiteBooking\Extension;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Plugin\CMSPlugin;
+use Joomla\Event\SubscriberInterface;
+
+class Booking extends CMSPlugin implements SubscriberInterface
+{
+ public static function getSubscribedEvents(): array
+ {
+ return [];
+ }
+}
\ No newline at end of file
diff --git a/source/packages/plg_webservices_mokosuitebooking/mokosuitebooking.xml b/source/packages/plg_webservices_mokosuitebooking/mokosuitebooking.xml
new file mode 100644
index 0000000..45c2880
--- /dev/null
+++ b/source/packages/plg_webservices_mokosuitebooking/mokosuitebooking.xml
@@ -0,0 +1,15 @@
+
+
+ Web Services - MokoSuite Booking
+ mokosuitebooking
+ Moko Consulting
+ hello@mokoconsulting.tech
+ https://mokoconsulting.tech
+ 2026-06-27
+ Copyright (C) 2026 Moko Consulting.
+ 06.00.00
+ GPL-3.0-or-later
+ REST API routes for MokoSuite Booking operations
+ Moko\Plugin\WebServices\MokoSuiteBooking
+ srcservices
+
\ No newline at end of file
diff --git a/source/packages/plg_webservices_mokosuitebooking/services/provider.php b/source/packages/plg_webservices_mokosuitebooking/services/provider.php
new file mode 100644
index 0000000..6be452f
--- /dev/null
+++ b/source/packages/plg_webservices_mokosuitebooking/services/provider.php
@@ -0,0 +1,25 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Extension\PluginInterface;
+use Joomla\CMS\Plugin\PluginHelper;
+use Joomla\DI\Container;
+use Joomla\DI\ServiceProviderInterface;
+use Joomla\Event\DispatcherInterface;
+use Moko\Plugin\WebServices\MokoSuiteBooking\Extension\MokoSuiteBooking;
+
+return new class implements ServiceProviderInterface {
+ public function register(Container $container): void {
+ $container->set(PluginInterface::class, function (Container $container) {
+ $dispatcher = $container->get(DispatcherInterface::class);
+ return new MokoSuiteBooking($dispatcher, (array) PluginHelper::getPlugin('webservices', 'mokosuitebooking'));
+ });
+ }
+};
\ No newline at end of file
diff --git a/source/packages/plg_webservices_mokosuitebooking/src/Extension/MokoSuiteBooking.php b/source/packages/plg_webservices_mokosuitebooking/src/Extension/MokoSuiteBooking.php
new file mode 100644
index 0000000..4d2ce96
--- /dev/null
+++ b/source/packages/plg_webservices_mokosuitebooking/src/Extension/MokoSuiteBooking.php
@@ -0,0 +1,43 @@
+
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * Authored-by: Moko Consulting
+ */
+
+namespace Moko\Plugin\WebServices\MokoSuiteBooking\Extension;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Plugin\CMSPlugin;
+use Joomla\CMS\Router\ApiRouter;
+use Joomla\Event\SubscriberInterface;
+
+class MokoSuiteBooking extends CMSPlugin implements SubscriberInterface
+{
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ 'onBeforeApiRoute' => 'onBeforeApiRoute',
+ ];
+ }
+
+ public function onBeforeApiRoute($event): void
+ {
+ $router = $event->getArgument('router');
+
+ $routes = [
+ 'services', 'staff', 'bookings', 'schedules',
+ 'locations', 'availability', 'waitlist',
+ ];
+
+ foreach ($routes as $route) {
+ $router->createCRUDRoutes(
+ "v1/booking/{$route}",
+ $route,
+ ['component' => 'com_mokosuitebooking']
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/pkg_mokosuitebooking.xml b/source/pkg_mokosuitebooking.xml
new file mode 100644
index 0000000..cd945f3
--- /dev/null
+++ b/source/pkg_mokosuitebooking.xml
@@ -0,0 +1,24 @@
+
+
+ Package - MokoSuite Booking
+ mokosuitebooking
+ 06.00.00
+ 2026-06-27
+ Moko Consulting
+ hello@mokoconsulting.tech
+ https://mokoconsulting.tech
+ Copyright (C) 2026 Moko Consulting. All rights reserved.
+ GNU General Public License version 3 or later; see LICENSE
+ Appointment and resource booking for service businesses
+ 8.3
+
+ true
+
+ plg_system_mokosuitebooking.zip
+ com_mokosuitebooking.zip
+ plg_webservices_mokosuitebooking.zip
+
+
+ https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBooking/updates.xml
+
+
\ No newline at end of file