# Support Ticketing System

Built from `BRD_Support_Ticketing_Module.pdf` (v1.0) — the Phase 1 "minimum
viable service desk" scope from BRD section 11, plus a working knowledge base
and escalation matrix pulled forward from Phase 2 because they're small
additions once the SLA engine exists and they make the system meaningfully
more useful on day one.

Stack: **plain PHP 8 + MySQL**, no framework, no Composer, no Node/build
step — chosen to drop cleanly onto ordinary cPanel shared hosting. See
[DEPLOY.md](DEPLOY.md) for the cPanel install steps.

## What's implemented

**Ticket lifecycle** — the fixed status machine from BRD 5.1 (NEW →
ASSIGNED → IN PROGRESS → PENDING CUSTOMER/THIRD PARTY → RESOLVED → CLOSED,
with ESCALATED, REOPENED, REJECTED), enforced server-side so no invalid
transition can happen from the UI or a direct request.

**Multi-channel intake** — customer portal, agent-logged
(telephone/walk-in/internal), and email-to-ticket via IMAP polling with
reference-header matching and a quarantine queue for unregistered senders.

**SLA engine** — business-hours calendars with holidays, per-priority
response/resolution targets by contract tier, automatic clock pause/resume
on PENDING CUSTOMER / PENDING THIRD PARTY, warning thresholds, permanent
breach flagging, and a configurable escalation matrix. Run from cron every
5 minutes, matching NFR-04.

**Agent console** — dashboard, All Tickets / My Queue / Unassigned /
Escalated views, ticket detail with a single conversation thread that
strictly separates public replies from internal notes (never exposed to
the portal, an email, or an export), canned responses, effort logging,
defect linking, and a full audit trail.

**Customer portal** — separate authentication and session from the agent
console, ticket raising with live knowledge-base deflection suggestions,
tracking, replying, accepting/reopening resolutions, CSAT capture, and an
entitlement/contract view. Portal users never see internal notes, agent
identities beyond assignment, effort records, or cost data.

**Knowledge base** — draft/review/published/retired workflow, full-text
search (with a plain LIKE fallback if MySQL FULLTEXT isn't available),
suggestion at ticket creation, and deflection tracking.

**Time, effort & billing** — effort logging against entitlement hours,
billable/non-billable marking, 80%-consumed warnings, and per-customer
billing summaries (CSV, ready to key into an invoice — see "Deferred"
below for the automatic Sales Invoice hand-off).

**Notifications** — a zero-dependency SMTP client (no PHPMailer needed),
editable templates with placeholder substitution, per-event enable/disable,
in-app alerts, and a full delivery log with retry for failed sends.

**Reporting** — SLA compliance, ticket ageing, breach register, agent
productivity, CSAT, and entitlement consumption, each exportable to CSV
(opens directly in Excel) with a print-to-PDF button.

**Administration** — categories, priorities, queues, teams, business
calendars/holidays, SLA policies, notification templates, canned responses,
customers/contacts/contracts/products (standing in for the ERP masters —
see below), agent accounts, and an admin change-audit log.

## Standalone masters, not a live ERP integration

The BRD assumes Customer, Contact, Contract/AMC, Product/Item and Employee
already exist in a surrounding ERP (section 5.4, 8). This workspace had no
such system to integrate with, so those are built as native tables and
Admin screens here instead — fully functional on their own, with the same
shape the BRD specifies, so a later integration mainly means pointing these
lookups at the real ERP's API/database rather than redesigning the ticket
model around it.

## Deferred (BRD Phase 2/3, or explicitly out of scope)

Kept out to keep this a focused, working Phase 1 rather than a half-built
Phase 3. Everything below is additive — none of it requires reworking what's
here:

- Ticket merge/split, duplicate detection at intake
- Skills-based routing, round-robin/least-loaded auto-assignment (queues
  have the setting; the routing logic itself is a Phase 3 item)
- REST API for external ticket creation (FR-SUP-009, FR-SUP-114)
- SMS notifications (FR-SUP-087)
- Timer-based effort capture (FR-SUP-079) — effort is logged after the fact
- Custom fields per category (FR-SUP-021)
- Automatic billing-summary → Sales Invoice hand-off (produces a CSV/report
  today; wiring it into a real Sales module is ERP-specific)
- Bangla localisation (NFR-19) and formal WCAG 2.1 AA certification (NFR-20)
  — the CSS uses real form labels, keyboard-reachable controls and AA-range
  contrast throughout, but hasn't been run through an accessibility audit
- Live chat, telephony/PBX integration, field-service dispatch, CMDB —
  explicitly out of scope per BRD section 14

## Local development

Easiest path — use the web installer:

```
mysql -u root -e "CREATE DATABASE sts_support CHARACTER SET utf8mb4;"
php -S localhost:8000 -t public_html
```

Then visit `http://localhost:8000/install.php` and follow the wizard (DB
host `localhost`, user `root`, database `sts_support`) — tick "Load sample
data" for demo customers/tickets/agents. Delete `install.php` when it's done.

Or set it up by hand:

```
mysql -u root sts_support < database/schema.sql
mysql -u root sts_support < database/core_setup.sql   # roles, priorities, SLA calendar — always needed
mysql -u root sts_support < database/demo_data.sql    # optional: demo customers/agents/tickets
cp config/config.sample.php config/config.php         # then edit db.* for your local MySQL, and
                                                        # insert your own admin user (see DEPLOY.md §5)
```

If you loaded `demo_data.sql`, every seeded agent/portal login uses the
password `Passw0rd!` (e.g. `r.karim@erp.com.bd`) — see that file for the
full list. The installer path creates your own admin account instead of
using a shared demo password.

## Structure

```
app/Core/          Router, DB (PDO), session/auth (agent + portal, separate), CSRF, view rendering
app/Services/       SlaEngine, TicketService (status machine + business rules), Mailer (SMTP), NotificationService,
                    EmailIngestService (IMAP), DeflectionSearch (KB), AttachmentService
app/Controllers/    One per functional area (routes.php maps URLs to these)
app/Views/          Plain PHP templates; app/Views/portal/ is the customer-facing theme
database/           schema.sql (DDL) + core_setup.sql (essential config) + demo_data.sql (optional sample content)
cron/               sla_engine.php, email_ingest.php, notification_retry.php
public_html/        Web root: front controller, install.php (web installer), .htaccess, CSS/JS (no build step)
```

## Security notes

- Agent and portal sessions use separate cookies so one browser can be
  logged into both without collision (NFR-10, NFR-14).
- All queries are parameterised (PDO prepared statements) — no string-built
  SQL anywhere.
- CSRF tokens on every state-changing form.
- Uploaded attachments are stored outside the web root and served through a
  PHP-controlled download route, not linked directly.
- Internal notes are a distinct `type` at the database layer (not just a UI
  flag), and every query that renders portal-facing content explicitly
  filters `type IN ('public_reply','inbound_email')` — see BRD 7.3's data
  rule that this distinction must survive any future export or API.
