# Feature Specification: Global Policy Search **Feature Branch**: `001-global-policy-search` **Created**: 2025-12-05 **Status**: Draft **Input**: User description: "Global Policy Search for Intune settings - A search engine within the SaaS app that indexes and searches all Intune policy settings" ## Clarifications ### Session 2025-12-07 - Q: Welche Synchronisierungsstrategie soll die Ingestion-API verwenden? → A: Incrementelles Upsert (nur geänderte Settings) - Die API führt ein Upsert durch (unique constraint auf tenantId + graphPolicyId + settingName), sodass nur neue/geänderte Einstellungen geschrieben werden. Dies minimiert Datenbankload und ist skalierbar. - Q: Welche Suchlatenz wird unter verschiedenen Lastszenarien garantiert? → A: Immer < 2s garantiert (auch bei 100 gleichzeitigen Anfragen) - Strikte Performance-Anforderung für alle Lastbedingungen. Erfordert optimierte Datenbankindizes und möglicherweise Caching-Strategie. ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Search Policy Settings (Priority: P1) Als Intune-Admin möchte ich nach einem Suchbegriff (z.B. "USB", "Camera", "Defender") suchen, um alle Policies zu finden, die diese Einstellung enthalten. **Why this priority**: Dies ist die Kernfunktion der Suchmaschine. Ohne Suchfunktion hat das Feature keinen Wert. **Independent Test**: Kann getestet werden, indem Testdaten in der DB angelegt werden und ein Suchbegriff eingegeben wird. Liefert sofort Mehrwert, da Admins Einstellungen finden können. **Acceptance Scenarios**: 1. **Given** der Admin ist eingeloggt und es existieren Policy-Einstellungen in der DB, **When** der Admin "USB" in das Suchfeld eingibt und Enter drückt, **Then** sieht er eine Tabelle mit allen Policies, die "USB" im Einstellungs-Namen oder -Wert enthalten. 2. **Given** der Admin ist eingeloggt, **When** er einen Suchbegriff eingibt der nicht existiert (z.B. "xyz123nonexistent"), **Then** sieht er eine leere Tabelle mit einer "Keine Ergebnisse gefunden"-Nachricht. 3. **Given** der Admin ist eingeloggt, **When** er nichts eingibt und Enter drückt, **Then** werden alle Einstellungen angezeigt (oder eine Aufforderung, einen Suchbegriff einzugeben). --- ### User Story 2 - Tenant-isolierte Ergebnisse (Priority: P1) Als Intune-Admin möchte ich sicherstellen, dass ich NUR die Policy-Einstellungen meines eigenen Tenants sehe, nicht die anderer Kunden. **Why this priority**: Sicherheit ist geschäftskritisch. Ohne Tenant-Isolation ist das Feature unbrauchbar für eine Multi-Tenant SaaS. **Independent Test**: Testbar durch Anlegen von Testdaten für zwei verschiedene Tenants und Verifizierung, dass jeder Tenant nur seine eigenen Daten sieht. **Acceptance Scenarios**: 1. **Given** Admin A (TenantId: "tenant-a") und Admin B (TenantId: "tenant-b") existieren, **When** Admin A nach "USB" sucht, **Then** sieht er nur Ergebnisse mit TenantId = "tenant-a". 2. **Given** Admin A ist eingeloggt, **When** er versucht über URL-Manipulation oder API-Calls auf Daten von Tenant B zuzugreifen, **Then** erhält er keine Ergebnisse oder einen 403 Fehler. --- ### User Story 3 - Daten-Ingestion API (Priority: P2) Als n8n-Workflow möchte ich Policy-Einstellungen über eine API in die Datenbank schreiben können, damit die Suchdaten aktuell gehalten werden. **Why this priority**: Ohne Daten keine Suche. Diese User Story ist P2, weil für den MVP Test-Daten manuell eingefügt werden können. **Independent Test**: Testbar durch Senden eines POST-Requests mit Policy-Daten an die API und Verifizierung, dass die Daten in der DB erscheinen. **Acceptance Scenarios**: 1. **Given** ein gültiger API-Request mit Policy-Daten, **When** der Request an `/api/policy-settings` gesendet wird, **Then** werden die Daten in der DB gespeichert (upsert-Logik). 2. **Given** ein API-Request ohne gültige Authentifizierung, **When** der Request gesendet wird, **Then** wird ein 401 Unauthorized zurückgegeben. --- ### Edge Cases - Was passiert bei sehr langen Suchbegriffen (>500 Zeichen)? → Begrenzen auf 200 Zeichen. - Wie verhält sich die Suche bei Sonderzeichen (SQL-Injection)? → Parametrisierte Queries via Drizzle ORM. - Was passiert wenn die DB nicht erreichbar ist? → Fehlermeldung "Service temporarily unavailable". - Groß-/Kleinschreibung bei der Suche? → Case-insensitive Suche. ## Requirements *(mandatory)* ### Functional Requirements - **FR-001**: System MUSS eine Suchseite unter `/search` bereitstellen. - **FR-002**: System MUSS ein Suchfeld (Shadcn Input) auf der Suchseite anzeigen. - **FR-003**: System MUSS eine Ergebnistabelle (Shadcn Table) mit den Spalten: Einstellungs-Name, Einstellungs-Wert, Policy-Name, Policy-Typ anzeigen. - **FR-004**: System MUSS Suchergebnisse nach `tenantId` der aktuellen Session filtern. - **FR-005**: System MUSS case-insensitive Suche über `settingName` und `settingValue` durchführen. - **FR-006**: System MUSS Suchergebnisse aus der lokalen PostgreSQL Datenbank laden (kein Live-API-Call zu Microsoft Graph). - **FR-007**: System MUSS eine API-Route `/api/policy-settings` bereitstellen für das Einfügen/Aktualisieren von Daten (POST mit upsert-Logik). - **FR-008**: System MUSS alle Datenbank-Operationen über Drizzle ORM durchführen. - **FR-009**: System MUSS Server Actions für die Suchfunktion verwenden (keine Client-Side Fetches). ### Key Entities - **PolicySetting**: Repräsentiert eine einzelne Einstellung innerhalb einer Intune-Policy. - `id`: Eindeutiger Identifier (UUID) - `tenantId`: Azure AD Tenant ID des Kunden (für Multi-Tenancy Isolation) - `policyName`: Name der Policy (z.B. "Windows 10 Compliance Policy") - `policyType`: Typ der Policy (z.B. "Compliance", "Configuration", "Security") - `settingName`: Name der Einstellung (z.B. "allowCamera", "allowUSBConnection") - `settingValue`: Wert der Einstellung (z.B. "blocked", "allowed", "true") - `graphPolicyId`: Original Microsoft Graph ID der Policy (für Referenz) - `lastSyncedAt`: Zeitpunkt der letzten Synchronisation ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: Admin kann eine Suche durchführen und Ergebnisse in unter 2 Sekunden sehen (garantiert auch bei 100 gleichzeitigen Anfragen). - **SC-002**: 100% der Suchanfragen werden mit Tenant-Filterung ausgeführt. - **SC-003**: Suchergebnisse werden aus der lokalen Datenbank geladen (keine externen API-Calls während der Suche). - **SC-004**: Admin findet alle relevanten Policies, die den Suchbegriff im Einstellungs-Namen oder -Wert enthalten. - **SC-005**: Datenbankindizes auf `tenantId`, `settingName` und `settingValue` gewährleisten konstante Performance unter Last. ## Assumptions - Die Daten werden von einem externen n8n-Workflow in die Datenbank geschrieben. - Die TenantId ist in der NextAuth-Session verfügbar (aus Azure AD Claims). - Die Suche ist auf Text-basierte Filterung beschränkt (kein Full-Text-Search mit Ranking in v1). - Maximal 10.000 Einstellungen pro Tenant werden initial unterstützt.