01 ยท Technical requirements

How it should work, technically

The existing PHP + SQLite system documented as-built, plus requirements, data model and constraints for the Orders & Dispatch module and its agentic layer.

Existing system + new module๐Ÿ“„ TRD.mdVersion 1.0 ยท 4 October 2026 Covers: the existing app (ยง1โ€“4), the new Orders & Dispatch module (ยง5โ€“9), the Dashboard + Hermes reminders (ยง5.11) and the agentic layer (ยง10).

1Project Overview

Skycrest Stock Control is a private web app for the Skycrest / Annie Makes Cakes kitchen in Marrickville, NSW. It tracks finished-goods stock by product code, plans production against airline orders, and manages tartlet-shell orders. The next step is an Orders & Dispatch module that takes every customer order โ€” airline and non-airline โ€” from intake through allocation to dispatch, and automatically removes dispatched goods from stock.

2Technical Goals

3Tech Stack (existing โ€” keep)

LayerChoiceNotes
LanguagePHP 8.xSingle entry point stock_control.php
DatabaseSQLite 3 via PDO (stock.db, same folder)ERRMODE_EXCEPTION, FETCH_ASSOC
FrontendServer-rendered HTML + inline CSS + vanilla JSNo framework, no build step
AuthPHP sessions, password_hash / password_verifyRoles: admin, user
Spreadsheet I/OZipArchive + SimpleXML (read), hand-built XLSX writer (export)No Composer dependencies
HostingShared host, nginx, skycrest.idDeploy by FTP (passive)
PrintingBrowser print with @media print rulesPlan and Tartlet pages

Decision for new work: keep the same stack. To control file size, new module code goes in includes/orders.php (and similar), required from stock_control.php. The URL scheme (?page=โ€ฆ, ?api=โ€ฆ, POST action=โ€ฆ) stays the same.

4Existing System โ€” Functional Summary

4.1 Request routing

  1. ?api=<name> โ†’ JSON endpoint (auth required). Returns {ok:true,โ€ฆ} or {error:"โ€ฆ"}.
  2. POST action=<name> โ†’ form handler โ†’ flash message โ†’ redirect (Post/Redirect/Get).
  3. Otherwise โ†’ renderLogin() if not signed in, else renderDashboard() which switches on ?page= (stock default, products, plan, tartlets, users).

4.2 Stock model

4.3 Existing data model

TablePurposeKey columns
usersLoginsusername (unique), password (hash), role
productsCatalogcode (PK), name, category, subcategory, pack_size, base_stock
transactionsStock ledgerproduct_code, type in/out, quantity, note, username, created_at
plan_itemsRows on Production Planningcode, name, category, ctn_qty, sort_order
plan_datesColumns on Production Planningdest_code, dest_label (SYD/MEL/BNE/ADLโ€ฆ), order_date
plan_ordersCell valuesitem_code, plan_date_id, qty_units, cell_color
saved_plans, saved_plan_orders, saved_plan_datesPlan snapshotsโ€”
tartlet_ordersTartlet client ordersclient_name, due_datetime, delivery_type, notes
tartlet_order_linesQty per tartlet sizeorder_id, size_code, qty, cell_color
saved_tartlet_plans, โ€ฆ_orders, โ€ฆ_linesTartlet snapshotsโ€”
settingsKey-valuee.g. tartlet "as at" date

4.4 Existing JSON APIs

search, product, set_stock, apply_xlsm_sync, discard_xlsm_preview; plan: add_plan_date, delete_plan_date, update_plan_dest, add_plan_week, save_plan_order, update_plan_date, list_plans, save_plan, load_plan, delete_saved_plan; tartlets: save_tartlet_line, save_tartlet_color, save_tartlet_order, add_tartlet_order, delete_tartlet_order, save_tartlet_asat, save_tartlet_plan, load_tartlet_plan, delete_tartlet_plan.

4.5 Existing form actions

login, logout, transaction, export, add_user, edit_user, delete_user, change_password, add_product, edit_product, delete_product, upload_xlsm.


5New Module โ€” Orders & Dispatch: Functional Requirements

Source: workflow.xlsx (two swim-lanes: Airline and Non-airline).

5.1 Customers

5.2 Order intake

5.3 Invoicing (manual in V1)

5.5 Kitchen ticket and confirmation

5.6 Packing check and allocation

5.7 Delivery schedule (day before dispatch)

5.8 Dispatch

5.8a Dispatch record (replaces the Excel "Dispatch Record" sheet)

5.9 Order status lifecycle

NEW โ†’ INVOICED โ†’ IN_KITCHEN โ†’ CONFIRMED_SENT โ†’ ALLOCATED โ”€โ”
                                    โ”‚                      โ”œโ†’ SCHEDULED โ†’ DISPATCHED
                                    โ””โ†’ SHORT โ†’ (made) โ”€โ”€โ”€โ”€โ”€โ”˜
Any state (before DISPATCHED) โ†’ CANCELLED (releases allocations)

5.11 Dashboard and staff reminders (spec: DASHBOARD.md)

5.12 Airline analytics (basis: AIRLINE_ANALYSIS.md)

5.10 Roles

App roles map to the managerial dashboards in DASHBOARD.md ยง2.3: savoury_prod (Alex), sweets_prod (Annie & sweets team), office_mgr (Ruth), gm (Mark), director (Tisna, Heri, Vivi โ€” read-only), packing, plus admin. In the table below, user (office) = Ruth's team; production managers can allocate and mark short; GM has admin-level overrides; directors view only.

Actionadminuser (office)packing (new)
Customers CRUDโœ…viewview
Create / edit orderโœ…โœ…โŒ
Record invoice no.โœ…โœ…โŒ
Allocate / mark shortโœ…โœ…โœ…
Schedule / booking refsโœ…โœ…view
Dispatchโœ…โœ…โœ…
Undo dispatch, overrideโœ…โŒโŒ

6Data Requirements (new tables โ€” additive only)

CREATE TABLE IF NOT EXISTS customers (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  entity TEXT NOT NULL DEFAULT 'ANNIE',        -- SKYCREST | ANNIE
  channel TEXT NOT NULL DEFAULT 'NON_AIRLINE', -- AIRLINE | NON_AIRLINE
  port TEXT DEFAULT '',                        -- SYD | MEL | BNE | ADL ...
  email TEXT DEFAULT '', phone TEXT DEFAULT '', address TEXT DEFAULT '',
  notes TEXT DEFAULT '', active INTEGER DEFAULT 1,
  created_at TEXT DEFAULT (datetime('now','localtime'))
);
CREATE TABLE IF NOT EXISTS orders (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  order_no TEXT UNIQUE,                        -- ORD-000123
  customer_id INTEGER NOT NULL,
  po_number TEXT DEFAULT '', source TEXT DEFAULT 'EMAIL_PO',
  order_date TEXT NOT NULL, dispatch_date TEXT NOT NULL,
  delivery_method TEXT DEFAULT 'DELIVERY', port TEXT DEFAULT '',
  status TEXT NOT NULL DEFAULT 'NEW',
  xero_invoice_no TEXT DEFAULT '',
  confirmed_at TEXT DEFAULT '', booking_type TEXT DEFAULT '',  -- ROADMASTER | DRIVER | PICKUP
  booking_ref TEXT DEFAULT '', booked_at TEXT DEFAULT '',
  dispatched_at TEXT DEFAULT '', dispatched_by TEXT DEFAULT '',
  notes TEXT DEFAULT '', created_by TEXT DEFAULT '',
  created_at TEXT DEFAULT (datetime('now','localtime'))
);
CREATE TABLE IF NOT EXISTS order_lines (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  order_id INTEGER NOT NULL,
  product_code TEXT DEFAULT '',               -- '' for bespoke free text
  description TEXT DEFAULT '',
  qty_units INTEGER NOT NULL DEFAULT 0,
  qty_dispatched INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS allocations (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  order_line_id INTEGER NOT NULL, product_code TEXT NOT NULL,
  qty_units INTEGER NOT NULL, username TEXT DEFAULT '',
  created_at TEXT DEFAULT (datetime('now','localtime'))
);
CREATE TABLE IF NOT EXISTS order_attachments (
  id INTEGER PRIMARY KEY AUTOINCREMENT, order_id INTEGER NOT NULL,
  filename TEXT NOT NULL, stored_path TEXT NOT NULL, mime TEXT DEFAULT '',
  uploaded_by TEXT DEFAULT '', created_at TEXT DEFAULT (datetime('now','localtime'))
);
CREATE TABLE IF NOT EXISTS order_events (       -- audit trail
  id INTEGER PRIMARY KEY AUTOINCREMENT, order_id INTEGER NOT NULL,
  event TEXT NOT NULL, detail TEXT DEFAULT '', username TEXT DEFAULT '',
  created_at TEXT DEFAULT (datetime('now','localtime'))
);
CREATE INDEX IF NOT EXISTS idx_orders_dispatch ON orders(dispatch_date, status);
CREATE INDEX IF NOT EXISTS idx_lines_order ON order_lines(order_id);
CREATE INDEX IF NOT EXISTS idx_alloc_code ON allocations(product_code);
CREATE INDEX IF NOT EXISTS idx_tx_code ON transactions(product_code);

7Non-Functional Requirements

8Integrations

IntegrationV1V2 (later)
Xero (SkyCrest + Annie Makes Cakes orgs)Record invoice number manuallyXero API: create draft invoice from order, store invoice ID
Email (orders in)Manual entry + attach POMailbox polling: template parsers for dnata / Gate Gourmet POs, AI for non-airline
Hermes Agent (VPS)Staff reminders: WhatsApp / Telegram / SMS / callAI voice calls (Vapi / Bland.ai)
TwilioAustralian number for SMS + calls (via Hermes telephony skill)โ€”
Email (confirmation out)Generate text, mailto: / copySMTP send from app with template
Roadmaster / driversRecord booking refโ€”
Stock Control.xlsmExisting manual Sync from XLSMโ€”

9Constraints

10Agentic Layer (summary โ€” full spec in AGENTIC.md)

11Definition of Done (Orders & Dispatch V1)