feat(fahrzeug): Funkkenner-Feld ergänzt (BOS-Digitalfunk-Kennung)
Nutzer-Fund: funkkenner (z.B. OPTA-Nummer) fehlte in fahrzeugdetails komplett - eigenes Feld, nicht dasselbe wie funkrufname (gesprochener Rufname vs. formale Funk-Identifikationsnummer im Digitalfunknetz). Migration 0018, Model/Schema/Frontend-Formular ergänzt. Auch im Kachel- Backlog (arbeitskacheln/05_fleet.md, FLEET-002) nachgezogen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
This commit is contained in:
@@ -4221,3 +4221,140 @@ Keine Commits in dieser Session.
|
||||
- frontend/src/styles/global.css | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:07 – 15:11 (3m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 95e04b5 style: Sidebar-Layout statt Topbar (Vorbild OpenFleet-Dashboard-Screenshot)
|
||||
- 024576c style: schlicheres Design (flach statt Schatten, kleinerer Radius)
|
||||
|
||||
### Geänderte Dateien
|
||||
- frontend/src/styles/global.css | 55 +++++++++++++++++++++++++++++++++++++++++--------------
|
||||
|
||||
---
|
||||
## 2026-09-05 15:13 – 15:16 (3m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 5524ef9 docs: Arbeitskacheln-Backlog als Dateien angelegt (arbeitskacheln/)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/01_foundation.md | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/02_identity.md | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/03_digital_file.md | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:16 – 15:18 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 862236f docs: nächste 10 Arbeitskacheln (FILE-006/007, ASSET-001..008)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 6 ++-
|
||||
- arbeitskacheln/03_digital_file.md | 46 +++++++++++++++++++++-
|
||||
- arbeitskacheln/04_assets.md | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:19 – 15:20 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- c7784f0 docs: nächste 10 Arbeitskacheln (FLEET-001..006, INV-001..004)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 4 ++-
|
||||
- arbeitskacheln/05_fleet.md | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/06_inventory.md | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:22 – 15:23 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- b7c7276 docs: Fehler korrigiert - Betriebsstunden fälschlich fahrzeug-only geplant
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 7 ++++---
|
||||
- arbeitskacheln/04_assets.md | 39 ++++++++++++++++++++++++++++++++++++++-
|
||||
- arbeitskacheln/05_fleet.md | 54 ++++++++++++++++++++++++++++++------------------------
|
||||
|
||||
---
|
||||
## 2026-09-05 15:23 – 15:25 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 8fc5453 docs: Inventory-Epic komplettiert (INV-005..007)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 6 +++---
|
||||
- arbeitskacheln/06_inventory.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
|
||||
|
||||
---
|
||||
## 2026-09-05 15:25 – 15:26 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 6aa45a3 docs: Warehouse-Epic komplettiert (WH-001..007)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 3 +-
|
||||
- arbeitskacheln/07_warehouse.md | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:28 – 15:29 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- f7070c5 docs: Loadout-Epic komplettiert (LOAD-001..006)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 3 +-
|
||||
- arbeitskacheln/08_loadout.md | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:30 – 15:31 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 81a7271 docs: Inspections-Epic komplettiert (INSP-001..006)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 3 +-
|
||||
- arbeitskacheln/09_inspections.md | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:31 – 15:32 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 71dc679 docs: Maintenance-Epic komplettiert (MAINT-001..006)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 5 ++--
|
||||
- arbeitskacheln/10_maintenance.md | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-05 15:32 – 15:33 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- 11a62db docs: Defects-Epic komplettiert (DEFECT-001..005)
|
||||
|
||||
### Geänderte Dateien
|
||||
- arbeitskacheln/00_index.md | 3 ++-
|
||||
- arbeitskacheln/11_defects.md | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
---
|
||||
|
||||
@@ -23,16 +23,19 @@ Details zu FLEET-001 … FLEET-006 (vollständig).
|
||||
- **Tests:** CRUD-Test.
|
||||
- **DoD:** mind. ein Fahrzeugtyp angelegt.
|
||||
|
||||
## FLEET-002 — Fahrzeuge (Kennzeichen/Funkrufname)
|
||||
## FLEET-002 — Fahrzeuge (Kennzeichen/Funkrufname/Funkkenner)
|
||||
|
||||
- **Nachtrag (Nutzer-Fund):** Funkkenner (BOS-Digitalfunk-Kennung, z.B. OPTA-Nummer) fehlte
|
||||
— ist ein eigenes Feld, nicht dasselbe wie Funkrufname (gesprochener Rufname wie
|
||||
„Florian München 1/44" vs. formale Funk-Identifikationsnummer im Digitalfunknetz).
|
||||
- **Ziel:** Fahrzeug-Spezialfelder am Asset.
|
||||
- **Beschreibung:** Kennzeichen, Fahrgestellnummer, Funkrufname als 1:1-Erweiterungstabelle
|
||||
zu Asset.
|
||||
- **Beschreibung:** Kennzeichen, Fahrgestellnummer, Funkrufname, Funkkenner als
|
||||
1:1-Erweiterungstabelle zu Asset.
|
||||
- **Benutzerwert:** Fahrzeuge sind die wichtigste Ressourcenklasse im Rettungsdienst — eigene
|
||||
Kennfelder sind Pflicht.
|
||||
- **Abhängigkeiten:** ASSET-003, FLEET-001
|
||||
- **Datenmodell:** `fahrzeugdetails` (asset_id, kennzeichen, fahrgestellnummer,
|
||||
funkrufname)
|
||||
funkrufname, funkkenner)
|
||||
- **Backend:** CRUD/Upsert
|
||||
- **Frontend:** Formular
|
||||
- **Mobile:** Anzeige
|
||||
@@ -139,4 +142,6 @@ Betriebsstunden-Feld) — und selbst der Fahrzeug-Kilometerstand hat **keine
|
||||
Rückwärtslauf-Validierung** (reiner Zahlen-Input). Beides zusammen: ASSET-009 wäre in MABEA
|
||||
kein reiner Nachzug, sondern verlangt (a) ein neues generisches Zählerfeld an Objekt/
|
||||
GeraetInstanz und (b) eine bisher fehlende Validierungsregel. FLEET-006 ist in MABEA (noch)
|
||||
nicht relevant, da kein Operations-Epic existiert.
|
||||
nicht relevant, da kein Operations-Epic existiert. **FLEET-002-Nachtrag:** `funkkenner`
|
||||
fehlte in MABEAs `fahrzeugdetails` komplett (nur `funkrufname` vorhanden) — echte, kleine
|
||||
Feld-Lücke, wird direkt nachgezogen (siehe Commit).
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
"""fahrzeugdetails.funkkenner (Nutzer-Fund): BOS-Digitalfunk-Kennung (z.B.
|
||||
OPTA-Nummer) ist ein eigenes Feld, nicht dasselbe wie funkrufname (gesprochener
|
||||
Rufname wie "Florian München 1/44" vs. formale Funk-Identifikationsnummer im
|
||||
Digitalfunknetz). Additiv, nullable.
|
||||
|
||||
Revision ID: 0018_funkkenner
|
||||
Revises: 0017_granulare_rollen
|
||||
Create Date: 2026-09-05
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision: str = "0018_funkkenner"
|
||||
down_revision: Union[str, None] = "0017_granulare_rollen"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute("ALTER TABLE fahrzeugdetails ADD COLUMN funkkenner TEXT")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute("ALTER TABLE fahrzeugdetails DROP COLUMN funkkenner")
|
||||
@@ -17,6 +17,9 @@ class Fahrzeugdetails(Base):
|
||||
objekt_id: Mapped[int] = mapped_column(ForeignKey("objekt.id"), primary_key=True)
|
||||
kennzeichen: Mapped[str | None] = mapped_column(String)
|
||||
funkrufname: Mapped[str | None] = mapped_column(String)
|
||||
# BOS-Digitalfunk-Kennung (z.B. OPTA-Nummer) - eigenes Feld, nicht dasselbe wie
|
||||
# funkrufname (gesprochener Rufname vs. formale Funk-Identifikationsnummer).
|
||||
funkkenner: Mapped[str | None] = mapped_column(String)
|
||||
baujahr: Mapped[int | None] = mapped_column(Integer)
|
||||
kilometerstand: Mapped[int | None] = mapped_column(Integer)
|
||||
betriebsstunden: Mapped[Decimal | None] = mapped_column(Numeric)
|
||||
|
||||
@@ -38,6 +38,7 @@ class ObjektUpdate(BaseModel):
|
||||
class FahrzeugdetailsUpsert(BaseModel):
|
||||
kennzeichen: str | None = None
|
||||
funkrufname: str | None = None
|
||||
funkkenner: str | None = None
|
||||
baujahr: int | None = None
|
||||
kilometerstand: int | None = None
|
||||
betriebsstunden: Decimal | None = None
|
||||
@@ -50,6 +51,7 @@ class FahrzeugdetailsRead(BaseModel):
|
||||
objekt_id: int
|
||||
kennzeichen: str | None
|
||||
funkrufname: str | None
|
||||
funkkenner: str | None
|
||||
baujahr: int | None
|
||||
kilometerstand: int | None
|
||||
betriebsstunden: Decimal | None
|
||||
|
||||
@@ -15,12 +15,18 @@ async def test_fahrzeugdetails_upsert(client, objekt_mit_position, admin_user):
|
||||
|
||||
gesetzt = await client.put(
|
||||
f"/api/v1/objekte/{objekt.id}/fahrzeugdetails",
|
||||
json={"kennzeichen": "XX-YY 123", "kilometerstand": 42315, "naechste_hu": "2027-05-01"},
|
||||
json={
|
||||
"kennzeichen": "XX-YY 123",
|
||||
"kilometerstand": 42315,
|
||||
"naechste_hu": "2027-05-01",
|
||||
"funkkenner": "OPTA-12345",
|
||||
},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert gesetzt.status_code == 200
|
||||
assert gesetzt.json()["kennzeichen"] == "XX-YY 123"
|
||||
assert gesetzt.json()["kilometerstand"] == 42315
|
||||
assert gesetzt.json()["funkkenner"] == "OPTA-12345"
|
||||
|
||||
aktualisiert = await client.put(
|
||||
f"/api/v1/objekte/{objekt.id}/fahrzeugdetails",
|
||||
|
||||
@@ -2,6 +2,7 @@ export interface Fahrzeugdetails {
|
||||
objekt_id: number;
|
||||
kennzeichen: string | null;
|
||||
funkrufname: string | null;
|
||||
funkkenner: string | null;
|
||||
baujahr: number | null;
|
||||
kilometerstand: number | null;
|
||||
betriebsstunden: string | null;
|
||||
|
||||
@@ -117,6 +117,7 @@ export function ObjektSection({
|
||||
body: {
|
||||
kennzeichen: details.kennzeichen || null,
|
||||
funkrufname: details.funkrufname || null,
|
||||
funkkenner: details.funkkenner || null,
|
||||
baujahr: details.baujahr || null,
|
||||
kilometerstand: details.kilometerstand || null,
|
||||
betriebsstunden: details.betriebsstunden || null,
|
||||
@@ -431,6 +432,12 @@ export function ObjektSection({
|
||||
value={details.funkrufname ?? ""}
|
||||
onChange={(e) => setDetails((d) => ({ ...d, funkrufname: e.target.value }))}
|
||||
/>
|
||||
<input
|
||||
className="input"
|
||||
placeholder="Funkkenner (BOS-Digitalfunk)"
|
||||
value={details.funkkenner ?? ""}
|
||||
onChange={(e) => setDetails((d) => ({ ...d, funkkenner: e.target.value }))}
|
||||
/>
|
||||
<div className="row">
|
||||
<input
|
||||
className="input"
|
||||
|
||||
Reference in New Issue
Block a user