Overview
New application built at Osky Interactive for a client project. The client's master records came from a legacy system export. NAD brings that data into a database the client's own staff can edit, review, and export, with every change traceable. I was the main developer on phase one, from the data layer through the screens.
Approach
The app is Laravel 13 on PHP 8.3, with Inertia.js 2 serving a React 18 front end, so there is no separate API to maintain for the admin screens. The schema came first. The import, the master records, and the history tables were designed together, because every later feature (merging, notifications, exports) depends on being able to say who changed what and when.
Work moved in weekly slices. Each slice landed as its own branch with tests, so the client could review real screens on the development site instead of mockups. One early slice was rebuilt rather than rebased when the data model changed underneath it, which kept the history clean and the new code honest about its assumptions.
Every change runs through PHPUnit for behavior, PHPStan through Larastan at level 7 for types, and Laravel Pint for style. GitHub Actions runs the test suite and deploys the development and staging environments.
Tech Stack
| Layer | Technology |
|---|---|
| Backend | Laravel 13, PHP 8.3 |
| Frontend | React 18 via Inertia.js 2, Tailwind CSS 3, Vite |
| Database | MySQL |
| Testing | PHPUnit |
| Code quality | PHPStan (Larastan, level 7), Laravel Pint |
| CI/CD | GitHub Actions |
Key Implementation Details
- Master spreadsheet import as a staged pipeline: upload, validate, review, decide on likely duplicates, then commit into the master tables, so nothing reaches the live records unchecked
- Record merge and unmerge backed by stored snapshots and an append-only merge trail, so any merge can be explained later and reversed
- Change history on every master record, with status changes that require a reason
- Access checked by permission rather than by role across screens, routes, and exports
- Email notifications on status changes, merges, and unmerges, with recipients derived from the data instead of a hand-kept list
- Shared front-end components (page containers, section headings, a stepper, button styles) extracted once the screens settled
Outcome
Phase one reached the client's staging environment in September 2026 with more than 1,100 PHPUnit tests and static analysis at PHPStan level 7. The client reviews each slice on a live environment, and follow-up tickets are handled in the same branch-per-slice flow.