# Phase 13 Security and Launch Readiness Report

Date: 30 June 2026

## Scope completed

Phase 13 reviewed authentication, sessions, role checks, payment callbacks and webhooks, certificate
verification, Email Manager access, course-cover uploads, public and private routes, environment
configuration, database migration tooling, production packaging, logging, backups, and automated
tests. Existing LMS behavior and migrated data structures were retained.

## Security changes

- Browser authentication now uses an `HttpOnly`, `SameSite=Lax` session cookie. Production cookies
  are marked `Secure`; session duration and remember-me duration are configurable.
- Session hashes use HMAC-SHA-256 when `SESSION_SECRET` is configured. Login prunes expired sessions,
  limits retained sessions per account, rejects inactive accounts, and logout revokes the server
  session and clears the cookie.
- Cookie-authenticated mutations require an allowed browser origin. CORS allows only the current app
  origin, `APP_BASE_URL`, and `FRONTEND_URL`; credentials are supported without wildcard origins.
- Security headers now include CSP, frame denial, content-type protection, restricted browser
  permissions, a strict referrer policy, and production HSTS.
- Rate limits cover login, registration, password reset, certificate verification, payment
  initialization/verification, payment webhooks, support forms, admin email tests, and admin tables.
  Account-specific limits supplement IP limits for login and registration.
- Course cover input accepts only bounded JPG, PNG, or WebP data URLs and HTTPS image URLs. Oversized,
  malformed, script, and insecure remote URLs are rejected.
- Structured operational logging redacts passwords, secrets, tokens, cookies, signatures, and card
  fields. Authentication rejections, payment errors, invalid webhooks, certificate lookup failures,
  email delivery failures, admin actions, and system errors are auditable.
- The frontend no longer persists the session token in `localStorage`. Temporary bearer-token
  responses remain for API/test compatibility and can be removed after external clients have moved
  to cookie authentication.

## Access control review

Admin overview, user management, payment records, certificate management, Email Manager, reports,
exports, and audit logs require an administrator. Course creation requires an instructor or
administrator; editing and publishing also require ownership or administrator permission.
Certificate issue, revoke, and reissue operations remain administrator-only. Automated tests confirm
that students and instructors receive `403` from private administration routes.

## Payment checks

Existing backend-only Paystack and Flutterwave initialization and verification were retained and
reviewed. Signed webhook validation, replay protection, idempotent payment events, strict amount,
currency, user, course, order-reference and gateway-reference matching, and enrollment uniqueness
are covered by the test suite. Payment rows now consistently expose the user, course or bundle,
amount, currency, gateway, gateway reference, internal reference, state, created/confirmed dates, and
failure reason.

Automated tests passed for forged signatures, wrong amount, currency, user, course and reference,
repeated callbacks, repeated webhook events, fake frontend success, one-time enrollment, and
reconciliation without duplicate access. These tests use deterministic gateway fixtures. Paystack
and Flutterwave sandbox tests and low-value live transactions still require valid merchant accounts
and must be completed manually before launch.

## Certificate checks

Automated tests cover current certificate verification, previous Coursepedia certificate-code
verification, invalid and revoked codes, public privacy, QR verification links, PDF generation,
download audit, reissue, revocation, search, and certificate history. Public verification returns
only learner name, course title, certificate code, issue date, and status.

The landscape certificate uses Coursepedia branding, signature, seal, and QR assets. Long learner and
course names receive smaller layout classes. The manual checklist requires final PDF and printer
inspection with representative long names before approval.

## Email checks

The Email Manager remains administrator-only. Existing template editing, test sending, branded
layout, event queue, suppression, preferences, audit, and log behavior were retained. New tests prove
that unavailable providers move queued mail through retry to terminal failure with a recorded error.
SMTP delivery cannot be proven without production or staging credentials; registration, password
reset, payment, enrollment, and certificate templates must be sent through the configured staging
SMTP service before launch.

## Production cleanup

- `.gitignore` already excludes `.env`, `node_modules`, runtime logs/data, database snapshots,
  backups, migration output, caches, and temporary files.
- `.dockerignore` now applies the same boundary to container build contexts.
- `pnpm production:build` generates `dist/coursepedia-lms` from an allowlist. It excludes `.env`,
  `node_modules`, tests, live JSON data, seed fixtures, logs, backups, migration exports, temporary
  files, and unrelated project reports while retaining application assets, PostgreSQL schema,
  migration tools, and production documentation.
- The generated manifest lists every included release file.
- `.env.example` now documents PostgreSQL, session, payment, SMTP, OAuth, storage, bootstrap-admin,
  monitoring, and application URL settings using placeholders only.
- The public asset version was advanced for Phase 13 so browsers receive the cookie-session and
  security changes immediately. Phone navigation now uses a bounded four-column layout instead of
  an overflowing horizontal strip.

## Verification results

- `pnpm check`: passed 26 of 26 tests.
- `pnpm security:audit`: no credential fields found in the application database.
- `pnpm seo:check-links`: 356 sitemap and essential public URLs checked with no broken links.
- `pnpm db:migrate -- --dry-run`: completed with source counts of 14,631 users, 525 courses, 9,247
  lessons, 591 quizzes, 3,053 enrollments, 1,245 orders, 1,250 certificates, 1,475 reviews, and 27,091
  quiz attempts.
- PostgreSQL live migration/reconciliation was not run because production database credentials were
  not supplied in this workspace.

## Monitoring plan

Send structured application logs to the hosting log service using `OPERATIONAL_LOG_STDOUT=true`, or
configure a protected `LOG_DIR`. Alert on repeated login failures, payment verification and webhook
errors, certificate verification spikes, email terminal failures, privileged admin actions, and
uncaught system errors. Add uptime checks for `/api/health`, the homepage, course catalogue, and
certificate verification.

Logs must never contain passwords, card data, full authorization tokens, session cookies, SMTP
passwords, OAuth secrets, payment secret keys, or storage credentials.

## Manual actions required before launch

1. Rotate any Paystack key already used in local development, then install production Paystack and
   Flutterwave keys and webhook secrets in the hosting secret manager.
2. Generate a new random `SESSION_SECRET` of at least 32 bytes. Rotate OAuth client secrets, SMTP
   credentials, database credentials, storage keys, and monitoring keys if they have ever appeared
   outside the secret manager.
3. Provision PostgreSQL, apply the schema, run the repeatable migration, and require a fully balanced
   `pnpm db:reconcile` result.
4. Configure HTTPS, the trusted reverse proxy, production domains, cookie domain if needed, persistent
   storage, and Coursepedia's SMTP sender authentication.
5. Register exact Paystack, Flutterwave, Google, and Facebook callback URLs.
6. Complete every item in `COURSEPEDIA_FINAL_TEST_CHECKLIST.md`, including sandbox and low-value live
   payments, real SMTP delivery, mobile testing, a backup restore drill, and final certificate print
   inspection.
7. Remove or blank `ADMIN_SEED_PASSWORD` immediately after the production administrator is created.

## Remaining launch risks

Production payment gateways, SMTP, OAuth, PostgreSQL, object storage, and monitoring are external
services and cannot be certified from local fixtures. Launch approval should remain blocked until
their staging tests, reconciliation evidence, backup restore evidence, and low-value live payment
evidence are attached to the final checklist.
