106 lines
4.4 KiB
Markdown
106 lines
4.4 KiB
Markdown
# Task 5 Report: Server-authoritative travel
|
|
|
|
## Outcome
|
|
|
|
Implemented the NestJS travel domain and public endpoints:
|
|
|
|
- `POST /api/travel`
|
|
- `GET /api/travel/current`
|
|
- injected deterministic/system clock abstraction
|
|
- exact `StartTravelDto` input validation
|
|
- stable idle, travelling, completed, and domain-error response shapes
|
|
- `TravelModule` registration in the application
|
|
|
|
Travel start and completion use `DataSource.transaction`. Both operations acquire a pessimistic write lock on the character row followed by the active travel row. Relations are deliberately not joined into either locking query, which keeps the queries compatible with TypeORM/PostgreSQL `FOR UPDATE` behavior. Due completion changes the travel status and character location through repositories owned by the same transaction; a failed second save rolls back both mutations.
|
|
|
|
No ambush evaluation or other later-slice logic was added. Existing untracked frontend images and the visual asset guide were preserved and excluded from the commit.
|
|
|
|
## RED evidence
|
|
|
|
Command:
|
|
|
|
```powershell
|
|
npm test --workspace=@ashen-realms/api -- travel.service.spec.ts travel.controller.spec.ts --runInBand
|
|
```
|
|
|
|
Initial result: exit code 1. Both suites failed to resolve the missing production modules:
|
|
|
|
```text
|
|
Cannot find module './travel.service' from 'travel/travel.service.spec.ts'
|
|
Cannot find module './travel.controller' from 'travel/travel.controller.spec.ts'
|
|
Test Suites: 2 failed, 2 total
|
|
Tests: 0 total
|
|
```
|
|
|
|
The active-travel regression test was also mutation-checked. Temporarily removing the `TRAVEL_ALREADY_ACTIVE` guard produced the expected focused failure (`Expected constructor: TravelDomainError; Received constructor: Object`); restoring the guard returned the test to green.
|
|
|
|
## GREEN evidence
|
|
|
|
Focused travel tests:
|
|
|
|
```powershell
|
|
npm test --workspace=@ashen-realms/api -- travel.service.spec.ts travel.controller.spec.ts --runInBand
|
|
```
|
|
|
|
```text
|
|
Test Suites: 2 passed, 2 total
|
|
Tests: 9 passed, 9 total
|
|
Time: 10.973 s
|
|
```
|
|
|
|
The service suite covers all five required behaviors plus active-travel rejection, public current-travel mapping, idempotent repeat completion, pessimistic-lock observation, and rollback when the second completion save fails. The controller suite drives a real Nest HTTP pipeline and verifies that server-owned timestamp/duration fields receive HTTP 400.
|
|
|
|
Full API suite:
|
|
|
|
```powershell
|
|
npm test --workspace=@ashen-realms/api -- --runInBand
|
|
```
|
|
|
|
```text
|
|
Test Suites: 7 passed, 7 total
|
|
Tests: 18 passed, 18 total
|
|
Time: 15.87 s
|
|
```
|
|
|
|
API E2E:
|
|
|
|
```powershell
|
|
npm run test:e2e --workspace=@ashen-realms/api -- --runInBand
|
|
```
|
|
|
|
```text
|
|
Test Suites: 1 passed, 1 total
|
|
Tests: 2 passed, 2 total
|
|
Time: 9.406 s
|
|
```
|
|
|
|
API build:
|
|
|
|
```powershell
|
|
npm run build:api
|
|
```
|
|
|
|
Result: exit code 0 (`nest build`).
|
|
|
|
Formatting and lint:
|
|
|
|
```powershell
|
|
apps/api/node_modules/.bin/prettier.cmd --check <Task 5 files>
|
|
node_modules/.bin/eslint.cmd <Task 5 files>
|
|
```
|
|
|
|
Both commands exited 0. Prettier reported `All matched files use Prettier code style!`; ESLint reported no findings.
|
|
|
|
## Integration notes and self-review
|
|
|
|
- The first build exposed TypeScript `TS1272` for a decorated `Clock` parameter under `isolatedModules`; importing `Clock` as a type fixed the root cause, after which tests and build were rerun.
|
|
- Registering the database-backed `TravelModule` exposed that the existing health E2E test replaced `DatabaseModule` and `CharactersModule` but not travel. The harness now replaces `TravelModule` as well, preserving the database-free health test.
|
|
- Lock order is identical in start and completion, reducing deadlock risk.
|
|
- The character row serializes concurrent starts even when no active travel row exists yet; the partial unique database index remains the final invariant.
|
|
- The due comparison treats `arrivesAt === now` as due and never moves the character earlier.
|
|
- Public responses contain only location summaries and travel timestamps/status, never entities, duration input, ambush probability, or persistence metadata.
|
|
|
|
## Remaining concern
|
|
|
|
No live-PostgreSQL travel integration test was added because the repository's current E2E harness intentionally runs without a database; clean migration/seed/API database smoke coverage belongs to Task 10. The transaction code uses supported real `EntityManager.getRepository`, `Repository.findOne` lock options, `findOneBy`, `create`, and `save` behavior, and the stateful fake verifies transaction commit/rollback semantics rather than mock call counts.
|