# Prep MVP — Testing Plan

Run this checklist before every deployment. Mark each item: ✅ Pass, ❌ Fail, ⬜ Not tested.

---

## 1. Upload

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 1.1 | Valid PDF | Upload a text-based PDF < 20 MB | Status: analyzed. Questions and/or suggestions appear. |
| 1.2 | Valid DOCX | Upload a .docx with readable text | Text extracted. Analysis results appear. |
| 1.3 | Valid PPTX | Upload a .pptx with multiple slides | "Slide N:" markers preserved. Analysis results appear. |
| 1.4 | Unsupported file (.exe) | Attempt upload of a .exe renamed to .pdf | Extension check fails → "This file type is not supported." |
| 1.5 | Unsupported file (.txt) | Upload a .txt file | Rejected with unsupported type message. |
| 1.6 | Oversized file (>20 MB) | Upload a file larger than 20 MB | Rejected with size message. |
| 1.7 | Empty file (0 bytes) | Upload a zero-byte .pdf | Rejected: "The file you selected is empty." |
| 1.8 | No file selected | Submit form without choosing a file | Client-side + server-side: "Please select a file." |
| 1.9 | MIME mismatch | Rename a .exe to .pdf and upload | MIME validation catches it. Rejected. |
| 1.10 | Corrupted file | Upload a truncated/partial PDF | Extraction fails gracefully. Status: failed. |
| 1.11 | No task selected | Upload file but check no tasks | "Please select at least one task." |
| 1.12 | Drag-and-drop | Drag a valid file onto the drop zone | File name appears. Submit works. |

---

## 2. Text Extraction

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 2.1 | Normal PDF | Upload a text-heavy PDF | Text extracted. Char/word count shown. |
| 2.2 | Scanned PDF | Upload an image-only PDF | "This PDF appears to be scanned or image-based." Status: failed. |
| 2.3 | Normal DOCX | Upload a DOCX with paragraphs and headings | Paragraphs preserved. Text extracted. |
| 2.4 | Blank DOCX | Upload a DOCX with no text | "This document contains very little readable text." Status: failed. |
| 2.5 | PPTX multi-slide | Upload a PPTX with 5+ slides | Slide numbers preserved. Slide count metadata shown. |
| 2.6 | Password-protected PDF | Upload an encrypted PDF | "This PDF file appears to be password-protected." |
| 2.7 | Very short document | Upload a PDF with <100 chars of text | "very little readable text." Status: failed. |

---

## 3. AI Analysis

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 3.1 | Questions only | Upload doc, check only "Questions" | Only questions card appears. Suggestions not shown. |
| 3.2 | Suggestions only | Upload doc, check only "Suggestions" | Only suggestions card appears. |
| 3.3 | Both tasks | Check both tasks | Both cards appear. |
| 3.4 | API key missing | Remove AI_API_KEY from .env, upload | "AI configuration is incomplete." |
| 3.5 | API timeout | Set short timeout, upload large doc | "Could not reach the AI service." |
| 3.6 | Invalid AI JSON | If AI returns non-JSON text | "returned a response we could not process." |
| 3.7 | AI content filter | Upload sensitive content | "The AI could not analyse this document due to content restrictions." |
| 3.8 | Rate limit (AI) | Trigger AI rate limit (429) | "temporarily busy. Please wait." |
| 3.9 | Partial failure | Questions succeed, suggestions fail | Questions shown. Warning: suggestions failed. Status: text_extracted. |
| 3.10 | All AI tasks fail | Both tasks fail | Warning shown. Status: text_extracted. |
| 3.11 | Accordion open/close | Click question accordion | Details expand. Click again to collapse. |
| 3.12 | Copy single question | Click copy icon on a question | "Copied" flash. Clipboard has question + details. |
| 3.13 | Copy all questions | Click "Copy all" | All questions in clipboard. |
| 3.14 | Copy all suggestions | Click "Copy all" on suggestions | All suggestions in clipboard. |
| 3.15 | Copy full analysis | Click "Copy full analysis" | Full text with disclaimer in clipboard. |
| 3.16 | Download as text | Click "Download as text" | .txt file downloads. Includes disclaimer. |

---

## 4. Security

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 4.1 | HTML in filename | Upload `<script>alert(1)</script>.pdf` | Filename escaped. No script executes. |
| 4.2 | Script-like AI output | If AI returns `<script>` text | Escaped as text. No script executes. |
| 4.3 | Invalid document ID | Visit result.php?id=99999 | Redirects to index.php. |
| 4.4 | Negative document ID | Visit result.php?id=-1 | Redirects to index.php. |
| 4.5 | Direct upload access | Visit /storage/uploads/anyfile.pdf | 403 or connection refused. |
| 4.6 | Storage dir listing | Visit /storage/uploads/ | 403 from index.php guard. |
| 4.7 | CSRF missing | POST to analyze.php without csrf_token | "Your session has expired." |
| 4.8 | CSRF replay | Reuse a CSRF token | Second use fails (token consumed). |
| 4.9 | SQL injection | Enter `' OR '1'='1` as filename via modified form | Escaped by prepared statements. No injection. |
| 4.10 | GET on analyze.php | Visit analyze.php in browser | 405 "Method not allowed." |
| 4.11 | Rate limit | Submit 11+ uploads within 1 hour | 11th request: "You have submitted too many requests." |
| 4.12 | API key in page source | View page source on any page | No API key or endpoint visible. |
| 4.13 | Stored file path | View page source on result page | No /storage/uploads/ paths visible. |
| 4.14 | .env accessible | Visit /.env in browser | Blocked by .htaccess or returns nothing. |

---

## 5. Database

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 5.1 | Document saved | Upload any file | Row appears in `documents` table. Status: uploaded → text_extracted → analyzed. |
| 5.2 | AI results saved | Both tasks succeed | Two rows in `ai_results` linked to document. |
| 5.3 | Failed status | Extraction fails | `documents.status = 'failed'`, `error_message` populated. |
| 5.4 | Partial AI saved | One task succeeds, one fails | Successful task saved to `ai_results`. Failed task not present. |
| 5.5 | DB connection fail | Stop MySQL, upload | "We could not save your data right now." |

---

## 6. Mobile / Responsive

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 6.1 | 360px width | Open index.php in Chrome DevTools at 360×800 | Form fits. No horizontal scroll. Buttons full-width. |
| 6.2 | 360px — result page | View result.php at 360px | Accordions readable. Copy buttons tappable. No overflow. |
| 6.3 | 360px — long filename | Upload file with 100+ char name | Filename wraps. No overflow. |
| 6.4 | Tablet (768px) | View at 768px | Two-column export bar. Larger padding. |
| 6.5 | Desktop (1280px) | View at 1280px | Content centered at 600px max-width. |
| 6.6 | Touch accordion | Tap accordion summary on phone/emulator | Opens smoothly. Copy button does not toggle accordion. |
| 6.7 | Drop zone tap | Tap drop zone on mobile | File picker opens. |
| 6.8 | Button tap targets | Inspect any button | Minimum 44×44px touch area. |
| 6.9 | Loading state mobile | Submit on mobile | Button shows spinner. Disabled state visible. |

---

## 7. Error & Edge Cases

| # | Test | Steps | Expected |
|---|------|-------|----------|
| 7.1 | Session expiry | Wait >24 min, submit form | "Your session has expired. Please refresh." |
| 7.2 | Double submit | Rapidly click "Analyze" twice | Second click blocked by loading state. |
| 7.3 | Large document chunking | Upload a document with >75,000 chars of text | Chunked, summarised, analysed. Warning shown. |
| 7.4 | All chunks fail | Simulate AI failure for every chunk | "None of the chunk summaries completed." Status: failed. |
| 7.5 | No results | Visit result.php with no session data | Redirects to index.php. |
| 7.6 | Unicode filenames | Upload файл.pptx (Cyrillic filename) | Filename stored. Displayed correctly (or escaped). |
| 7.7 | Emoji in filename | Upload file named test😀.pdf | Handled gracefully. No crash. |

---

## 8. Pre-Deployment Final

| # | Check | Status |
|---|-------|--------|
| 8.1 | `.env` has real API key and DB credentials | ⬜ |
| 8.2 | `APP_ENV` is NOT `local` | ⬜ |
| 8.3 | `display_errors = 0` in production php.ini (verified by visiting a page that throws) | ⬜ |
| 8.4 | `composer install --no-dev` run on production | ⬜ |
| 8.5 | Database schema applied (`database/schema.sql`) | ⬜ |
| 8.6 | `storage/uploads/` is writable by the web server | ⬜ |
| 8.7 | SSL/HTTPS enabled | ⬜ |
| 8.8 | Cron job for `cleanup_old_uploads()` configured (optional) | ⬜ |
| 8.9 | Server firewall blocks direct access to `/storage/` | ⬜ |
| 8.10 | PHP `open_basedir` restricts file access to project root | ⬜ |
