# Security and Critical Workflow Architecture

## Role and permission architecture

Use RBAC with scoped assignments:

```text
User -> Role assignment (institution + optional campus/department + validity)
Role -> Permissions
Policy -> permission + tenant + record relationship + workflow state
```

Default roles are seeded templates, not hard-coded conditionals. Institutions may
clone templates and create roles. Permissions use stable verbs such as
`students.view`, `results.approve`, and `payments.reverse`.

Authorization has four layers:

1. authenticated, verified, active user and valid session;
2. resolved tenant membership and scope;
3. permission or explicit super-administrator capability;
4. policy checks for ownership, organizational scope, separation of duties, and state.

High-risk operations require fresh authentication/MFA readiness, a reason, and audit
evidence. A person cannot approve their own sensitive action where separation of
duties is configured. Super administrators receive explicit, logged cross-tenant
impersonation/access rather than an invisible bypass.

## Multi-institution isolation

- Resolve tenant from an allowlisted verified domain/subdomain, then bind an immutable
  `TenantContext` for the request/job.
- Reject tenant IDs supplied by clients when they conflict with context.
- Apply tenant-aware repositories/global scopes, scoped route binding, policies, and
  composite foreign-key validation.
- Serialize institution ID into queued jobs and re-establish context before execution.
- Partition cache keys, rate-limit keys, filesystem prefixes, search indexes, exports,
  and broadcast channels by institution.
- Run automated “cross-tenant matrix” tests for every tenant-owned endpoint.
- Use a privileged central console for super-administration; log every cross-tenant read
  of sensitive data.

Initially use a shared schema with `institution_id`. If regulatory or scale needs
require it, the domain boundaries permit selected institutions to move to isolated
databases later.

## CBT autosave and timing

### Server authority

The server stores `starts_at`, `expires_at`, granted accommodations, and final state.
Remaining time is derived from server UTC time. Browser countdown is display-only and
periodically re-synchronizes; changing the device clock has no effect.

### Attempt lifecycle

1. Eligibility is evaluated and snapshotted.
2. A transaction locks the candidate row; a Redis lock reduces contention.
3. The server creates one active attempt and an immutable randomized manifest.
4. Candidate payload returns question presentation only—never answer keys.
5. Each answer save sends attempt ID, question ID, answer, client sequence, and a
   unique idempotency key.
6. The server validates ownership, manifest membership, state, and server deadline,
   then appends an answer revision and updates the current answer transactionally.
7. The response returns authoritative saved version/time. The browser retains an
   encrypted-at-rest-as-supported IndexedDB retry queue for network interruption.
8. Submission obtains a row lock, freezes answers, marks once, records checksum, and
   emits post-commit marking jobs.
9. The scheduler submits expired attempts using the same idempotent submission action.

Use short save intervals with debounce and explicit status indicators. Service workers
may improve recovery but never bypass server authorization. Essay text is saved in
revisions. Activity telemetry is risk evidence, not automatic proof of misconduct.

## Payment verification

All gateways implement an internal `PaymentGateway` contract. The browser redirect is
not proof of payment.

1. Create a local pending transaction with a random unique reference and expected
   amount/currency; never trust amount supplied after initialization.
2. Redirect/initiate using provider credentials from secrets.
3. Receive webhook raw body; verify provider signature before parsing business fields.
4. Store the event with unique provider event ID and body hash for replay protection.
5. Acknowledge promptly and process idempotently in a queue.
6. Query the provider verification endpoint where required.
7. Match reference, merchant account, amount, currency, and successful status.
8. In one database transaction, mark verified, post balanced ledger entries, allocate
   funds, update invoice state, and write an audit/outbox event.
9. Reconciliation jobs compare provider settlements with local ledger activity.

Duplicate events return success without duplicating credit. Reversals and refunds are
compensating ledger transactions requiring permission and reason.

## Transcript and certificate security

- Generate from an approved, versioned academic snapshot—not live mutable joins.
- Record template version, data checksum, generator, approver, issue time, and document
  hash.
- Queue rendering on trusted workers; store output privately and encrypt sensitive
  metadata where appropriate.
- Embed a QR URL containing a high-entropy opaque identifier, not student data.
- Verification pages expose a minimum data set (valid/revoked, holder display name,
  award, issue date, institution) and are rate-limited and monitored.
- Downloads require policy checks and short-lived signed URLs; email attachments are
  avoided where a secure delivery link is possible.
- Revocation does not delete history. It records reason, authority, timestamp, and
  replacement relation.
- Optional institution signing keys can create detached digital signatures. Keys live
  in KMS/HSM-backed storage with rotation and access audit.

## Threats and controls

| Risk | Primary controls |
|---|---|
| Cross-tenant data leak / IDOR | tenant context, scoped binding, policies, composite constraints, matrix tests |
| Privilege escalation | scoped RBAC, policy state checks, MFA readiness, role-change audit |
| Account takeover | strong hashing, throttling, email verification, MFA, session revocation, login alerts |
| CBT answer exposure | separate answer-key storage/query path, server marking, response tests |
| CBT replay/concurrency | active-attempt lock, idempotency keys, revision sequence, server time |
| Payment spoofing/replay | raw-body signatures, unique event IDs, server verification, ledger reconciliation |
| Result tampering | staged approval, immutable versions, locks, reasoned amendments, separation of duties |
| Malicious uploads | extension/MIME/signature checks, size limits, random keys, private storage, malware scan |
| Stored XSS | escaped Blade output, HTML sanitization for rich text, CSP, upload isolation |
| Data loss/ransomware | PITR, immutable/versioned off-site backups, restore drills, least privilege |
| Sensitive log leakage | structured redaction, no tokens/answers/secrets, restricted audit access |
| Queue/job tenant confusion | serialized tenant context, job middleware, tenant-aware cache/storage |
| PDF/QR forgery | approved snapshots, hashes/signatures, opaque verification, revocation registry |
| Insider misuse | least privilege, access logs, four-eyes approvals, anomaly reporting |

## Security baseline

- Secure cookies, CSRF protection, strict transport security, CSP, frame restrictions,
  content-type protections, and conservative referrer policy.
- Argon2id/bcrypt password hashing, password compromise checks where available, login
  throttling, session rotation, idle/absolute session expiry.
- Form Requests with allowlists; guarded models; output encoding and rich-text
  sanitization.
- Database users with least privilege; encrypted transport; sensitive field encryption
  with key rotation planning.
- Dependency lockfiles, automated vulnerability scanning, static analysis, secret
  scanning, and reviewed production configuration.
- Data classification, retention, export, correction, and deletion policies aligned to
  applicable law; academic/audit retention exceptions documented.
