# Fon2Fix POS — System Documentation

Comprehensive technical documentation of the Fon2Fix POS / repair-tracking system. Covers architecture, every file's purpose, data flow, modules, and integration points. Companion docs: [SECURITY.md](SECURITY.md), [CHANGELOG.md](CHANGELOG.md), [OPERATIONS.md](OPERATIONS.md).

---

## 1. Overview

Fon2Fix is a single-tenant, multi-branch web POS that combines:

- Repair-job tracking (Gombak + Sri Rampai branches)
- Point-of-sale with QR scan and barcode
- Dual-branch inventory with transfers, merge, bulk import
- Role-based staff management
- Reports with charts, exports, audit logs
- Off-site backup, uptime monitoring, Telegram alerts

It is native PHP (no framework), MySQL/MariaDB via PDO, and a single-page-application style dashboard. Designed for cPanel / LiteSpeed shared hosting.

```mermaid
flowchart LR
    User[Staff Browser] -->|HTTPS| Web[LiteSpeed + Apache]
    Web --> Index[index.php login]
    Web --> Dash[dashboard.php]
    Web --> API[api.php]
    Web --> Inv[invoice.php / receipt.php]
    Web --> Bak[backup.php / sync_to_backup.php]
    Dash --> API
    API --> DB[(MySQL: fonfixco_leng)]
    Sync[sync_to_backup.php] -->|cURL HTTPS| Off[systembackup.spartanmnc.com]
    Uptime[uptime_monitor.php] -->|cURL| Off
    Uptime -->|Telegram| TG[Telegram Bot]
    Audit[security_audit.php] --> DB
    Audit --> TG
    Health[health_check.php] --> DB
    Cron[cPanel Cron] --> Uptime
    Cron --> Sync
    Cron --> Health
    Cron --> Audit
    Cron --> Rotate[log_rotate.php]
```

---

## 2. Runtime stack

- **OS:** cPanel / Linux shared host
- **Web server:** LiteSpeed (Apache-compatible; honours `.htaccess` and `php.ini`)
- **PHP:** 8.1+ (configured in [php.ini](php.ini)); previous declared minimum was 7.4
- **Database:** MySQL / MariaDB, PDO with prepared statements
- **Session:** custom name `FONFIX_SYSTEM_ID`, file-based storage
- **Front-end:** vanilla HTML/JS, CDN-loaded Chart.js, html5-qrcode, QRious, html2pdf.js, JsBarcode (all SRI-pinned)

---

## 3. File inventory

### 3.1 Entry points

| File | Purpose |
|---|---|
| [index.php](index.php) | Login page; rate-limit gate; bot UA block; session bootstrap |
| [dashboard.php](dashboard.php) | Main SPA — all modules (Repair Job, POS, Stock, Reports, Staff) |
| [api.php](api.php) | Single JSON endpoint for all dashboard actions |
| [logout.php](logout.php) | Destroys session and redirects |
| [invoice.php](invoice.php) | Printable invoice viewer for repair jobs |
| [receipt.php](receipt.php) | Printable receipt viewer for retail sales |

### 3.2 Core infrastructure

| File | Purpose |
|---|---|
| [db.php](db.php) | PDO connection, session, security headers, CSP-Report-Only |
| [config.php](config.php) | DB / backup / Telegram / session secrets and settings |
| [config.sample.php](config.sample.php) | Template (committed, no secrets) |
| [helpers.php](helpers.php) | Validation, sanitisation, env-aware `getConfig()` |
| [php.ini](php.ini) | Server-side runtime config (opcache, disabled functions, session) |
| [.htaccess](.htaccess) | Apache/LiteSpeed rules: deny rules, gzip, cache, headers |

### 3.3 Backup & sync

| File | Purpose |
|---|---|
| [backup.php](backup.php) | One-click full SQL+source ZIP download for logged-in admins |
| [sync_to_backup.php](sync_to_backup.php) | Off-site backup uploader (cron-friendly) |
| [uptime_monitor.php](uptime_monitor.php) | Pings the backup server, alerts on Telegram |

### 3.4 Checkup / maintenance (new in v17.0)

| File | Purpose |
|---|---|
| [health_check.php](health_check.php) | DB/disk/index/backup-age health snapshot (HTML + JSON) |
| [security_audit.php](security_audit.php) | Read-only audit of login attempts, stale users, suspicious activity |
| [log_rotate.php](log_rotate.php) | Rotate + prune `debug_log.txt` and `backups/sync_log.txt`; prune `backups/ratelimit/` (v17.2) |
| [cron_runner.php](cron_runner.php) | Chain uptime → health → log_rotate → audit in one cron slot |
| [optimize_database.php](optimize_database.php) | Create missing indexes; analyse tables (data-safe) |
| [archive_logs.php](archive_logs.php) | Manual move of `activity_logs` / `stock_activity_logs` rows older than N days into `*_archive` (new in v17.2) |
| [bug_scanner.php](bug_scanner.php) | Static scan: orphaned JS functions, API actions, SQL risk patterns |

### 3.4.1 Archive Console (new in v18.0)

Master-only feature inside the dashboard (`📦 ARCHIVE` tab between `🗑️ TRASH` and `👥 STAFF`). Backed by 5 new `api.php` actions:

| Action | Method | Purpose |
|---|---|---|
| `archive_preview` | GET | Count + sample of rows that would move (no writes) |
| `archive_list` | GET | Paginated read of `*_archive` tables, with search + date filters |
| `archive_move` | POST + CSRF | Transactional INSERT-then-DELETE from live to archive |
| `archive_restore_one` | POST + CSRF | Move one archive row back to live |
| `archive_restore_range` | POST + CSRF | Bulk restore by date range |

Scope whitelist (defined in `archive_scope_meta()`):

| Scope | Live table | Archive table | WHERE filter |
|---|---|---|---|
| `dropoff` | `jobs` | `jobs_archive` | `model <> 'Retail Sale' AND job_id LIKE 'JS-S%' AND is_deleted = 0` |
| `retail` | `jobs` | `jobs_archive` | `model = 'Retail Sale' AND job_id LIKE 'IV-S%' AND is_deleted = 0` |
| `expenses` | `expenses` | `expenses_archive` | (none) |
| `activity_logs` | `activity_logs` | `activity_logs_archive` | (none) |
| `stock_activity_logs` | `stock_activity_logs` | `stock_activity_logs_archive` | (none) |

Schema is created on first move via `archive_ensure_schema()` (idempotent `CREATE TABLE LIKE` + column-drift self-heal). Batches > 500 rows require a typed confirmation token (`ARCHIVE <count>` / `RESTORE <count>`). All operations write a row to `activity_logs` with action `ARCHIVE` / `ARCHIVE_RESTORE`.

### 3.5 Reference & operational data

| File | Purpose |
|---|---|
| [README.md](README.md) | Project overview + usage guide |
| [SYSTEM.md](SYSTEM.md) | This document |
| [SECURITY.md](SECURITY.md) | Security posture + patch inventory |
| [CHANGELOG.md](CHANGELOG.md) | Versioned change log |
| [OPERATIONS.md](OPERATIONS.md) | Runbook: preflight, rotation, cron install, verification |
| [PseudoSitemap.txt](PseudoSitemap.txt) | Legacy text sitemap (kept for continuity) |
| [security_improvements.md](security_improvements.md) | Older notes from prior hardening pass |
| `manifest.json` | PWA manifest |
| `robots.txt` | Crawler exclusion |
| `logo.png` | Branding asset |

### 3.6 Backup folder

- `backups/ratelimit/` — per-IP API rate-limit files (auto-created)
- `backups/archive/` — rotated logs older than 1 MB
- `backups/pre_patch/{date}/` — per-deploy file snapshots for rollback
- `backups/sync_log.txt` — sync result log
- `backups/sync_last_status.json` — last sync result (used by health_check)
- `backups/health_log.json` — latest health snapshot
- `backups/cron_runner_last.json` — last chained-cron result

### 3.7 Archives

- `Archives-Executed/` — historical migration scripts (kept for reference; not web-accessible via `.htaccess`)

---

## 4. Database schema (current)

See [README.md § Database Schema](README.md) for canonical CREATE TABLE statements. Tables in active use:

- `jobs` — repair tickets (+ deleted_at, deleted_by, delete_reason, request_id)
- `retail_sales` — POS transactions (JSON `items`)
- `stock_list` — inventory (with `brand`, reorder points, average cost, turnover)
- `stock_movements` — fine-grained stock change log
- `stock_transfers` — between-branch transfer audit
- `customers` — autocomplete source
- `users` — staff + RBAC flags (many `can_*` columns)
- `activity_logs` — audit trail
- `stock_activity_logs` — stock-specific actions
- `login_attempts` — rate-limit + audit
- `expenses` — branch expense tracking
- `purchase_orders`, `purchase_order_items` — PO workflow
- `credit_notes` — return-to-supplier notes

Auto-migrations live in [api.php](api.php) lines 64–240 (idempotent `CREATE TABLE IF NOT EXISTS` + `ALTER TABLE … ADD COLUMN` blocks gated by a per-session flag).

---

## 5. Module map (within `dashboard.php`)

```mermaid
flowchart TB
    Tabs[Tab Bar] --> RJ[Repair Job]
    Tabs --> POS[Retail Sale POS]
    Tabs --> ST[Stock]
    Tabs --> RP[Reports]
    Tabs --> SF[Staff Mgmt - Master only]
    RJ --> api1[api.php: CREATE_JOB, update_full_job, delete_job]
    POS --> api2[api.php: CREATE_RETAIL, refund_retail]
    ST --> api3[api.php: insert_stock_item, transfer_stock, merge_duplicate_stocks]
    RP --> api4[api.php: get_report, export]
    SF --> api5[api.php: create_user, update_user_permissions]
```

---

## 6. Request flow

```mermaid
sequenceDiagram
    participant U as Browser
    participant W as LiteSpeed
    participant I as index.php
    participant D as dashboard.php
    participant A as api.php
    participant DB as MySQL

    U->>W: POST /index.php (username, password)
    W->>I: dispatch
    I->>DB: SELECT ... FROM users WHERE username=?
    I->>I: password_verify + session_regenerate_id
    I-->>U: 302 dashboard.php
    U->>D: GET /dashboard.php
    D-->>U: HTML + JS bundle
    U->>A: POST /api.php (action=fetch_jobs)
    A->>A: bot UA check + rate-limit (file)
    A->>A: CSRF check (state-changing only)
    A->>DB: prepared SELECT
    A-->>U: JSON
```

---

## 7. Cross-cutting concerns

- **Sessions** are bootstrapped in [db.php](db.php) with `use_strict_mode`, SameSite=Lax, HttpOnly, Secure (HTTPS), configurable lifetime (`security.session_lifetime` in [config.php](config.php)).
- **CSRF** tokens generated in [db.php](db.php), validated in [api.php](api.php) for state-changing actions and in [optimize_database.php](optimize_database.php) for index creation.
- **Headers** (`X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`, HSTS on HTTPS, CSP-Report-Only) emitted by [db.php](db.php), [index.php](index.php), [api.php](api.php) and reinforced at the Apache layer in [.htaccess](.htaccess).
- **Rate limiting** is two-tiered: login attempts → DB table `login_attempts`; API throughput → per-IP file under `backups/ratelimit/`.
- **Bot detection** is two-tiered: Apache `RewriteCond %{HTTP_USER_AGENT}` in [.htaccess](.htaccess), PHP-side list in [index.php](index.php) / [api.php](api.php).
- **Secrets** flow: env vars → `config.php` → fail-closed. No hardcoded fallback values remain in any committed PHP file as of v17.0.

---

## 8. External integrations

- **Telegram Bot API** — alerts from `uptime_monitor.php`, `security_audit.php` (via cURL, SSL verify on)
- **Off-site backup server** — `systembackup.spartanmnc.com/restore_from_sync.php`, called by `sync_to_backup.php`
- **WhatsApp wa.me links** — generated for receipt sharing in `dashboard.php`
- **CDN** — Chart.js 4.5.0, html5-qrcode 2.3.8, QRious 4.0.2, html2pdf.js 0.10.1, JsBarcode 3.11.5 (all served from `cdnjs.cloudflare.com` with SRI integrity)

---

## 9. Regular checkup pipeline

| Frequency | Component | Action |
|---|---|---|
| Every 5 min | `uptime_monitor.php` | Probe backup server; Telegram on state change |
| Hourly | `health_check.php?cron=1` | Snapshot DB/disk/indexes/backup-age to JSON |
| Daily 02:25 | `sync_to_backup.php?cron=1` | Off-site DB + source ZIP upload |
| Daily 03:30 | `log_rotate.php` | Rotate `debug_log.txt`, prune > 90 days |
| Weekly Sun 01:45 | `security_audit.php?cron=1` | Failed-login spikes + Telegram alert |
| Quarterly | `optimize_database.php` (manual) | Recreate missing indexes |

Single-cron-slot environments can use `cron_runner.php` to chain steps 1–4 every 15 minutes.

---

## 10. Glossary

- **Master role** / **Endie user** — superuser; bypasses all `can_*` permission checks.
- **Branch restriction** — when `users.restrict_branch = 1`, the user can only see/modify their `assigned_branch`.
- **Refund** — creates a negative entry in `retail_sales`, flagged via `refunded = 1` to prevent double refunds.
- **Smart merge** — case-insensitive matching across `name + type + category + supplier + cost`; same → merged, any differs → kept separate.
- **Report-only CSP** — `Content-Security-Policy-Report-Only` header logs violations without blocking; not enforced because of inline handlers in `dashboard.php`.
