112 lines
6.9 KiB
Markdown
112 lines
6.9 KiB
Markdown
# 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.
|