# Release Candidate QA Report — MVNexus Agile Analytics

**Date:** 2026-06-05
**Scope:** Agile Project Management & Analytics module (feature scope **frozen** for this cycle)
**Purpose:** Final release-confidence evidence collection prior to production sign-off.
**Prepared by:** Automated QA agent (evidence-backed)

---

## 1. Executive summary

All required automated suites pass. A dedicated Release Candidate QA spec was added to
collect first-class evidence for console errors, failed API responses, responsive layouts,
dark mode, Arabic localization, and role-based permissions.

Two defects were discovered during this QA pass and **fixed**:

1. **Capacity page runtime crash** (`Cannot read properties of undefined (reading 'length')`).
   Root cause was an **E2E mock gap** — the `/capacity-planning` endpoint was unmocked, so the
   catch-all returned `[]` and `data.team.length` threw. Fixed the mock to return the correct
   `CapacityPlanningDashboard` shape, and added a **defensive guard** so a malformed/empty API
   response degrades to the empty state instead of white-screening.
2. **Invalid DOM nesting on the Overview page** (`<ul>` rendered inside `<p>` → React hydration
   error). The `OverviewNavCard` "Upcoming Milestones" hint passed a `<ul>` into a `styled.p`
   slot. Fixed by changing the hint container to `styled.div` (zero visual change).

After fixes, the console-error / failed-response sweep across all 14 Agile surfaces is **clean**.

**Verdict input:** All RC gates verified → recommendation is **GO for controlled production pilot**
(see `docs/FINAL_PRODUCTION_SIGNOFF.md`). One **non-blocking** known limitation is documented:
pre-existing Arabic translation debt in legacy (non-refactored) sections, which falls back to
English (`fallbackLng: 'en'`).

---

## 2. Required commands — results

| Command | Result | Evidence |
|---|---|---|
| `php artisan test` | ✅ **274 passed** (1256 assertions, ~35s) | PHPUnit JSON: `{"result":"passed","tests":274,"passed":274}` |
| `npm run type-check` | ✅ pass (`tsc --noEmit`, 0 errors) | clean exit |
| `npm run lint` | ✅ pass (`eslint . --max-warnings 0`) | clean exit |
| `npm run build` | ✅ pass (`vite build`, ~2.2s) | bundle emitted to `public/build/` |
| `npm run test -- --run` | ✅ **173 passed** (50 files) | vitest summary |
| `npm run test:e2e:agile` | ✅ **12 passed** | `enterprise-agile-flows.spec.ts` |
| `npm run test:e2e:uat` | ✅ **12 passed** | `enterprise-agile-uat.spec.ts` |
| `release-candidate-qa.spec.ts` (QA evidence) | ✅ **11 passed** | console/API + responsive + dark + i18n + permissions |

> E2E execution used the project's Laravel host (`php artisan serve` on `127.0.0.1:8000`) + Vite,
> with `PLAYWRIGHT_SKIP_WEBSERVER=1 PLAYWRIGHT_BASE_URL=http://127.0.0.1:8000`. The Laravel host
> is required because it serves the SPA HTML shell that Playwright authenticates against.

---

## 3. Console errors & failed API responses (E2E/UAT)

A capture harness (`page.on('console')`, `page.on('pageerror')`, `page.on('response')`) was
attached and swept across **all 14 Agile surfaces**: Overview, Executive, Backlog, Sprints,
Sprint Planning, Board, Capacity, Gantt, Risks, Dependencies, Milestones, Reports,
Report (Velocity), Settings — plus interactive Risk view-switching and the Analytics Center
"More analytics" disclosure.

| Check | Result |
|---|---|
| Uncaught page errors | ✅ **0** |
| Console `error` messages | ✅ **0** (noise allowlist below) |
| Failed API responses (`/api/` with status ≥ 400) | ✅ **0** |

**Noise allowlist (documented):** `favicon`, `ResizeObserver loop`, `React DevTools` — generic
browser/devtools noise unrelated to the Agile module. These are filtered before asserting; no
matches occurred in the final run regardless.

**Defects this check caught (now fixed):** the Capacity crash and the Overview `<ul>`-in-`<p>`
nesting error were both surfaced by this harness and resolved before sign-off.

---

## 4. Responsive QA — 1440 / 768 / 390

Full-page screenshots captured for Executive, Backlog, Risks, Reports, Gantt, Settings at each
breakpoint (`docs/uat-screenshots/responsive/`).

| Breakpoint | Result | Notes |
|---|---|---|
| 1440 desktop | ✅ | Multi-column grids, charts and KPI cards laid out as designed |
| 768 tablet | ✅ | Grids reflow to fewer columns; tabs wrap; no horizontal overflow |
| 390 mobile | ✅ | Sidebar collapses to hamburger; cards stack full-width; tabs wrap cleanly; no clipping |

Manually reviewed (sample): `responsive/390-mobile-executive.png` confirms collapsed nav,
stacked health card, and wrapped sub-tabs with no overflow.

---

## 5. Dark mode QA

Theme toggled to dark; screenshots captured for charts, cards, tabs, and a modal
(`docs/uat-screenshots/dark/`).

| Surface | Result | Notes |
|---|---|---|
| Executive (charts + KPI cards) | ✅ | `dark-executive.png` — cards, badges, progress bars themed correctly |
| Reports / Analytics Center | ✅ | `dark-reports.png` — preview charts legible on dark surfaces |
| Risks matrix (KPI tints + critical banner) | ✅ | `dark-risks-matrix.png` — colored card tints and red critical banner render correctly |
| Settings (tabs) | ✅ | `dark-settings-tabs.png` — tab row and forms themed |
| Modal | ✅ | `dark-modal.png` — backdrop, dark surface, readable inputs, styled actions |

No broken charts, cards, modals, or tabs observed in dark mode.

---

## 6. Arabic / English parity (changed labels)

i18next is configured with `fallbackLng: 'en'`, so any untranslated key renders English
(functional, never a raw key).

**Method:** deep key diff of `locales/en/projects.json` vs `locales/ar/projects.json`.

| Metric | Before | After |
|---|---|---|
| Missing AR keys in **refactored** sections (the changed labels: `executive`, `analyticsCenter`, `portfolio`, `settings`, `overview`, `deps`, `risks`, `milestones`, `backlogAnalytics`, `reportsHub`, `gantt.zoomLabel`) | 222 | ✅ **0** |
| AR `projects.json` key count | 180 | 402 |

**Action taken:** Added **222 Arabic translations** for all changed/refactored labels and merged
into `ar/projects.json`. Visual RTL verification captured (`docs/uat-screenshots/i18n/`):

- `ar-executive.png` — sidebar flips right; `صحة المشروع`, `تسليم السبرنت`, `العمل المنجز`,
  `معدل الإكمال`, and all tabs render in Arabic with correct RTL.
- `ar-analytics-center.png` — `مركز التحليلات`, `اتجاه السرعة`, `احتراق السبرنت` translated; charts RTL-correct.
- `ar-settings.png` — `حفظ التفاصيل` and governance tabs translated.

Automated assertions confirm AR strings render (`getByText('مركز التحليلات')`,
`getByText('تسليم السبرنت')`, `getByRole('button', { name: 'حفظ التفاصيل' })`).

**Known limitation (non-blocking):** ~194 keys in **legacy, non-refactored** sections remain
untranslated in AR (e.g. `capacity`, `backlog`, `sprints`, `planning`, `workItem`, `closure`,
`lifecycle`, `board`, and `nav.capacity`). These predate this cycle and fall back to English.
Example visible in `ar-executive.png`: the "Capacity" tab label. Tracked as a follow-up
localization pass; does not affect the **changed labels** gate.

---

## 7. Permissions QA (viewer / member / manager / admin)

Permission gating is driven by `project.permissions` via `useProjectPermissions`
(`readOnly = !can_update_work_items`, `canManage`). Verified by varying mock permissions and
asserting UI behavior:

| Role | can_update_work_items | can_manage | Backlog create actions | Settings "Save details" / archive | Result |
|---|---|---|---|---|---|
| **Viewer** | false | false | ❌ hidden | ❌ hidden | ✅ read-only enforced |
| **Member (agent)** | true | false | ✅ visible | ❌ hidden | ✅ can edit work, cannot manage |
| **Manager** | true | true | ✅ visible | ✅ visible | ✅ full management |
| **Owner/Admin** | true | true | ✅ visible | ✅ visible + Archive tab | ✅ full control |

All four role assertions pass in `release-candidate-qa.spec.ts`.

---

## 8. Screenshot inventory (manually reviewed)

- **Core UAT** (`docs/uat-screenshots/`): `01-overview` … `13e-settings-archive` (19 images) —
  Overview, Executive, Backlog, Risks (register/matrix/heatmap/distribution), Dependencies,
  Milestones (list/timeline), Gantt, Analytics Center (+more), Velocity report, Settings (all 5 tabs).
- **Responsive** (`responsive/`): 18 images (6 surfaces × 3 breakpoints).
- **Dark mode** (`dark/`): 5 images (executive, reports, risks-matrix, settings-tabs, modal).
- **Arabic** (`i18n/`): 3 images (analytics-center, executive, settings).

Reviewed samples confirm professional, consistent enterprise styling with no layout breakage,
clipped content, or unstyled elements.

---

## 9. Changes made during this QA pass (defect fixes + evidence tooling)

| File | Change | Type |
|---|---|---|
| `resources/js/src/features/projects/components/OverviewNavCard.tsx` | `Hint` `styled.p` → `styled.div` (fix `<ul>`-in-`<p>`) | **Product fix** |
| `resources/js/src/features/projects/pages/ProjectCapacityPage.tsx` | Defensive guard `!data.team \|\| data.team.length === 0` | **Product hardening** |
| `resources/js/src/locales/ar/projects.json` | +222 Arabic translations for changed labels | **Localization** |
| `resources/js/src/__tests__/e2e/helpers/project-mocks.ts` | Add `capacity-planning` mock + permissions override | Test infra |
| `resources/js/src/__tests__/e2e/release-candidate-qa.spec.ts` | New RC QA evidence spec | Test (QA) |

No new product features were introduced. Feature scope remained frozen.

---

## 10. Outstanding / follow-up (non-blocking)

1. **Complete Arabic localization** for legacy sections (~194 keys: capacity, backlog, sprints,
   planning, workItem, closure, lifecycle, board, `nav.capacity`). Currently English fallback.
2. **Backend contract note:** the Capacity page depends on `/projects/{id}/capacity-planning`
   returning `{ sprint, metrics, team[] }`. The added defensive guard prevents a crash on
   malformed responses, but the live endpoint must honor this contract for full functionality.
3. **Browser matrix:** automated runs executed on Chromium. Recommend a manual smoke on
   WebKit/Firefox during the pilot.
