From 39b1b806d99bfedd9ef8a0675c170989896c1651 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kristian=20St=C3=B6ckel?=
Date: Sat, 17 Oct 2026 18:02:45 +0200
Subject: [PATCH] :fire: remove deprecated DepartureResource fields
---
API_CHANGELOG.md | 4 +-
app/Http/Resources/DepartureResource.php | 36 +------------
.../Stationboard/DepartureEntry.vue | 4 +-
.../pages/Stationboard/Stationboard.vue | 22 ++++----
resources/types/Api.gen.ts | 48 -----------------
resources/types/Departure.ts | 25 ---------
.../components/Checkin/CheckinInterface.vue | 10 ++--
.../components/Checkin/StationBoardEntry.vue | 4 +-
resources/vue/components/CheckinLineRun.vue | 14 ++---
resources/vue/components/Stationboard.vue | 50 +++++++++--------
storage/api-docs/api-docs.json | 54 -------------------
11 files changed, 57 insertions(+), 214 deletions(-)
diff --git a/API_CHANGELOG.md b/API_CHANGELOG.md
index 77ab8610c0..99d922b9a4 100644
--- a/API_CHANGELOG.md
+++ b/API_CHANGELOG.md
@@ -15,7 +15,6 @@ Check back here regularly to stay ahead of removals.
| Announced | What? | Safe until | PR |
|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|---------------------------------------------------------------|
-| 2026-04-01 | `DepartureResource.stop.*` is deprecated → use `DepartureResource.station` instead | 2026-09-30 | [#4663](https://github.com/Traewelling/traewelling/pull/4663) |
| 2026-04-07 | `OperatorResource.id` is deprecated as integer: will become a UUID after 2026-09-30. prefer `uuid` instead while migration-period | 2026-09-30 | [#4676](https://github.com/Traewelling/traewelling/pull/4676) |
| 2026-05-14 | `POST /api/v1/trains/checkin` 409 response: `message.status_id` and `message.lineName` are deprecated. Use `data.conflicts` (full `StatusResource` array) instead | 2026-10-31 | [#4677](https://github.com/Traewelling/traewelling/pull/4677) |
| 2026-07-19 | `StopoverResource.id` is deprecated as station ID: it currently holds the station ID (not unique within a trip). Use `station` for station details. After the safe-until date `id` is repurposed to the unique stopover ID | 2026-11-30 | [#4959](https://github.com/Traewelling/traewelling/pull/4959) |
@@ -34,7 +33,8 @@ Removed the following deprecated fields, announced in 2026-03 and 2026-04:
- `DepartureResource.destination`: use `direction` instead
- `DepartureResource.line.productName`: use `line.name` instead
- `DepartureResource.provenance`, `remarks`, `origin`, `currentTripPosition`, `loadFactor` and `line.operator`: were always `null`
-- `DepartureResource.stop.products`, `line.public` and `line.adminCode`: were always placeholder values
+- `DepartureResource.line.public` and `line.adminCode`: were always placeholder values
+- `DepartureResource.stop`: use `station` instead
- `CheckinSuccessResource.points.additional` (`POST /trains/checkin`): was always `null`
- `WebhookResource.clientId` (`/webhooks`): use `client.id` instead
- `WebhookResource.userId` (`/webhooks`): use `user.id` instead
diff --git a/app/Http/Resources/DepartureResource.php b/app/Http/Resources/DepartureResource.php
index b23b09e710..0c7eeefff2 100644
--- a/app/Http/Resources/DepartureResource.php
+++ b/app/Http/Resources/DepartureResource.php
@@ -5,38 +5,15 @@
namespace App\Http\Resources;
use App\Dto\Internal\Departure;
-use App\Enum\StationIdentifierType;
use Illuminate\Http\Resources\Json\JsonResource;
use OpenApi\Attributes as OA;
#[OA\Schema(
title: 'Departure',
description: 'A single departure at a station',
- required: ['tripId', 'stop', 'when', 'plannedWhen', 'platform', 'plannedPlatform', 'direction', 'line', 'cancelled', 'station'],
+ required: ['tripId', 'when', 'plannedWhen', 'platform', 'plannedPlatform', 'direction', 'line', 'cancelled', 'station'],
properties: [
new OA\Property(property: 'tripId', description: 'Unique trip identifier', type: 'string', example: '1|200513|0|81|6012023'),
- new OA\Property(
- property: 'stop',
- description: 'The stop at which this departure occurs',
- properties: [
- new OA\Property(property: 'type', type: 'string', example: 'stop', deprecated: true),
- new OA\Property(property: 'id', description: 'Träwelling internal station ID', type: 'integer', example: 5181, deprecated: true),
- new OA\Property(property: 'name', type: 'string', example: 'Karlsruhe Hbf', deprecated: true),
- new OA\Property(
- property: 'location',
- properties: [
- new OA\Property(property: 'type', type: 'string', example: 'location', deprecated: true),
- new OA\Property(property: 'id', description: 'IBNR identifier (if available)', type: 'string', example: '8000191', nullable: true, deprecated: true),
- new OA\Property(property: 'latitude', type: 'number', format: 'float', example: 48.993207, deprecated: true),
- new OA\Property(property: 'longitude', type: 'number', format: 'float', example: 8.400977, deprecated: true),
- ],
- type: 'object',
- deprecated: true,
- ),
- ],
- type: 'object',
- deprecated: true,
- ),
new OA\Property(property: 'when', description: 'Actual departure time (null if no realtime data)', type: 'string', format: 'date-time', example: '2023-01-06T13:49:00+01:00', nullable: true),
new OA\Property(property: 'plannedWhen', description: 'Scheduled departure time', type: 'string', format: 'date-time', example: '2023-01-06T13:49:00+01:00'),
new OA\Property(property: 'platform', description: 'Actual platform (null if no realtime data)', type: 'string', example: '3a', nullable: true),
@@ -69,17 +46,6 @@ public function toArray($request): array
{
return [
'tripId' => $this->resource->trip->tripId,
- 'stop' => [ // @deprecated - remove after 2026-09-30, use station instead
- 'type' => 'stop',
- 'id' => $this->resource->station->id,
- 'name' => $this->resource->station->name,
- 'location' => [
- 'type' => 'location',
- 'id' => $this->resource->station->getIdentifier(StationIdentifierType::DE_DB_IBNR)?->identifier,
- 'latitude' => $this->resource->station->latitude,
- 'longitude' => $this->resource->station->longitude,
- ],
- ],
'when' => $this->resource->realDeparture?->toIso8601String(),
'plannedWhen' => $this->resource->plannedDeparture->toIso8601String(),
'platform' => $this->resource->realPlatform,
diff --git a/resources/tailwind-app/components/Stationboard/DepartureEntry.vue b/resources/tailwind-app/components/Stationboard/DepartureEntry.vue
index effc16d5b8..8beb29523e 100644
--- a/resources/tailwind-app/components/Stationboard/DepartureEntry.vue
+++ b/resources/tailwind-app/components/Stationboard/DepartureEntry.vue
@@ -76,10 +76,10 @@ const platform = computed((): string | null => props.item.platform ?? props.item
{{ item.direction }}
- {{ trans('stationboard.dep') }} {{ item.stop.name }}
+ {{ trans('stationboard.dep') }} {{ item.station.name }}
diff --git a/resources/tailwind-app/pages/Stationboard/Stationboard.vue b/resources/tailwind-app/pages/Stationboard/Stationboard.vue
index 79815ed18d..54515cf434 100644
--- a/resources/tailwind-app/pages/Stationboard/Stationboard.vue
+++ b/resources/tailwind-app/pages/Stationboard/Stationboard.vue
@@ -100,20 +100,20 @@ function fetchNext(): void {
fetchDepartures(next ?? fetchTime.value.plus({ minutes: 15 }).toISO() ?? undefined);
}
-function openLineRun(train: DepartureResource): void {
+function openLineRun(departure: DepartureResource): void {
router.push({
name: 'line-run',
query: {
- tripId: train.tripId,
- lineName: train.line?.name ?? train.line?.fahrtNr,
- startId: train.stop?.id,
- plannedWhen: train.plannedWhen,
- direction: train.direction,
- originName: train.stop?.name,
- product: train.line?.product ?? undefined,
- mode: train.line?.mode ?? undefined,
- color: train.line?.color ?? undefined,
- textColor: train.line?.textColor ?? undefined,
+ tripId: departure.tripId,
+ lineName: departure.line?.name ?? departure.line?.fahrtNr,
+ startId: departure.station?.id,
+ plannedWhen: departure.plannedWhen,
+ direction: departure.direction,
+ originName: departure.station?.name,
+ product: departure.line?.product ?? undefined,
+ mode: departure.line?.mode ?? undefined,
+ color: departure.line?.color ?? undefined,
+ textColor: departure.line?.textColor ?? undefined,
},
});
}
diff --git a/resources/types/Api.gen.ts b/resources/types/Api.gen.ts
index 1df57addd5..d88b68a6df 100644
--- a/resources/types/Api.gen.ts
+++ b/resources/types/Api.gen.ts
@@ -1302,54 +1302,6 @@ export interface DepartureResource {
* @example "1|200513|0|81|6012023"
*/
tripId: string;
- /**
- * The stop at which this departure occurs
- * @deprecated
- */
- stop: {
- /**
- * @deprecated
- * @example "stop"
- */
- type?: string;
- /**
- * Träwelling internal station ID
- * @deprecated
- * @example 5181
- */
- id?: number;
- /**
- * @deprecated
- * @example "Karlsruhe Hbf"
- */
- name?: string;
- /** @deprecated */
- location?: {
- /**
- * @deprecated
- * @example "location"
- */
- type?: string;
- /**
- * IBNR identifier (if available)
- * @deprecated
- * @example "8000191"
- */
- id?: string | null;
- /**
- * @deprecated
- * @format float
- * @example 48.993207
- */
- latitude?: number;
- /**
- * @deprecated
- * @format float
- * @example 8.400977
- */
- longitude?: number;
- };
- };
/**
* Actual departure time (null if no realtime data)
* @format date-time
diff --git a/resources/types/Departure.ts b/resources/types/Departure.ts
index 2bb375a070..73a55ee0cd 100644
--- a/resources/types/Departure.ts
+++ b/resources/types/Departure.ts
@@ -1,6 +1,5 @@
export type departureEntry = {
tripId: string;
- stop: HafasStop;
when: string | null;
plannedWhen: string | null;
platform: string | null;
@@ -31,27 +30,3 @@ export type HafasLine = {
mode: any; // eslint-disable-line @typescript-eslint/no-explicit-any
product: any; // eslint-disable-line @typescript-eslint/no-explicit-any
};
-
-export type HafasStop = {
- type: string;
- id: string;
- name: string;
- location: HafasLocation;
- station: HafasStation;
-};
-export type HafasStation = {
- type: string;
- id: string;
- name: string;
- location: HafasLocation;
- products: {
- [key: string]: boolean;
- };
-};
-
-export type HafasLocation = {
- type: string;
- id: string;
- latitude: number;
- longitude: number;
-};
diff --git a/resources/vue/components/Checkin/CheckinInterface.vue b/resources/vue/components/Checkin/CheckinInterface.vue
index 97a9bf1594..411a3e8b52 100644
--- a/resources/vue/components/Checkin/CheckinInterface.vue
+++ b/resources/vue/components/Checkin/CheckinInterface.vue
@@ -20,7 +20,7 @@ export default {
type: Object,
required: true,
},
- selectedTrain: {
+ selectedDeparture: {
type: Object,
required: true,
},
@@ -93,11 +93,11 @@ export default {
visibility: this.visibility,
business: this.business,
ibnr: false,
- tripId: this.selectedTrain.tripId,
- lineName: this.selectedTrain.line.name ?? this.selectedTrain.line.fahrtNr,
- start: this.selectedTrain.stop.id,
+ tripId: this.selectedDeparture.tripId,
+ lineName: this.selectedDeparture.line.name ?? this.selectedDeparture.line.fahrtNr,
+ start: this.selectedDeparture.station.id,
destination: this.selectedDestination.id,
- departure: DateTime.fromISO(this.selectedTrain.plannedWhen).setZone('UTC').toISO(),
+ departure: DateTime.fromISO(this.selectedDeparture.plannedWhen).setZone('UTC').toISO(),
arrival: DateTime.fromISO(this.selectedDestination.arrivalPlanned).setZone('UTC').toISO(),
force: this.collision,
eventId: this.selectedEvent ? this.selectedEvent.id : null,
diff --git a/resources/vue/components/Checkin/StationBoardEntry.vue b/resources/vue/components/Checkin/StationBoardEntry.vue
index d16c0f5aae..6109b7b512 100644
--- a/resources/vue/components/Checkin/StationBoardEntry.vue
+++ b/resources/vue/components/Checkin/StationBoardEntry.vue
@@ -93,8 +93,8 @@ function normalizeLineName(name: string | null): string {
{{ item.direction }}
-
- {{ trans('stationboard.dep') }} {{ item.stop.name }}
+
+ {{ trans('stationboard.dep') }} {{ item.station.name }}
diff --git a/resources/vue/components/CheckinLineRun.vue b/resources/vue/components/CheckinLineRun.vue
index 4e451b978a..55c4e64c95 100644
--- a/resources/vue/components/CheckinLineRun.vue
+++ b/resources/vue/components/CheckinLineRun.vue
@@ -7,7 +7,7 @@ export default {
name: 'CheckinLineRun',
components: { LoadingSkeletonRows },
props: {
- selectedTrain: {
+ selectedDeparture: {
type: Object,
required: true,
},
@@ -32,7 +32,7 @@ export default {
};
},
watch: {
- selectedTrain() {
+ selectedDeparture() {
this.getLineRun();
},
},
@@ -48,9 +48,9 @@ export default {
this.loading = true;
const params = new URLSearchParams({
- hafasTripId: this.$props.selectedTrain.tripId,
- lineName: this.$props.selectedTrain.line.name,
- start: this.$props.selectedTrain.stop.id,
+ hafasTripId: this.$props.selectedDeparture.tripId,
+ lineName: this.$props.selectedDeparture.line.name,
+ start: this.$props.selectedDeparture.station.id,
});
fetch(`/api/v1/trains/trip?${params.toString()}`)
.then((response) => {
@@ -61,9 +61,9 @@ export default {
}
response.json().then((result) => {
this.lineRun = result.data;
- const givenDeparture = DateTime.fromISO(this.$props.selectedTrain.plannedWhen);
+ const givenDeparture = DateTime.fromISO(this.$props.selectedDeparture.plannedWhen);
const startIndex = this.lineRun.stopovers.findIndex((item) => {
- if (Number(item.id) !== Number(this.$props.selectedTrain.stop.id)) {
+ if (Number(item.id) !== Number(this.$props.selectedDeparture.station.id)) {
return false;
}
const dep = item.departurePlanned
diff --git a/resources/vue/components/Stationboard.vue b/resources/vue/components/Stationboard.vue
index a1543b29bb..4bc89a5d6b 100644
--- a/resources/vue/components/Stationboard.vue
+++ b/resources/vue/components/Stationboard.vue
@@ -28,9 +28,9 @@ export default {
travelType: null,
fetchTime: null,
show: false,
- selectedTrain: null,
- selectedTrainBackgroundColor: null,
- selectedTrainTextColor: null,
+ selectedDeparture: null,
+ selectedDepartureBackgroundColor: null,
+ selectedDepartureTextColor: null,
selectedDestination: null,
loading: false,
stationName: null,
@@ -49,7 +49,7 @@ export default {
: DateTime.now().setZone('UTC');
},
showLineRun() {
- return !!this.selectedTrain && !this.selectedDestination;
+ return !!this.selectedDeparture && !this.selectedDestination;
},
showCheckinInterface() {
return !!this.selectedDestination;
@@ -81,19 +81,19 @@ export default {
this.pushHistory(params);
}
},
- selectedTrain(value) {
+ selectedDeparture(value) {
if (value !== null) {
- this.selectedTrainBackgroundColor = this.selectedTrain?.line?.color || null;
+ this.selectedDepartureBackgroundColor = this.selectedDeparture?.line?.color || null;
- if (this.selectedTrainBackgroundColor) {
- this.selectedTrainTextColor = this.selectedTrain?.line?.textColor || null;
+ if (this.selectedDepartureBackgroundColor) {
+ this.selectedDepartureTextColor = this.selectedDeparture?.line?.textColor || null;
}
}
},
},
mounted() {
this.analyzeUrlParams().then(() => {
- if (!this.selectedTrain) {
+ if (!this.selectedDeparture) {
this.fetchData();
}
});
@@ -108,14 +108,14 @@ export default {
trans,
showModal(selectedItem) {
this.selectedDestination = null;
- this.selectedTrain = selectedItem;
+ this.selectedDeparture = selectedItem;
this.show = true;
this.$refs.modal.show();
const data = new URLSearchParams({
tripId: selectedItem.tripId,
lineName: selectedItem.line.name,
- start: this.selectedTrain.stop.id,
+ start: this.selectedDeparture.station.id,
departure: selectedItem.when,
category: selectedItem.line.product,
});
@@ -216,13 +216,13 @@ export default {
if (!urlParams.has('destination')) {
this.selectedDestination = null;
}
- this.selectedTrain = {
+ this.selectedDeparture = {
tripId: urlParams.get('tripId'),
line: {
name: urlParams.get('lineName'),
product: urlParams.get('category') || null,
},
- stop: {
+ station: {
id: urlParams.get('start'),
},
plannedWhen: urlParams.get('departure'),
@@ -252,7 +252,7 @@ export default {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.toString() !== this.pushState.toString()) {
this.analyzeUrlParams().then(() => {
- if (!this.selectedTrain) {
+ if (!this.selectedDeparture) {
this.fetchData();
}
});
@@ -275,7 +275,7 @@ export default {
// triggering the selectedDestination watcher's history.back()
this.suppressDestinationWatcher = true;
this.selectedDestination = null;
- this.selectedTrain = null;
+ this.selectedDeparture = null;
this.fastCheckinIbnr = null;
this.show = false;
this.suppressDestinationWatcher = false;
@@ -362,16 +362,20 @@ export default {
-
+
@@ -387,12 +391,12 @@ export default {
diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json
index bab41a4115..cc0417ee93 100644
--- a/storage/api-docs/api-docs.json
+++ b/storage/api-docs/api-docs.json
@@ -13708,7 +13708,6 @@
"description": "A single departure at a station",
"required": [
"tripId",
- "stop",
"when",
"plannedWhen",
"platform",
@@ -13724,59 +13723,6 @@
"type": "string",
"example": "1|200513|0|81|6012023"
},
- "stop": {
- "description": "The stop at which this departure occurs",
- "properties": {
- "type": {
- "type": "string",
- "example": "stop",
- "deprecated": true
- },
- "id": {
- "description": "Träwelling internal station ID",
- "type": "integer",
- "example": 5181,
- "deprecated": true
- },
- "name": {
- "type": "string",
- "example": "Karlsruhe Hbf",
- "deprecated": true
- },
- "location": {
- "properties": {
- "type": {
- "type": "string",
- "example": "location",
- "deprecated": true
- },
- "id": {
- "description": "IBNR identifier (if available)",
- "type": "string",
- "example": "8000191",
- "nullable": true,
- "deprecated": true
- },
- "latitude": {
- "type": "number",
- "format": "float",
- "example": 48.993207,
- "deprecated": true
- },
- "longitude": {
- "type": "number",
- "format": "float",
- "example": 8.400977,
- "deprecated": true
- }
- },
- "type": "object",
- "deprecated": true
- }
- },
- "type": "object",
- "deprecated": true
- },
"when": {
"description": "Actual departure time (null if no realtime data)",
"type": "string",