diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..cff6c9d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,52 @@ +# AGENTS.md + +## Ziel der Datei +Dieses Dokument beschreibt, welche Informationen ich als Agent für `p:\netwatch` erwarten würde: Projektziel, Setup, Regeln, Skills, bekannte Issues, Kontext & Einschränkungen. + +## Projektüberblick +- Name: **netwatch** – ein Netzwerk-Dokumentations- und Verkabelungsverwaltungs-Tool (Alpha v0.2, Core-Module funktionsfähig, Stand: 13. Februar 2026). +- Features: Dashboard, Gerätetypen-/Geräteverwaltung, Racks/Floors mit SVG-Planung, Verbindungen inkl. VLANs, Module, grafische Ansichten (Rack, Netzwerkgraph, Stockwerke/Räume). +- Datenmodell: zentrales SQL-Schema (`locations`, `device_types`, `devices`, `connections` etc.) mit JSON-Erweiterungsmöglichkeiten. +- Projektphasen (Phase 1–4) sind im README gelistet, siehe letzte Abschnitte. + +## Schneller Projektstart +```powershell +docker-compose up -d --build +# danach: http://localhost +``` +Das Docker-Setup (Compose + Portainer) liegt in `docker-compose.yml` und `docker-portainer.yml`, ergänzende Infos in `Dockerfile`. + +## Skills & Nutzungshinweise +- **skill-creator** – Anleitung zum Erstellen bzw. Erweitern eigener Skills. Pfad: `C:/Users/s.titz/.codex/skills/.system/skill-creator/SKILL.md`. +- **skill-installer** – Anleitung zum Installieren zusätzlicher Skills aus Kurationslisten oder GitHub. Pfad: `C:/Users/s.titz/.codex/skills/.system/skill-installer/SKILL.md`. + +Wenn ein Skill genannt wird (z. B. `$skill-creator`) oder die Aufgabe exakt zur Beschreibung passt, muss dieser Skill in dem Turn verwendet werden. Skills immer erst öffnen (`SKILL.md`), nur nötige Teile lesen, relative Pfade innerhalb des Skill-Verzeichnisses auflösen. Bei mehreren Skills: minimaler Satz in sinnvoller Reihenfolge, kurz ankündigen, warum welche Skills genutzt wurden. + +## Lokale Arbeitsregeln +- Arbeitsumgebung: Windows, Pfad `P:\netwatch`, Shell `powershell`. Schreibzugriff für mich hier ist verboten; Änderungen müssen vom Nutzer übernommen werden. +- Suche: Nutze `rg`/`rg --files` statt `grep`/`find` für Geschwindigkeit. +- Codeänderungen: Nur ASCII-Zeichen einführen (außer bestehende Dateien nutzen Unicode); Formate ohne `apply_patch` nur wenn nötig; preferiere `apply_patch`. +- Keine destruktiven Git-Befehle ohne ausdrückliche Aufforderung (z. B. keinen `reset --hard`). +- Tests/Builds: Wenn nötig, nenne passende Tests / Prüfmethoden als nächsten Schritt. +- Kommunikation: Verwende beim Antworten absolute Datumsangaben (z. B. „13. Februar 2026“) wenn sich jemand auf „heute/morgen“ bezieht, um Missverständnisse zu vermeiden. + +## Bekannte Bugs (aus `BUGS.md`) +- Gerät löschen funktioniert nicht (Status unklar). +- Gerätetypen SVG-Modul: Malfunktion. +- Ports Drag & Drop (Funktion unklar). +- Beim Erstellen von Gerätetypen soll ein voreingestelltes Rechteck basierend auf 19-Zoll & HE-Größe erzeugt werden, das als Grundgerüst dient. +- Device-Typ-Erstellung: Klick auf Objekt-Typ-Button, dann Drag-Drop für Diagonale und Loslassen fixiert Position. + +## Weitere Ressourcen +- `NEXT_STEPS.md` (aktuelles ToDo / Roadmap). +- `IMPLEMENTATION_STATUS.md` (Status-Tracking). +- `README.md` (Feature- und Architekturübersicht). + +## Besonderheiten / Kommunikation +- Aktuelles Datum: Freitag, 13. Februar 2026 (nicht überschreiben). +- Keine Netzwerkanfragen möglich; Referenzen nur lokal nutzen. +- Wenn ein Agent spezielle Instruktionen benötigt (z. B. Skill-Anwendung), immer darauf hinweisen und ggf. den Nutzer nach Bestätigung fragen. + +## Einschränkungen +- Sandbox ist lesend; bitte selbst `AGENTS.md` anlegen. +- Jegliche Ausgaben/Antworten sollten den Developer-Guidelines folgen (kurz, teamorientiert, klare nächste Schritte). diff --git a/README.md b/README.md index 1b42ea5..085703c 100644 --- a/README.md +++ b/README.md @@ -232,8 +232,26 @@ Verbindungen werden: - Netzwerkdosen: - anklickbar - Ports sichtbar +- Patchpanels: + - Fest installierte Patchfelder, die im Raum- bzw. Stockwerksplan als eigene Objekte auftauchen. + - Sie stammen nicht aus dem `devices`-Modul, sondern zeigen die permanente Verdrahtung zwischen Patchpanels und Anschlussdosen. + - Die untereinander verbundenen Patchpanels lassen sich direkt auf der SVG-Stockwerkskarte verorten, damit jeder Port physisch nachvollziehbar bleibt. - Verbindungen zu Racks / Switches darstellbar +### TODO: Patchpanel-Infrastruktur +- [ ] Floorplans erweitern, damit Patchpanels als feste Infrastrukturobjekte (nicht als rack-basierte `devices`) angelegt, verschoben und mit `x/y`/Größe verankert werden. +- [ ] Backend und SVG-Editor dahingehend adaptieren, dass Patchpanel-Ports unabhängig von Racks definiert werden können. +- [ ] Patchpanel ↔ Patchpanel- und Patchpanel ↔ Netzwerkbuchse-Verbindungen als permanente Kabel zwischen Floorplan-Objekten darstellen und über die `connections`-Tabelle verwalten. +- [ ] UI/Schema-Dokumentation aktualisieren (README + Datenbank-Docs) sowie neue SQL-Tabellen (`floor_patchpanels` / `floor_patchpanel_ports`) fertigstellen. +- [ ] Floorplan-Filter/Legend leiten die Nutzung dieser Infrastrukturobjekte, Kampagnen und Search & Filter integrieren. + +### Stockwerksinfrastruktur-Modul +- Das neue Modul „Stockwerksinfrastruktur“ sammelt Patchpanels und Wandbuchsen an einem Ort. +- Patchfelder bekommen feste X/Y-Positionen, Maße, Portanzahl und verknüpfen zu Floorplans. +- Wandbuchsen sind direkt mit Räumen verbunden, können aber auch später im SVG verteilt werden. +- Ziel: Die Floorplan-Grafik zeigt die permanente Infrastruktur samt fest verlegter Kabelverläufe. +- TODO: SVG-Editor um Drag & Drop für diese Objekte erweitern und Klicks direkt mit dem Modul verbinden. + --- ## Datenbank (konzeptionell) diff --git a/app/index.php b/app/index.php index c1f8614..b2c3b23 100644 --- a/app/index.php +++ b/app/index.php @@ -27,7 +27,7 @@ $module = $_GET['module'] ?? 'dashboard'; $action = $_GET['action'] ?? 'list'; // Whitelist der Module -$validModules = ['dashboard', 'locations', 'buildings', 'device_types', 'devices', 'racks', 'floors', 'connections', 'port_types']; +$validModules = ['dashboard', 'locations', 'buildings', 'device_types', 'devices', 'racks', 'floors', 'floor_infrastructure', 'connections', 'port_types']; // Whitelist der Aktionen $validActions = ['list', 'edit', 'save', 'ports', 'delete']; diff --git a/app/modules/floor_infrastructure/edit.php b/app/modules/floor_infrastructure/edit.php new file mode 100644 index 0000000..81d9389 --- /dev/null +++ b/app/modules/floor_infrastructure/edit.php @@ -0,0 +1,177 @@ +get("SELECT id, name FROM floors ORDER BY name", "", []); +$rooms = $sql->get( + "SELECT r.id, r.name, f.name AS floor_name + FROM rooms r + LEFT JOIN floors f ON f.id = r.floor_id + ORDER BY f.name, r.name", + "", + [] +); + +$panel = null; +$outlet = null; +$pageTitle = $type === 'outlet' ? 'Wandbuchse bearbeiten' : 'Patchpanel bearbeiten'; + +if ($type === 'patchpanel' && $id > 0) { + $panel = $sql->single( + "SELECT * FROM floor_patchpanels WHERE id = ?", + "i", + [$id] + ); + if ($panel) { + $pageTitle = "Patchpanel bearbeiten: " . htmlspecialchars($panel['name']); + } +} + +if ($type === 'outlet' && $id > 0) { + $outlet = $sql->single( + "SELECT * FROM network_outlets WHERE id = ?", + "i", + [$id] + ); + if ($outlet) { + $pageTitle = "Wandbuchse bearbeiten: " . htmlspecialchars($outlet['name']); + } +} +?> + +
+

+ +
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +

TODO: Drag & Drop auf dem SVG-Plan erlauben.

+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +

TODO: Wandbuchsen gezielt auf dem Stockwerksplan platzieren.

+ + +
+ + Abbrechen +
+
+
+ + diff --git a/app/modules/floor_infrastructure/list.php b/app/modules/floor_infrastructure/list.php new file mode 100644 index 0000000..ad9db53 --- /dev/null +++ b/app/modules/floor_infrastructure/list.php @@ -0,0 +1,196 @@ +get("SELECT id, name FROM floors ORDER BY name", "", []); + +$where = ''; +$types = ''; +$params = []; + +if ($floorId > 0) { + $where = "WHERE p.floor_id = ?"; + $types = "i"; + $params[] = $floorId; +} + +$patchPanels = $sql->get( + "SELECT p.*, f.name AS floor_name + FROM floor_patchpanels p + LEFT JOIN floors f ON f.id = p.floor_id + $where + ORDER BY f.name, p.name", + $types, + $params +); + +$networkOutlets = $sql->get( + "SELECT o.*, r.name AS room_name, f.name AS floor_name + FROM network_outlets o + LEFT JOIN rooms r ON r.id = o.room_id + LEFT JOIN floors f ON f.id = r.floor_id + ORDER BY f.name, r.name, o.name", + "", + [] +); +?> + +
+

Stockwerksinfrastruktur

+ +
+ + + Patchpanel hinzufügen + + + + Wandbuchse hinzufügen + +
+ +
+ + + + + + + Zurücksetzen +
+ +
+

Patchpanels

+ + + + + + + + + + + + + + + + + + + + + + + + +
NameStockwerkPositionGrößePortsAktionen
+ Bearbeiten +
+ +

Noch keine Patchpanels definiert.

+ +
+ +
+

Wandbuchsen

+ + + + + + + + + + + + + + + + + + + + + + + + +
NameStockwerkRaumKoordinatenKommentarAktionen
+ Bearbeiten +
+ +

Noch keine Wandbuchsen angelegt.

+ +
+ +
+

Stockwerksplan-Verortung

+

Die eingetragenen Patchpanels und Wandbuchsen erscheinen später als feste Objekte auf dem Stockwerks-SVG. Die Polygon-Positionen werden momentan noch durch numerische X/Y-Werte gesteuert.

+

TODO: SVG-Editor mit Drag & Drop für diese Objekte erweitern (siehe Stockwerke-Modul).

+
+
+ + diff --git a/app/modules/floor_infrastructure/save.php b/app/modules/floor_infrastructure/save.php new file mode 100644 index 0000000..5a61f27 --- /dev/null +++ b/app/modules/floor_infrastructure/save.php @@ -0,0 +1,57 @@ + 0) { + $sql->set( + "UPDATE floor_patchpanels SET name = ?, floor_id = ?, pos_x = ?, pos_y = ?, width = ?, height = ?, port_count = ?, comment = ? WHERE id = ?", + "siiiiisii", + [$name, $floorId, $posX, $posY, $width, $height, $portCount, $comment, $id] + ); + } else { + $sql->set( + "INSERT INTO floor_patchpanels (name, floor_id, pos_x, pos_y, width, height, port_count, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + "siiiiiss", + [$name, $floorId, $posX, $posY, $width, $height, $portCount, $comment] + ); + } +} elseif ($type === 'outlet') { + $name = trim($_POST['name'] ?? ''); + $roomId = (int)($_POST['room_id'] ?? 0); + $x = (int)($_POST['x'] ?? 0); + $y = (int)($_POST['y'] ?? 0); + $comment = trim($_POST['comment'] ?? ''); + + if ($id > 0) { + $sql->set( + "UPDATE network_outlets SET name = ?, room_id = ?, x = ?, y = ?, comment = ? WHERE id = ?", + "siiisi", + [$name, $roomId, $x, $y, $comment, $id] + ); + } else { + $sql->set( + "INSERT INTO network_outlets (name, room_id, x, y, comment) VALUES (?, ?, ?, ?, ?)", + "siiis", + [$name, $roomId, $x, $y, $comment] + ); + } +} + +header('Location: ?module=floor_infrastructure&action=list'); +exit; diff --git a/app/templates/header.php b/app/templates/header.php index 51abd6f..f527764 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -40,6 +40,7 @@ 'port_types' => 'Porttypen', 'devices' => 'Geräte', 'racks' => 'Racks', + 'floor_infrastructure' => 'Infrastruktur', 'connections' => 'Verbindungen', ]; ?> diff --git a/doc/DATABASE.md b/doc/DATABASE.md index de0e4f7..1df743d 100644 --- a/doc/DATABASE.md +++ b/doc/DATABASE.md @@ -95,6 +95,41 @@ Einzelne Ports einer Netzwerkdose. --- +### Patchpanel-Objekte im Floorplan +Patchpanels haben eine Sonderstellung: Sie sind fest verkabelte Bündel von Ports und werden **nicht** wie normale `devices` im Rack verschoben, sondern als eigene Floorplan-Objekte fest auf einem Stockwerk positioniert. + +**Verwendung** +- Repräsentieren physische Patchfelder auf dem Stockwerksplan. +- Werden im SVG mit festen `x`/`y`-Koordinaten verankert und symbolisieren deren reale Position. +- Ermöglichen die Dokumentation der dauerhaften Verbindungen zu anderen Patchpanels, Netzwerkdosen oder Geräteports ohne Rack-Neuanlage. + +**Grafische Attribute** +- `x`, `y`, `width`, `height` für die Visualisierung im Floorplan. +- `name`/`label` und `port_count` für die eindeutige Kennzeichnung. +- Optional: `connection_group` oder `cross_connect_id`, um zusammengehörige Patchfelder zu bündeln. + +**Verbindungen** +- Jeder Patchpanel-Port wird über `connections` mit passenden Gegenstellen verbunden (andere Patchpanels, Dosen, Geräteports, Module). +- Da sie Teil der Floorplan-Grafik sind, lassen sich die permanenten Kabelverbindungen direkt auf der Stockwerkskarte darstellen. + +### Tabellenstruktur `floor_patchpanels` +Die Bühne für Patchpanel-Objekte auf dem Stockwerkplan. +- `floor_id` referenziert das Stockwerk, in dem das Panel liegt. +- `pos_x`, `pos_y`, `width`, `height` definieren das feste Rechteck auf der SVG. +- `port_count` und `comment` beschreiben die Kapazität und zusätzliche Hinweise. + +### Tabellenstruktur `floor_patchpanel_ports` +- Jeder Eintrag ist ein physischer Port eines Patchpanels. +- Attributes: Panel-Referenz, `name`, `port_type_id`, optionale VLAN- bzw. Status-Attribute. +- Ports werden über `connections` sowohl mit anderen Patchpanels als auch mit Netzwerkbuchsen (`network_outlet_ports`) oder Gerätports verbunden; dadurch lassen sich Router-Kabel grafisch darstellen. + +**TODO** +- [ ] Floorplan- und CRUD-Module so erweitern, dass Patchpanels als Floor-Objekte verwaltet und deren Ports gepflegt werden können (`floor_patchpanels`, `floor_patchpanel_ports`). +- [ ] Verbindungen zwischen Patchpanel ↔ Patchpanel und Patchpanel ↔ Netzwerkbuchse standardisiert in der `connections`-Logik abbilden. +- [ ] UI/CSV/Export/Dokumentation nachziehen, damit Planer sofort sehen, wo die permanent installierten Kabel verlaufen. + +--- + ## 3. Racks & physische Infrastruktur ### `racks` diff --git a/init.sql b/init.sql index d826c10..87ad7ef 100644 --- a/init.sql +++ b/init.sql @@ -338,6 +338,41 @@ CREATE TABLE `network_outlet_ports` ( -- -------------------------------------------------------- +-- +-- Tabellenstruktur für Tabelle `floor_patchpanels` +-- + +CREATE TABLE `floor_patchpanels` ( + `id` int(11) NOT NULL, + `floor_id` int(11) NOT NULL, + `name` varchar(255) NOT NULL, + `pos_x` int(11) NOT NULL DEFAULT 0, + `pos_y` int(11) NOT NULL DEFAULT 0, + `width` int(11) NOT NULL DEFAULT 0, + `height` int(11) NOT NULL DEFAULT 0, + `port_count` int(11) NOT NULL DEFAULT 0, + `comment` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `floor_patchpanel_ports` +-- + +CREATE TABLE `floor_patchpanel_ports` ( + `id` int(11) NOT NULL, + `patchpanel_id` int(11) NOT NULL, + `name` varchar(50) NOT NULL, + `port_type_id` int(11) DEFAULT NULL, + `status` enum('active','inactive','pending') NOT NULL DEFAULT 'active', + `comment` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; + +-- TODO: Port-Konfiguration (Patchpanel ↔ Patchpanel, Patchpanel ↔ Netzwerkbuchse) wird über die `connections`-Tabelle geregelt. + +-- -------------------------------------------------------- + -- -- Tabellenstruktur für Tabelle `port_types` -- @@ -509,6 +544,21 @@ ALTER TABLE `network_outlet_ports` ADD PRIMARY KEY (`id`), ADD KEY `outlet_id` (`outlet_id`); +-- +-- Indizes für die Tabelle `floor_patchpanels` +-- +ALTER TABLE `floor_patchpanels` + ADD PRIMARY KEY (`id`), + ADD KEY `floor_id` (`floor_id`); + +-- +-- Indizes für die Tabelle `floor_patchpanel_ports` +-- +ALTER TABLE `floor_patchpanel_ports` + ADD PRIMARY KEY (`id`), + ADD KEY `patchpanel_id` (`patchpanel_id`), + ADD KEY `port_type_id` (`port_type_id`); + -- -- Indizes für die Tabelle `port_types` -- @@ -624,8 +674,20 @@ ALTER TABLE `network_outlet_ports` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; -- --- AUTO_INCREMENT für Tabelle `port_types` +-- AUTO_INCREMENT für Tabelle `floor_patchpanels` -- +ALTER TABLE `floor_patchpanels` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT für Tabelle `floor_patchpanel_ports` +-- +ALTER TABLE `floor_patchpanel_ports` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT für Tabelle `port_types` +-- ALTER TABLE `port_types` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; @@ -714,8 +776,21 @@ ALTER TABLE `network_outlet_ports` ADD CONSTRAINT `network_outlet_ports_ibfk_1` FOREIGN KEY (`outlet_id`) REFERENCES `network_outlets` (`id`) ON DELETE CASCADE; -- --- Constraints der Tabelle `racks` +-- Constraints der Tabelle `floor_patchpanels` -- +ALTER TABLE `floor_patchpanels` + ADD CONSTRAINT `floor_patchpanels_ibfk_1` FOREIGN KEY (`floor_id`) REFERENCES `floors` (`id`) ON DELETE CASCADE; + +-- +-- Constraints der Tabelle `floor_patchpanel_ports` +-- +ALTER TABLE `floor_patchpanel_ports` + ADD CONSTRAINT `floor_patchpanel_ports_ibfk_1` FOREIGN KEY (`patchpanel_id`) REFERENCES `floor_patchpanels` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `floor_patchpanel_ports_ibfk_2` FOREIGN KEY (`port_type_id`) REFERENCES `port_types` (`id`); + +-- +-- Constraints der Tabelle `racks` +-- ALTER TABLE `racks` ADD CONSTRAINT `racks_ibfk_1` FOREIGN KEY (`floor_id`) REFERENCES `floors` (`id`) ON DELETE CASCADE;