# 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.
