- Removed `Module` and `ModuleRepository` compatibility shims.
- Replaced NWIDART `Module` facade usages with the new `AddonRegistry`.
- Updated frontend controllers to use `AddonRegistry` for module handling.
- Added new feature tests to cover `AddonRegistry` lifecycle and rebuild cases.
- Updated bootstrapping logic and service bindings to drop NWIDART dependencies.
# Conflicts:
# app/Models/Flight.php
# app/Support/Utils.php
New Filament page at /admin/route-forge: compose dozens of scheduled
flights across five topologies (Hub→Spokes, Spokes→Hub, Hub & Spokes,
Mesh, Chain), preview rows live, lint for operational issues, commit
as one Flight Bundle in a single atomic transaction.
Frontend: TypeScript + Preact 10 + @preact/signals + @date-fns/tz.
Separate Vite entry, 26.69 KB gzip (well under the 60 KB target).
Client-side generator + 12 lint rules; localStorage draft resume.
Backend: RouteForge service + 12 PHP lint rule classes + duplicate
checker + commit orchestration (Flight::withoutEvents + single
bundle-level activity log). Six endpoints under
/admin/route-forge/api/, gated by permission:create:flight.
Bundle picker is dual-mode — type a new name to create, or pick an
existing bundle to append flights to (read-only summary, server skips
the bundle persist step and stamps the existing id onto new flights).
Airport picker: click-to-open dropdown with 50-result alpha pages,
checkbox rows for multi-select, prefix-only search via new
searchMode=prefix opt-in on the shared AirportSearchQueryV1
(/api/airports default substring behavior preserved).
Quality: tsc strict mode clean, oxlint 0/0, phpstan no errors,
pint passing. Pest scaffolding deferred per workflow.
Tracking: openspec/changes/route-forge — 66/106 tasks complete
(sections 1, 2, 4, 5, 6, 7, 8; Pest 4.6/5.3/6.4 + sections 9–12
remaining).
# Conflicts:
# package-lock.json
# package.json
* wip
* refactor: update enum handling and improve type hints across models
* refactor: deprecate labels and select methods in HasSelect trait for better separation of concerns
* copilot suggestions
* refactor: Casts, Observers and Traits
* refactor: replace Sluggable observer with HasSlug trait in models
* test: add HasSlug trait tests for slug generation and uniqueness
* refactor: rename resource classes for consistency and update references
* refactor: update return type of index method to use AnonymousResourceCollection
* refactor: simplify slug generation in HasSlug trait and update tests for consistency
* refactor: update namespace annotation in UserBidResource for clarity
* apply coderabbit suggestions
* fix tests
* chore: remove prettus/l5-repository (Phase 8 cleanup)
Phase 8 of the Prettus repository removal. Phases 1-7 deleted all 25 concrete
repositories and rewired callers; this drops the package itself plus the
remaining scaffolding.
- Migrate Sluggable observer registration from ObserverServiceProviders boot
to #[ObservedBy(Sluggable::class)] attributes on FlightField, FlightFieldValue,
Page, PirepField, PirepFieldValue.
- Delete app/Providers/ObserverServiceProviders.php, app/Contracts/Repository.php,
app/Repositories/ (incl. Criteria/WhereCriteria.php), config/repository.php.
- Drop RepositoryServiceProvider and ObserverServiceProviders from config/app.php.
- Sweep dead 'use Prettus\Validator\Exceptions\ValidatorException' imports from
10 files plus the 12 orphaned '@throws ValidatorException' docblock lines that
PHPStan would otherwise flag as throws.notThrowable.
- Move pagination default from deleted config/repository.php to config/phpvms.php
('pagination.limit' => 20, matches historical value). Update 8 prod callers +
2 test sites to read 'phpvms.pagination.limit'.
- Drop App\Contracts\Repository exception from tests/Arch/GlobalTest.php
http-helpers rule.
- composer remove prettus/l5-repository (drops prettus/laravel-validation
transitively).
No public API, JSON shape, or behavior change. Pint, PHPStan level 5, Pest, and
Rector --dry-run all pass; the 7 pre-existing CSRF/ProfileUpdated test failures
on main remain unchanged.
* fix(pagination): default 50, max cap 100, central paginate_limit() helper
Address PR #2202 review feedback (CodeRabbit + Copilot):
- config/phpvms.php: pagination.limit = 50 (default page size),
pagination.max = 100 (hard cap on ?limit= query input).
- Add paginate_limit() helper in app/helpers.php that resolves the raw
?limit= value, falls back to pagination.limit, and clamps to
[1, pagination.max]. Single source of truth for per-page sanitization.
- Replace ad-hoc `$request->query('limit') ?: config(...)` patterns in
8 controllers with paginate_limit():
- Api: AirportController, FleetController, FlightController,
NewsController, UserController (fleet + pireps)
- Frontend: FlightController, PirepController, UserController
Frontend/UserController previously used 20 as fallback default; now
consistent with the rest of the app at 50.
- SearchAirportsRequest validator now bounds ?limit= against
pagination.max (100) instead of pagination.limit (50), so callers can
request the full clamp range. Add boundary test asserting limit=100
passes and limit=101 fails.
Net effect: API endpoints can no longer be coerced into oversized result
sets via ?limit=. Default page size moves from 20 to 50 to match the
review consensus.
* feat(journal): add JournalService, JournalTransactionQuery, model methods
Move balance math onto Journal model as instance methods returning Money:
- recalculateBalance(): self
- getCreditBalanceBetween(Carbon, ?Carbon, ?string): Money
- getDebitBalanceBetween(Carbon, ?Carbon, ?string): Money
Convert $casts to casts() method.
Add JournalService for writes (post, deleteAllForObject) — drops the
dead try/catch around ValidatorException; deleteAllForObject iterates so
JournalTransactionObserver fires (preserves cached balance).
Add JournalTransactionQuery as plain class for ref-model lookups
(replaces JournalRepository::getAllForObject). No FormRequest — no HTTP
endpoint drives it; arguments are object/journal/date.
Modernize observers with #[ObservedBy] on Journal and JournalTransaction;
remove imperative ::observe registrations from ObserverServiceProviders
to prevent double-firing.
Phase 7 setup commit. Callers still use JournalRepository; migration
follows in next commit.
* refactor(journal): migrate callers to JournalService and Journal model
FinanceService, PirepFinanceService, Api/PirepController, and the nightly
RecalculateBalances cron now use JournalService::post/deleteAllForObject,
Journal::recalculateBalance, and JournalTransactionQuery::build directly.
JournalService::post takes Eloquent\Model (not App\Contracts\Model) so
User references keep working without a wrapper. Drops dead ValidatorException
import and stale @throws docblocks now that Prettus is out of the call path.
The Phase 0 deleteAllForObject characterization test moves to
tests/Unit/JournalServiceTest.php with assertions intact.
* feat(repos): remove JournalRepository (Phase 7)
Last journal repository deleted. Reads now go through Journal model
(balance math) and JournalTransactionQuery (transaction lookups);
writes go through JournalService.
Drops the phpstan ignoreErrors entry that masked Repository magic-method
calls — no real repos remain in app/Repositories/, only Criteria/.
* fix(journal,finance): address latent bugs found in Phase 7 review
PirepService::delete now drops the pirep's journal entries before the
forceDelete. The polymorphic ref_model_id has no FK constraint, so
without explicit cleanup those rows would dangle — still summed by
nightly recalculate, skewing journal balances. Inject PirepFinanceService
to call deleteFinancesForPirep first.
JournalService::post now uses $journal->currency (with the system
setting as fallback) for the transaction.currency column. The legacy
behavior unconditionally stamped the system setting regardless of the
target journal's currency, so a non-default-currency journal could
silently log transactions in the wrong currency.
JournalTransaction::casts() had a typo: 'credits' (plural, no such
column) instead of 'credit'. Result: $tx->credit came back uncast
(string from MySQL bigint). Mostly masked by PHP coercion and
SUM() returning numeric, but a real risk for any code doing direct
arithmetic on $tx->credit.
JournalTransactionObserver renamed saved → created so that updates to
a JournalTransaction no longer re-add its credit/debit to the cached
journal balance. saved fires on both insert and update; created fires
only on insert.
PirepFinanceService::processFinancesForPirep wraps the delete + 9 pay*
calls in DB::transaction. A partial failure mid-pay would otherwise
leave the journal half-cleared with new entries on top.
JournalTransactionQuery::build replaces the broken
where('post_date', '=', Y-m-d) with whereDate. The legacy '=' compare
against a datetime column would silently match nothing for any row
not posted at midnight UTC. No production caller passes $date today,
so this is a dead-code fix — but the code is now correct.
Adds clarifying docblock notes on Journal::recalculateBalance (sums
unfiltered by post_date — disagrees with getCurrentBalance when
future-dated rows exist) and Journal::getCreditBalanceBetween
(whereDate day-precision vs getCreditBalanceOn datetime-precision).
* fix(journal,finance): address PR review feedback
CRITICAL
- JournalTransaction tags cast was 'array' but post() stores as
CSV string. JSON decode of CSV returned null on read. Switch
cast to 'string' to match storage format.
MAJOR
- PirepController finances_get / finances_recalculate now use
findOrFail so a missing id yields 404 instead of a 500 type
error from JournalTransactionQuery::build's non-nullable param.
- PirepService::delete is now wrapped in DB::transaction so
partial-delete failures roll back. Same pattern as
processFinancesForPirep.
- FinanceTest 'pirep expenses nightly' assertion was tautological
(toHaveCount on the 3-key array shape always passes). The test
also lacked initJournal calls and queried by ref_model=Airline
even though processExpenses posts with ref_model=Expense. Fixed
by calling initJournal and counting transactions on each
airline's journal directly.
MINOR
- JournalTransactionQuery copy()'s the Carbon argument before
setTimezone so callers don't see their instance mutated.
- Reverted the whereDate change for post_date (column is DATE,
not DATETIME, so the legacy = compare was correct and uses the
index; whereDate disables it).
- Switched JournalTransactionQuery to getKey() over ->id so the
read path matches JournalService::deleteAllForObject.
NITPICKS
- RecalculateBalances cron uses chunkById(500) instead of all().
- JournalService::deleteAllForObject uses lazyById for memory
safety on large cleanups.
- JournalService gets declare(strict_types=1).
- processFinancesForPirep declares its Pirep return type.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Switched many backend lookups to use centralized model-driven queries;
flight searching rebuilt with a new query flow for richer filtering,
multi-column sorting, and optional pagination.
* **Bug Fixes**
* Missing-record lookups now consistently return not-found responses;
diversion handling reliably reuses or creates reposition flights;
airline/flight selection lists and visible flight-type filtering
improved.
* **Tests**
* Added extensive unit and feature tests covering search, bids,
finances, ACARS, diversion, and related behaviors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
PirepSearchQuery::applySearch carried a defensive 'like' branch
suppressed via @phpstan-ignore. FIELD_SEARCH only contains '='
operators, so the branch was unreachable. Reshape FIELD_SEARCH to
list<string> + drop the branch. YAGNI: 1-line revert if a future
field needs LIKE.
Frontend/PirepController::index no longer throws RepositoryException
(removed with prettus). Drop the @throws docblock; pint nukes the
now-unused import.
SearchPirepsRequest validates ?status= as a documented filter, but
the controller only branched on ?state=. Clients passing ?status=
got their filter silently ignored. Wire it through.
* test(setting): characterization tests for setting() helper + API shape
* refactor(setting,expense): add #[Scope] + #[ObservedBy] + casts() + drop dead $rules
* feat(services): add SettingService with cache-aware store/retrieve
* feat(finance): add FinanceService::getExpensesForType
* refactor(setting): migrate setting()/setting_save() helpers to SettingService
* refactor(setting): migrate Api controller, Filament page, importer, test helper to SettingService
* refactor(expense): migrate PirepFinanceService, ExportAction, FinanceTest to FinanceService::getExpensesForType
* refactor(setting,expense): delete SettingRepository and ExpenseRepository
* test(setting): use Setting::byKey scope in characterization test
* refactor(setting): drop redundant Cache::forget in Maintenance page
SettingService::store() now invalidates the per-key cache slot internally
(introduced in d9c94195). Manual Cache::forget calls after setting_save()
became dead code in this branch, mirroring the same cleanup applied to
Filament/Pages/Settings.php in 31aa55da. Drops the now-unused Cache import
as well — caught by deep review.
* fix(setting): increment count in SettingsImporter run
Pre-existing bug. $count was declared but never incremented, so the
import log always read 'Imported 0 settings' regardless of how many
settings the legacy importer actually wrote.
Found during Phase 5 deep review.
* refactor(filament): wrap settings save in DB::transaction
The Filament Settings page writes N setting rows in a foreach loop,
then calls FinanceService::changeJournalCurrencies() which rewrites
journal + journal_transaction rows to a (potentially) new currency.
A throw mid-loop or mid-currency-migration left the DB with half-saved
settings or a half-migrated journal.
Wrap both halves in a single DB::transaction() so a partial failure
rolls back all writes atomically.
Found during Phase 5 deep review.
* refactor(services): declare strict_types=1 across app/Services/
Phase 5 introduced declare(strict_types=1); in SettingService.php only.
This commit applies the same declaration to the remaining 65 service
files for consistency.
65 files migrated. 6 files required minimal signature/cast adjustments
to handle existing caller patterns where strict mode exposed implicit
type coercion at runtime or in phpstan:
- FareService::recalculateFares cast $pivot->capacity to (float)
before floor() (DB returns string).
- Finance/RecurringFinanceService::processExpenses cast
$expense->ref_model to (string) before explode() (nullable column).
- AirportLookup/VaCentralLookup, GeoService: pass $e->getMessage()
to Log::error() instead of the Exception object.
- DatabaseService::time() cast Carbon to (string) (return type contract).
- ModuleService::installModule pass $file->getRealPath() to PharData
and Madzipper::make() (UploadedFile -> string path).
No files reverted. No tests modified.
Found during Phase 5 deep review (convention drift).
* style(setting): align match arms for pint 1.29.1
Pint 1.29.1 aligns => arrows in match expressions under
binary_operator_spaces (with align_single_space_minimal). 1.29.0 did
not. CI installs latest globally and fails on the un-aligned form.
Bumped composer.lock so local matches CI.
* Update app/Services/Finance/RecurringFinanceService.php
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* refactor(installer): add strict types to LoggerTrait
LoggerTrait declared strict_types=1 but methods had no parameter or
return types. Added: comment(string $text): void, info(string $text):
void, error(string $text): void.
FlightImporter:59 was passing a Throwable to error() — switched to
$e->getMessage() to match the new contract. Same pattern applied in
5b2133a8 to VaCentralLookup and GeoService.
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Fix issues raised by code review on Phase 4:
- UserController::index now honors validated `?limit` query param via
paginate($request->integer('limit') ?: config('repository.pagination.limit', 15)),
matching the convention used in NewsController, FleetController, AirportController.
- UserSearchQuery::applySearch joins multi-pair field-specific search with OR
(matching the legacy Prettus RequestCriteria default and the documented behavior
in SearchUsersRequest's PHPDoc), and falls back to free-text when a colon-prefixed
payload contains no allowlisted fields (e.g. "8:30") instead of silently returning
all users.
- Role::byName docblock corrected: case-sensitivity follows the database collation
(case-sensitive on SQLite, case-insensitive on MySQL utf8mb4_unicode_ci) rather
than being a guarantee of the scope itself.
- UserService::getUserFields PHPDoc rewritten to describe the actual three-valued
contract: true=public-only, false=private-only, null=all visibility-allowed.
- Trivial scope tests removed: deleted RoleScopesTest entirely (both cases were
smoke tests of where() with no real signal, one was even mis-named) and trimmed
UserScopesTest to keep only the composition test that proves #[Scope] chaining
works. The single-where scope tests are tested implicitly by feature tests.
- New UserSearchQueryTest cases lock the OR-join and free-text-fallback behaviors.
Code review caught: User::find() returns null on missing user, then
foreach ($user->bids) NPEs to 500. Old Prettus userRepo->find() called
findOrFail under the hood, throwing ModelNotFoundException for clean 404.
Restore old contract via User::findOrFail().
- Frontend/AirportController: drop airportRepo, use
Airport::with('files')->find($id) ($id was already uppercased
earlier in the method)
- Frontend/PirepController: drop airportRepo from constructor
(only reference was a commented-out selectBoxList call). Phase
2 precedent (Aircraft was the same case).
- Filament/Actions/ExportAction: AIRPORT case uses Airport::all()
- Delete app/Repositories/AirportRepository.php (dead selectBoxList
goes with it)
- phpstan.neon: suppress larastan.relationExistence for
FilesTrait::files() across Aircraft/Airline/Airport/Subfleet.
The morphMany is trait-defined and works at runtime, but
larastan can't statically resolve trait-declared polymorphic
relations. First direct Eloquent with('files') call lands in
this commit, hence the new suppression.
Final commit of Phase 3. AirportRepository is gone; 9 repositories
remain (was 10 at branch start). First Query class
(AirportSearchQuery) and search Form Request (SearchAirportsRequest)
are now in production, ready to be reused by Phases 4/6/7.
- index() and search() use AirportSearchQuery + SearchAirportsRequest
- index_hubs() uses Airport::byHub()->orderByIcao()
- get(Airport $airport) uses route model binding (case-insensitive
via Airport::resolveRouteBinding)
- routes/api.php: rename airports/{id} -> airports/{airport} so
Laravel binds to the typed parameter (URL format unchanged)
- Drop AirportRepository injection and Prettus criteria use
- Match Phase 2's perPage() pattern for ?limit= handling
- Add regression test asserting lowercase ICAO routes resolve
Public API contract preserved: ?search=field:value syntax, ?hub=,
?hubs=, ?limit=, ?orderBy=, ?sortedBy= all continue to work.
Drops un-tested Prettus magic params (?with, ?withCount, ?filter,
?searchFields, ?searchJoin) — narrows the public contract to what's
actually exercised.
Phase 2 of the prettus/l5-repository removal. Deletes 3 Fleet-domain
repositories and migrates their callers to direct Eloquent. Introduces
the first #[ObservedBy] attribute migrations on Aircraft and Subfleet.
## Repositories deleted
- NavdataRepository (2 callers, no unique methods)
- AircraftRepository (6 callers, dead selectBoxList() also dropped)
- SubfleetRepository (5 callers, selectBoxList() ported as private
helper on FlightController — its only caller)
## Caller migrations
- Filament/Actions/ExportAction: inline Aircraft::orderBy()->get(),
Subfleet::all() (2 cases)
- Api/FleetController: empty constructor; Subfleet::with()->paginate(),
Aircraft::with()->where()->first(); explicit ?limit= handling
- Api/UserController: Aircraft::find() (findWithoutFail → find);
passes $perPage explicitly to UserService::getAllowableSubfleets
- Api/NewsController: explicit ?limit= handling restored (was lost in
Phase 1 when migrating from the Repository contract's paginate()
override at app/Contracts/Repository.php:112-129)
- Frontend/PirepController: constructor surgery + findOrFail/find swaps
- Frontend/FlightController: constructor surgery; ported subfleetSelectBoxList()
with null-safe airline access
- Services/PirepService: constructor surgery + Aircraft::find / where
- Services/UserService: constructor surgery; Subfleet::when()->with();
through() instead of transform() to preserve LengthAwarePaginator
wrapper when paginating; $perPage parameter to keep request() out
of services (Tests\Arch\GlobalTest forbids it)
- Services/AirlineService::canDeleteAirline: partial rewire (subfleet
uses Subfleet::where()->exists(); pirep/flight repos remain for
their phases)
- Services/FlightService: Navdata::whereIn('id', $route_points)->get()
- Services/GeoService: Navdata::where('id', $route_point)->get();
dropped dead ModelNotFoundException catch (where()->get() never
throws that)
## Model modernizations
- Aircraft: drop dead public static array $rules; attach
#[ObservedBy(AircraftObserver::class)]
- Subfleet: drop dead $rules; convert public $casts property to
protected casts() method (Laravel 11+ form); attach
#[ObservedBy(SubfleetObserver::class)]
- ObserverServiceProviders: remove the imperative Aircraft::observe()
and Subfleet::observe() lines + their now-unused imports. Other
observer registrations (Airport, Flight, Journal, Setting, User,
Sluggable) stay until their domain phases.
## Pagination contract preserved
paginate($limit)->appends($request->except(['page', 'user'])) on
all three migrated paginated endpoints (/api/fleet, /api/news,
/api/user/fleet). Mirrors the deleted Repository contract exactly,
including the 'user' exclusion (the test framework's auth middleware
leaks the full User model into request()->query() — without exclusion,
next_page URLs would carry the serialized User as query params).
## New tests
- Tests\Unit\AirlineTest: 'cannot delete airline with subfleet' and
'can delete airline with no associations' — the rewired branch had
no direct coverage and the all-clear happy path was untested.
- Tests\Feature\ApiTest: 3 new pagination contract tests for /api/fleet,
/api/news, and /api/user/fleet — assert meta.per_page matches the
requested limit AND meta.next_page (the codebase's
CustomPaginatedResourceResponse moves it there from links.next)
contains the original ?limit= forward.
## Known trade-off
GeoService::parseRoute previously enjoyed a 5-minute Prettus result
cache via findWhere; the new direct Navdata::where()->get() is
uncached. Acceptable: PK lookup on a small indexed table.
## Verification
- 240 Pest tests pass (1630 assertions); 0 failures
- PHPStan level 5: no errors
- Pint: pass
- 13 → 10 repositories
- 0 remaining references to AircraftRepository, SubfleetRepository,
or NavdataRepository (one docblock breadcrumb in FlightController
is intentional documentation)
## Followups
Tracked locally in docs/superpowers/followups.md:
- F2.1: Form Request validation pass on legacy controllers (raised
by review on PirepController::fares — pre-existing semantic match
with Prettus's find() throw-on-miss)
- F2.2: perf(filament/export): eager-load relations in CSV exporters
to eliminate N+1 (raised by review on ExportAction — pre-existing
in deleted repo code)
Applies in-scope cleanups flagged during code review on PR #2190:
- helpers.php: fix stale "KVP repository" docblocks (→ "KVP service");
rename local $kvpRepo → $kvpService; add ": void" return type and
correct docblock on kvp_save() (it persists, not reads).
- Api/NewsController::index(): add explicit
": AnonymousResourceCollection" return type to replace stale
"@return mixed" (the method body was rewritten in this PR).
- LegacyImporterService::$kvpRepo: type as KvpService instead of
mixed — the @var docblock was updated in the rename commit but the
property type was not.
- NewsService::deleteNews(): switch from News::findOrFail(\$id)->delete()
to News::whereKey(\$id)->delete() so it stays idempotent, matching
the null-return style of updateNews(). Matches old repo-layer
semantics (silent no-op on missing id).
- NewsService: direct News::create/find/fill+save/delete calls, no more
repo dependency
- Api/NewsController: News::with/latest/paginate instead of repo chain
- LatestNews widget: same, using Eloquent latest() and paginate()
- Remove dead public static array $rules from News model (unused by
anything — was a Prettus validator hook that was never activated)
The Phase 0 NewsListShapeTest locks the JSON contract, so API
consumers see no behavioral difference.
Part of Phase 1b of the Prettus repository removal.
Added a #[Scope] bySlug($slug) method to Page model for the common
slug-lookup pattern. PageController and PageLinksComposer updated to
use the scope and direct Eloquent respectively.
Uses Laravel 11+ #[Scope] attribute syntax as per spec.
Part of Phase 1b of the Prettus repository removal.
Three callers all used plain Eloquent methods (all, whereIn) via the
repo layer. Replaced with direct PirepField::... calls. The repo
had no custom methods.
- PirepController (Frontend): 3 whereIn() call sites
- CreatePirepRequest, UpdatePirepRequest: all() call
Part of Phase 1b of the Prettus repository removal.
The /api/news index endpoint paginates News records and serializes them
through NewsResource, which dereferences $this->user. Without the
eager load, multi-item responses would lazy-load on each iteration
(now fatal because preventLazyLoading is enabled).
Bumped the response-shape test to count(3) so the eager load is
genuinely exercised; the previous count(1) masked the N+1.
Enable Laravel's preventLazyLoading in dev/test environments to catch
N+1 query regressions during the upcoming repository refactor phases.
Fixes 3 distinct N+1 patterns revealed by the check (7 failing tests):
- Expense::ref_model: eager-load in ExpenseRepository::getAllForType
and RecurringFinanceService::processExpenses (also in ImporterTest).
- Flight::airline: eager-load in SetActiveFlights::checkFlights where
the Flight::ident accessor triggers lazy load via Log::info.
- Pirep::aircraft: add 'aircraft' to the eager loads in
Api/UserController::pireps so the Pirep Resource doesn't lazy load
aircraft during response serialization.
Part of Phase 0 for the Prettus repository removal.