MenuMatic - install
===================
What is in this upload
  admin/      the admin panel: platform screens for you, and each restaurant owner's own screens
  api/        the CRM provisioning API (create, change, suspend, delete and restore outlets)
  app/lib/    shared PHP code, including MenuMatic's own database connection
  uploads/    pictures that owners upload (the .htaccess here stops any script from running)
  sql/        001_schema.sql, all tables (prefix dvmmatic_)
  docs/       API.txt, the API reference
  install.php the installer (command line)
  top.php, db_api.php, landing_new.php   the public menu
The folder can have any name. The default web address folder is "mmatic": https://your-domain/mmatic/admin/ . To use another name, set 'app_folder' (see step 2).

1. Upload the folder to your web space (for example as public_html/mmatic).
2. Create admin/inc/config.local.php (never edit config.php; this file is never overwritten):
     <?php return [
       'app_folder' => 'mmatic',                 // the folder name in the web address; '' if installed at the site root
       'db' => [
         'host' => 'localhost', 'port' => 3306,
         'name' => 'your_database', 'user' => 'your_user', 'pass' => 'your_password',
         'prefix' => 'dvmmatic_',                // in front of every table name
       ],
       'base_url'  => 'https://your-domain.com/mmatic/admin',          // used in emails; if left out it is built from the address of the request
       'menu_url'  => 'https://your-domain.com/mmatic/landing_new.php',
       'mail_from' => 'MenuMatic <no-reply@your-domain.com>',
       'mail_mode' => 'mail',                    // 'log' writes emails to admin/storage/mail.log instead
     ];
3. From a terminal on the server, inside this folder:
     php install.php --check                           tests the database connection and folders, changes nothing
     php install.php you@company.com "Your Name"       creates all tables and the first platform admin
   It prints a one-time link where you choose your password. It refuses to run if tables with your prefix already exist.
   No terminal? Import sql/001_schema.sql with phpMyAdmin instead (prefix dvmmatic_), then create the admin:
     php admin/cli/create_admin.php superadmin you@company.com "Your Name"
4. Open https://your-domain.com/mmatic/admin/ and sign in. Set your PIN under Account (needed to delete or erase outlets).
5. Create an outlet in Outlets: the owner gets an email invite. The outlet's menu link is shown in its Share screen: .../landing_new.php?m=its-slug
6. CRM API: create a key in the panel under API clients, or from a terminal:
     php api/create_api_client.php create "Company CRM" --ips=YOUR.CRM.IP
   Endpoints: /mmatic/api/v1/ (see docs/API.txt). Uses the same database settings.

Folders that must not be public: admin/inc, admin/storage, admin/cli, app/lib, api/provision_lib.php. Each has an .htaccess that blocks it on Apache. On nginx add equivalent deny rules, and block script execution inside uploads/.
Turn on HTTPS before use. The panel redirects HTTP to HTTPS (config key force_https).
Sessions: 30 minutes idle, 12 hours absolute. Five wrong passwords for one email, or twenty from one IP, lock sign-in for 15 minutes.
Plans: edit them in the panel (Plans). Basic, Pro and Business are created by the SQL file. A blank limit means unlimited. An outlet can override its plan in its own Plan tab.

Billing: Billing settings (company name, tax number, currency, tax %, payment terms, bank details), then Invoices > Make monthly invoices creates a draft for every active outlet on a paid plan. Review a draft, Issue it (it gets INV-YYYY-00001), record payments, print PDF in English or Arabic. Overdue invoices are flagged, never suspended automatically. Voiding an issued invoice needs your PIN.
Invoice PDFs need mPDF. If your site already has it (a vendor/ folder in this folder, or one or two folders above), nothing to do. Otherwise run "composer require mpdf/mpdf" in this folder, or set 'pdf_autoload' => '/full/path/vendor/autoload.php' in config.local.php. Put a logo.png in pdf_images/ to print it on invoices. PDF problems are logged in admin/storage/pdf_errors.log.
Team (platform): Super admin does everything. Support manages outlets and reads the audit log. Billing handles invoices and sees outlets.
Staff logins (outlet): the owner adds people under Staff logins. Owner = everything for that outlet, Staff = orders only. The plan's "Admin users" limit applies.

Banners: Menu > Banners (up to 10, scheduled by date, shown on the public menu).
Opening hours: set in Settings with the outlet time zone. When hours are saved, ordering is blocked outside them; no hours means always open.
Links: record ids in addresses are signed tokens (16 characters), never plain numbers; an altered or old-style link shows the "Page not found" page. The signing key is created once in admin/storage/link.key (or set 'link_key' in config.local.php). Changing or deleting it makes existing bookmarks stop working.
Errors: pages show a branded 403, 404 or 500 with a reference code. The details (never shown to users) are in admin/storage/error.log under that code.
Lists: Orders and Invoices have a date range, a totals line over the filtered set, and a CSV export that uses the same filters.
Addresses: pages open at /mmatic/admin/<group>/<action>/<entity>[/<token>], e.g. /mmatic/admin/outlet/edit/item/Xk3... or /mmatic/admin/platform/list/invoices. Groups are platform (super admin, support, billing) and outlet (owner, staff). The route tables are in admin/inc/routes.php: a page that is not listed does not exist. Sign-in pages keep their own addresses (login.php, logout.php, forgot.php, reset.php, accept_invite.php).
  Apache: admin/.htaccess already holds the rewrite rule (needs mod_rewrite and AllowOverride All).
  nginx: add   location /mmatic/admin/ { try_files $uri $uri/ /mmatic/admin/router.php?$query_string; }   and keep PHP handling for router.php.
  If the rewrite cannot work on your server, set 'pretty_urls' => false in config.local.php: the panel then uses the plain page addresses (orders.php, item.php?id=...) and everything else is unchanged.
  Wrong group or role gives a branded 403, an unknown address or a bad token gives 404, other HTTP methods give 405, signed out goes to sign-in (machines get 401 JSON).
