# Conversion report

## Source inspection

The uploaded archive contains a compact staff application with a front controller (`public/index.php`), shared PHP views, PDO-based domain/import/mail functions, a PHP-defined database schema, CLI installation commands, CSS, a favicon, five example workbooks, five templates, and regression tests. There was no separate SQL dump, populated production database, JavaScript application, or embedded default staff password.

The resulting project runs through Laravel 12's standard bootstrap and HTTP kernel on PHP 8.2. The shipped lock file resolves Laravel 12.69.2. MySQL 8.4.6 and PHP 8.2.29 were used for verification.

## Module mapping

| Original responsibility | Laravel equivalent |
|---|---|
| Front controller / query-page navigation | `routes/web.php`, `PageController`, named workspace routes; legacy `?page=` and `/index.php` reads remain supported |
| Staff sign-in/out | `AuthController`, `LoginRequest`, Laravel session guard, `User`, password hashing, login rate limiting |
| Staff and role management | `AccountController`, `ActionRequest`, `admin` authorization gate, Eloquent `User` |
| Semester creation / open / close | `SemesterController`, `FulfillmentController`, `Semester`, validated named POST routes |
| Overview and reporting | `PageReadService`, dedicated Blade page views, common layout/alerts/pagination components |
| Student search and histories | Eloquent student pagination, related models, bound cross-table history queries, students Blade view |
| Approved books / course sections | `Requirement`, requirements view/read service, snapshot import rules |
| XLSX/CSV reading and safe XLSX export | `SpreadsheetService`; original one-sheet, expansion/row/column limits and ISBN validation retained |
| Upload → mapping → preview → commit | `ImportController`, `ActionRequest`, `ImportService`, private encrypted session draft, imports Blade view |
| Finance/registration/requirements snapshots | `ImportService`, atomic Laravel transactions, preserved missing-membership and dropped-demand behavior |
| Demand derivation and allocation | `FulfillmentService`, Eloquent demand relationships and locked code selection, unique database constraints |
| Registrar / publisher / Finance exports | `ExportController`, XLSX HTTP responses, `PublisherRequest`, unchanged request signatures and audit history |
| Editions, returns, refunds and referrals | `FulfillmentService`, `Issue`, `IssueEvent`, `IssueStudent`, `ProviderDelivery`, validated case actions |
| SMTP socket code and scheduled worker | Laravel Mail/Symfony SMTP transport, `OutboxService`, `scholarbooks:outbox`, Laravel scheduler |
| Audit trail | `AuditEntry`, centralized audit writer, paginated audit read service |
| PDO bootstrap/config | Laravel configuration, `.env.example`, Database facade/Query Builder, Eloquent, Laravel encryption |
| `install_schema()` | Two reversible Laravel migrations preserving 18 tables and adding supporting indexes |
| CLI install and fictional demo | `DatabaseSeeder`, `DemoSeeder`, `scholarbooks:demo` |
| Existing installation migration | `scholarbooks:import-legacy`, transactional copy with old-key decryption and Laravel re-encryption |
| Original tests | Adapted business regression suite, HTTP/security tests, separate MySQL migration/concurrency checks |

## Business behavior preserved

- Semester, course, section, publisher, and validated ISBN matching; titles remain descriptive.
- Finance omission creates a review hold, not silent deletion. Complete registration and requirements snapshots deactivate missing rows while retaining history.
- Globally unique access-code fingerprints, one allocation per demand/generation, and one lifetime allocation per code. Old codes are never silently recycled.
- Edition incidents require an external instructor decision. Replacement generations, old-code return confirmation, and sent replacement requirements are retained.
- Post-delivery drops create Finance referrals. Kortext delivery reports and refund confirmation remain separate from student activation.
- Repeated current imports and unchanged export requests are idempotent. Restoring an earlier complete snapshot remains possible.
- Outbox cancellation/restoration follows eligibility changes. Retries do not allocate another code. Explicit staff evidence is required to reconcile uncertain delivery.
- Requests, invoices, provider-platform changes, and refunds are still handled externally by staff. No new external integrations or unsolicited sending were introduced.

## Laravel integration and security

- Authentication uses Laravel's guard and sessions; inactive staff and sessions idle for 30 minutes are rejected. Login regenerates session IDs; logout invalidates sessions and CSRF tokens. Passwords use Laravel hashing and are never redisplayed.
- Named POST routes enforce authentication, current staff status, and an administrator gate. Form Requests validate actions, identifiers, enums, lengths, mapping indexes, and uploads. Domain services recheck semester/case state inside transactions.
- Laravel's web middleware supplies CSRF protection. There is no raw `session_start`, direct `$_POST`/`$_GET` dispatch, raw PDO connection, public setup endpoint, or hand-written SMTP socket in the converted application.
- Access codes, outbox bodies, and import drafts use Laravel authenticated encryption. Viewer pages do not decrypt code messages. Logs/audits do not intentionally contain raw access codes.
- Uploads are read from Laravel's private temporary upload path; no spreadsheet is copied to the public directory. The original ZIP expansion limits, XML entity rejection, XLSX formula rejection, checksum checks, and string-only XLSX exports are retained.
- Stock reservation now uses Eloquent and `lockForUpdate`, with a serialized application mutation lock and existing unique constraints. Laravel transaction retries cover deadlocks. Cross-table reconciliation and reporting queries that preserve intricate original semantics remain parameter-bound Laravel Database-facade queries; this is not an assertion that all SQL was eliminated.
- Students, requirements, imports, request histories, case lists, outbox lists, and audit entries now have server-side pagination. Small summaries and per-student histories remain complete.
- Original visual styling and favicon are copied unchanged. Blade layouts, individual page views, alerts, and pagination replace the original page includes. Some view preparation remains in Blade `@php` blocks to preserve the existing table/form markup; database read queries live in the read service.
- Error pages hide stack traces when `APP_DEBUG=false`. Security headers preserve the original no-script content policy, frame denial, no-sniff behavior, and private/no-store responses.
- Laravel Mail requires encrypted SMTP. A mail transport exception is conservatively marked uncertain. A newly covered edge case—SMTP acceptance followed by a database write failure—is also treated as uncertain to avoid an unsafe automatic retry.

## Database and operational differences

- All original business tables/columns remain. Integer IDs/foreign IDs use Laravel-compatible unsigned types; `users.remember_token` and supporting indexes are added. Original UTC timestamp strings remain to avoid reinterpretation of history.
- Laravel maintains a `migrations` table. Sessions/cache default to private files, so no new session or queue tables are required. The domain outbox remains the delivery queue.
- `login_attempts` is retained for data compatibility; new throttling uses Laravel's rate limiter.
- The old installation page and `bin/console.php` commands are replaced by migrations, seeders, and Artisan. No installation route is exposed publicly.
- Source MySQL migration is provided and tested. A source SQLite database requires a separate transfer to MySQL before using this importer.
- The migration importer assumes the source schema from this archive and positive IDs. Modified production schemas should be reviewed in a staging copy before migration.
- The default deployment uses one application server with file sessions/cache. Shared session/cache/locking configuration is required for multiple web nodes. SMTP remains synchronous in small batches, matching the original workflow; the scheduled outbox handles remaining messages.
- The bundled test-only passwords are not seeded into production. The original source ZIP excludes `.env` and keys. This domain-specific hosting edition additionally contains a private `.env` with a newly generated fresh-install key and credential placeholders; it excludes live database credentials, session files, test databases, and logs. Its vendor folder contains production dependencies only.

## Verification

See [docs/TESTING.md](docs/TESTING.md) for exact commands, final results, and limits. All 11 modules and protected detail screens were exercised through Laravel HTTP tests. Browser inspection covered login with a migrated account, the dashboard, and the import center. CSS and favicon hashes match the source. Live delivery to an external SMTP provider was not attempted; mail outcomes were tested with mocks and safe preview remained active.
