# TheSol Chat — Release Checklist

**Version:** v1.0  
**Date:** 2026-04-26  
**Release tag:** `v1.0-pre-release`  

> Run this checklist from top to bottom before every production deployment.  
> A ✅ means automated or script-verified; 🔲 means manual confirmation required.

---

## 1. Code Quality

| # | Check | How to verify | Status |
|---|-------|---------------|--------|
| 1.1 | PHP lint passes on all modified files | `Get-ChildItem -r *.php \| ForEach { php -l $_.FullName }` | 🔲 |
| 1.2 | No `SB_DEBUG` or `error_reporting(E_ALL)` left enabled | `Select-String -r -Pattern "SB_DEBUG.*true\|E_ALL" *.php` | 🔲 |
| 1.3 | No hardcoded credentials or API keys in tracked files | `git diff HEAD -- '*.php' \| grep -i 'password\|secret\|api_key'` | 🔲 |
| 1.4 | `config.php` is in `.gitignore` and **not** staged | `git status config.php` → must show nothing | 🔲 |
| 1.5 | Minified JS is current (if rebuilt) | Compare `js/min/*.js` mtime vs `js/*.js` | 🔲 |

---

## 2. Database

| # | Check | How to verify | Status |
|---|-------|---------------|--------|
| 2.1 | Migration script applied to target DB | `Get-Content resources/migrate-v1.sql \| & mysql.exe -u… dbname` (idempotent — safe to re-run) | 🔲 |
| 2.2 | `sb_otp_sessions.otp_code` is `VARCHAR(64)` | `SHOW COLUMNS FROM sb_otp_sessions LIKE 'otp_code'` | 🔲 |
| 2.3 | `sb_queue` has `claim_id`, `heartbeat_at`, `failed_at` columns | `SHOW COLUMNS FROM sb_queue` | 🔲 |
| 2.4 | `sb_settings.version` column exists | `SHOW COLUMNS FROM sb_settings LIKE 'version'` | 🔲 |
| 2.5 | `otp-verification-config` seeded with `active: false` | `SELECT value FROM sb_settings WHERE name='otp-verification-config'` | 🔲 |
| 2.6 | Pre-deploy DB snapshot taken | See §6 — Backup & Rollback | 🔲 |

---

## 3. Security

| # | Check | How to verify | Status |
|---|-------|---------------|--------|
| 3.1 | `uploads/` directory listing disabled | Request `https://yourhost/uploads/` — must return 403 | 🔲 |
| 3.2 | `uploads/embeddings/` returns 403 | Direct browser request | 🔲 |
| 3.3 | `.log` files return 403 | Request any `logs/*.log` URL | 🔲 |
| 3.4 | `.sql` files return 403 | Request `resources/migrate-v1.sql` URL | 🔲 |
| 3.5 | `config.php` returns 403 or blank (not source code) | Direct browser request | 🔲 |
| 3.6 | Admin-only AJAX operations require `user_type = admin` | Run smoke test — test 7 | ✅ |
| 3.7 | `display_errors = Off` in production `php.ini` | `php -r "echo ini_get('display_errors');"` → must be empty/0 | 🔲 |
| 3.8 | `SB_ENCRYPTION_KEY` is 64+ hex chars, set in `config.php` | `php -r "require 'config.php'; echo strlen(SB_ENCRYPTION_KEY);"` | 🔲 |

---

## 4. Runtime Environment

| # | Check | How to verify | Status |
|---|-------|---------------|--------|
| 4.1 | PHP version ≥ 7.4 | `php -v` | 🔲 |
| 4.2 | Required extensions loaded: `curl`, `openssl`, `json`, `mbstring`, `fileinfo`, `mysqli` | `php -m` | 🔲 |
| 4.3 | `logs/` directory is writable by web process | `Test-Path` + `[IO.File]::OpenWrite` check | 🔲 |
| 4.4 | `uploads/` directory is writable by web process | Write + delete a temp file | 🔲 |
| 4.5 | MySQL advisory locks available (`GET_LOCK`/`RELEASE_LOCK`) | `SELECT GET_LOCK('test',1), RELEASE_LOCK('test')` | 🔲 |
| 4.6 | Cron job for queue worker configured (if async jobs used) | `crontab -l` or Windows Task Scheduler | 🔲 |

---

## 5. Smoke Tests

| # | Check | Command | Status |
|---|-------|---------|--------|
| 5.1 | All 15 smoke test sections pass | `php logs/smoke_test_release.php` | 🔲 |
| 5.2 | Exit code is 0 (no failures) | `echo $LASTEXITCODE` | 🔲 |

**Run the full suite:**
```powershell
php D:\xampp\htdocs\Chatbot\logs\smoke_test_release.php
echo "Exit: $LASTEXITCODE"
```

---

## 6. Backup & Rollback

| # | Step | Command | Status |
|---|------|---------|--------|
| 6.1 | Create pre-release backup | `php logs/release_backup.php --tag=v1.0 --dir=D:\xampp\chatbot-private\backups --mysql-bin=D:\xampp\mysql\bin` | 🔲 |
| 6.2 | Verify DB dump is non-empty | Check `.sql` file path printed by `release_backup.php` | 🔲 |
| 6.3 | Verify source manifest exists | Check `_manifest.json` path printed by `release_backup.php` | 🔲 |
| 6.4 | Restore backup to staging DB | Follow `deploy/release-execution-runbook.md` section 3 | 🔲 |
| 6.5 | Rollback procedure documented | `deploy/release-execution-runbook.md` section 8 | ✅ |
| 6.6 | Build final release package | `php logs/create_release_package.php --tag=v1.0` | 🔲 |
| 6.7 | Final package excludes install/config/runtime artifacts | Inspect `release-manifest.json` inside package | 🔲 |

---

## 7. Post-Deploy Verification

| # | Check | How to verify | Status |
|---|-------|---------------|--------|
| 7.1 | Chat widget loads on test page | Open `testchat/index.php` in browser | 🔲 |
| 7.2 | Admin panel accessible | Login at `admin.php` | 🔲 |
| 7.3 | No PHP errors in error log | `Get-Content logs/error.log -Tail 50` | 🔲 |
| 7.4 | Webhook endpoint returns 200 for valid request | Test with Postman / MSG91 test send | 🔲 |
| 7.5 | OTP flow: send + verify cycle works end to end | Manually trigger OTP via chat | 🔲 |
| 7.6 | MSG91 webhook URL includes shared token | URL format: `https://yourdomain.com/Chatbot/apps/whatsapp/post.php?token=YOUR_TOKEN` | 🔲 |
| 7.7 | MSG91 retry does not duplicate inbound message | Post the same MSG91 inbound payload twice; only one chatbot message appears | 🔲 |
| 7.8 | MSG91 IP allowlist decision recorded | Keep token-only unless MSG91 provides stable documented source IP ranges for the target account/region | 🔲 |
| 7.9 | HTTP preflight passes public URL | `php logs/http_preflight_check.php --url=https://yourdomain.com/Chatbot --no-color` | 🔲 |
| 7.10 | Manual release notes completed | Copy `deploy/release-notes-template.md` and fill every result/evidence cell | 🔲 |

---

## Section 8 — Operations & Retention (P5)

| # | Check | How to verify | Status |
|---|-------|---------------|--------|
| 8.1 | Maintenance script runs without error | `php logs/maintenance.php --dry-run --all` completes with 0 PHP errors | 🔲 |
| 8.2 | Maintenance cron scheduled | Daily cron entry exists (see `deploy/queue-worker-runbook.md`) | 🔲 |
| 8.3 | OpenAI usage retention configured | Default 18 months; `sb_openai_usage_cleanup()` exists and callable | 🔲 |
| 8.4 | Audit log retention configured | Default 18 months; `sb_audit_log_cleanup()` exists and callable | 🔲 |
| 8.5 | System health endpoint returns data | Admin AJAX call `function=system-health` returns `queue`, `disk`, `db_tables`, `alerts` keys | 🔲 |
| 8.6 | No current health alerts on target | `system-health` response has `has_alert: false` or all alerts acknowledged | 🔲 |
| 8.7 | Log rotation configured on host | Logrotate / cPanel / Task Scheduler rotation in place per `deploy/log-rotation-runbook.md` | 🔲 |
| 8.8 | Error log is not unexpectedly large | `error_log` file size < 10 MB before go-live | 🔲 |

---

## Sign-off

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Developer | | | |
| QA | | | |
| Deployment approver | | | |

---

## Known Deferred Items (Phase 7+)

The following items are tracked in `PRODUCT_STABILITY_AUDIT_2026-04-26.md` §9.3 and are **not** blockers for v1.0 release but must be addressed before v1.1:

- **PND-1** Dead-letter queue dashboard UI
- **PND-2** Per-job retry/backoff algorithm
- **PND-3** Cron batch worker mode
- **PND-4** OTP session scheduled purge
- **PND-6** External settings version locking
- **PND-7** `uploads/` conversation exports still publicly accessible
- **PND-13** Minified JS not rebuilt from source
- **PND-14** No preflight checker (PHP version, DB connect, writable paths)
- **PND-15** AJAX function registry is manually maintained
- **PND-16** Webhook/upload endpoints use `die()` instead of structured error responses
