Files
HiveGrid-Wireframes/hivegrid-cloud/docs/boilerplate-mapping/M32-feature-flags.md
T

17 KiB

Boilerplate-Abgleich — Modul M32 (Feature-Flags / Admin-UI)

  • Modul-ID: M32
  • Name: Feature-Flags (Plattform-Admin-UI)
  • Milestones: M031 (Schalter-Definition + Lifecycle), M032 (Filter-Editor + Einzel-Ausnahme), M033 (Massen-Funktionen + Statistik + Audit-Historie)
  • Block: Block 1 · Modul 32 (Pflichtenheft block1.md §32.1-32.9)
  • LP: LP-9 (Spec-Tiefe), LP-10 (Klartext-Diagnostik); ist selbst die Umsetzung von AV #7 (Feature-Flag-Hülle) und AV #6 (Audit-Default)
  • Reuse-Level: medium — sehr starke, getestete Querschnitt-/Engine-Basis (Paket @toolctrl/feature-flags) vorhanden; das fachliche Datenmodell der Spec (Lifecycle, Tenant-Override, Filter mit Priority/Criteria/Value, Owner, Audit-Diff) und die konkrete Admin-UI müssen aber nennenswert ergänzt/neu gebaut werden.

Verifiziert direkt in /Users/raffaelsheikh/Documents/GitHub/boilerplate (nicht nur Inventur). Hinweis: HiveGrid hat noch kein Prisma-Schema (/Users/raffaelsheikh/Documents/GitHub/HiveGrid-Cloud/prisma enthält nur init-db.sql), keine packages/ui-hivegrid, kein app/routes. Die Boilerplate-Artefakte sind daher als Vorlage/zu portieren zu betrachten, nicht 1:1-Import in ein bestehendes HiveGrid-Paket.


Übernehmbar aus Boilerplate

Boilerplate-Pfad Was Wie nutzbar
packages/feature-flags/src/evaluate.ts evaluateFlag(name, ctx, opts) — DB-freie Eval-Engine via FlagLoader-Callback, mit Zeitfenster, Parent-Dependency (Zyklus-Schutz maxDepth=8), Variant-Bucketing. EvaluateFlagResult.reason (flag-not-found/disabled/…/matched) anpassen — Fundament für tenantHasFlag. Spec-Auswertungsreihenfolge (Override → Filter nach priority → default_value) ist NICHT die Paket-Logik; muss als eigene Resolver-Schicht oben drauf oder als neuer Rule-/Loader-Aufbau ergänzt werden.
packages/feature-flags/src/targeting/evaluator.ts + targeting/types.ts Reiner Regel-Evaluator + Rule-Union (allowlist/percentage/plan-tier/role-based/time-based/composite) als-vorlage — Pattern für deterministische, I/O-freie, total-typsichere Regel-Auswertung. HiveGrid-Filter-Criteria (tenant_size, tenant_industry, tenant_status, subscription_product_id, tenant_created_*, tenant_id_in/not_in) sind andere Leaf-Typen → analog ergänzen. AND-Verknüpfung + Exhaustiveness-Check direkt übernehmbar.
packages/feature-flags/src/targeting/percentage.ts computeBucket, isInRolloutBucket (sticky Hash-Bucketing) als-vorlage — in Phase 1 nicht benötigt (Prozent-Rollout = Phase 2), aber für M032/Phase-2 vorhanden.
packages/feature-flags/src/cache.ts createFlagEvalCache, buildCacheKey, hashContext, FEATURE_FLAGS_INVALIDATION_CHANNEL anpassen — deckt das Spec-Caching (Block E: Request-scoped, kein wiederholtes DB-Roundtrip) ab. Cache-Key müsste um Resolver-Inputs (TenantOverride/Filter-Set) erweitert werden; Cross-Replica-Invalidierung bei Admin-Save bereits gelöst.
packages/feature-flags/src/publisher.ts publishFeatureFlagInvalidationOnce/ViaStore (Cross-Process-Invalidierung via shared-store) 1:1 — bei jeder Flag-/Filter-/Override-Mutation aus Admin-Action aufrufbar.
packages/feature-flags/src/client/context.tsx FeatureFlagProvider, useFeatureFlag, useFeatureFlagEnabled, useFeatureFlagVariant (SSR-Hydration) 1:1 / anpassen — Phase 1 hat kein Tenant-User-UI für Flags, aber das Hydration-Pattern ist für flag-gegatete UI (AV #7) generell nutzbar (deckt INTEGRATION-CONTRACTS §2 feature_flag?-Gate ab).
packages/foundation/src/flags.ts defineFlag, featureFlag, selectFlagRecord (leichtgewichtige Auflösung user > tenant > global, override) als-vorlage — die selectFlagRecord-Präzedenz (User→Tenant→Global) ist konzeptuell nah an der Spec-Reihenfolge (Override→…→Default). Für ein einfaches tenantHasFlag ggf. direkt erweiterbar; berücksichtigt aber keine priority-sortierten Filter.
packages/foundation/src/audit.ts auditEvent(input, client), withAuditMiddleware(handler, buildEvent, client) 1:1 — erfüllt Block G (Audit-Logging mit Vorher/Nachher). Wrappt jede mutierende Flag-/Filter-/Override-Action. Schreibt nach AuditEvent (core.prisma).
packages/foundation/src/permissions.ts requirePermission, withPermission, withTenantScope, withOwnerCheck 1:1 — für Block H (admin.feature_flags.read/write/lifecycle). Liefert bei Fehlschlag CatalogError(notFound) → 404 statt 403 (deckt DoD „Permission-Denied → 404" / INTEGRATION-CONTRACTS A.5.3).
packages/foundation/src/errors.ts CatalogError, foundationErrors, catalogRegistry, toPinoLogObject 1:1 — Klartext-Fehler mit i18nKey für Block I (Lookup-auf-unbekannten-Key, Vergangenheits-expires_at usw.).
packages/view-models/src/index.ts VMState, VMStatus, ActionCallbacks, RegistryGate, SidebarRegistryItem, ready/empty, assertI18nLabel 1:1 — Loader-baut-VM-Disziplin (DoD „Loader baut VM; UI nur VM+Actions"), Empty-/Loading-/Error-States, Sidebar-Registry-Gate.
packages/i18n/src/* useTranslate-Factory, Intl-Formatter, ICU, Namespaces, assertI18nKey 1:1 — alle UI-Texte als i18n-Keys (DoD/INTEGRATION-CONTRACTS §10).
packages/url/src/canonical.ts adminPath/adminUrl (host-aware) 1:1 — alle Routen liegen auf admin.hivegrid.de (Block B).
prisma/schema/core.prisma → AuditEvent (Z.55) Append-only Audit-Event mit actorType, action, targetType/Id, metadata, previousHash/eventHash (Hash-Chain), dataSensitivity, regulatoryScope[] 1:1 — Ziel-Tabelle für Block G. Diff (oldValue/newValue) als metadata ablegbar.
prisma/schema/core.prisma → IdempotencyKey (Z.84) @@unique([scope, key]) 1:1 — für idempotente Bulk-Override-Actions (M033).
apps/web/app/routes/admin/feature-flags/* (feature-flags.tsx, index.tsx, flags.tsx, flags/$id.tsx, flags/new.tsx, settings.tsx, engine.tsx) Bestehende Plattform-Admin-Routen-Struktur (Liste/Detail/New, Sidebar-Icon-Layout, Permission-Gate admin.featureFlags.view/manage) als-vorlage — Routen-Aufteilung und Admin-Gating als Blaupause. UI deckt jedoch nur einfache An/Aus + analytics-orientierte Filter ab, nicht Lifecycle/Tenant-Override/Priority/Statistik/Audit-Historie.
apps/web/app/modules/featureFlags/db/featureFlags.db.server.ts getAllFeatureFlags, getFeatureFlag, create/update/deleteFeatureFlag, Cache-Invalidierung als-vorlage — DB-Server-Layer-Muster (.db.server.ts). Muss um Lifecycle/Owner/TargetModule/Archiv/Tenant-Override/Filter-Priority erweitert werden.
apps/web/app/modules/featureFlags/components/FeatureFlagForm.tsx, FeatureFlagTracker.tsx Anlege-/Edit-Form + Analytics-Tracker-Component als-vorlage — Form-Struktur wiederverwendbar; HiveGrid-Felder/UI (Lifecycle-Dropdown, Owner, Modul-Tag, Default-Toggle) ergänzen.
apps/web/app/utils/services/.server/featureFlagEvaluator.server.ts, featureFlagCache.server.ts, featureFlagsRequest.server.ts Server-Bridge zwischen Prisma-FeatureFlag und Paket-evaluateFlag (OR-Lookup name/id, L2-Cache, Memo 60s) anpassen — Vorlage für die HiveGrid-tenantHasFlag-Server-Bridge; Resolution-Order/Loader an Spec-Modell anpassen.
apps/web/app/components/layouts/icons/IconFeatureFlags.tsx Sidebar-Icon 1:1 — Icon übernehmbar.
apps/web/app/application/sidebar/AdminSidebar.tsx (Z.206-215) Admin-Sidebar-Registrierung der Feature-Flags-Gruppe inkl. Sub-Items + Permission-Gate als-vorlage — Muster für die HiveGrid-Sidebar (packages/ui-hivegrid/src/app-shell/sidebar.config.ts, INTEGRATION-CONTRACTS §2).
packages/shared-store/* createTwoTierCache, Pub/Sub 1:1 — Infrastruktur, die cache.ts/publisher.ts benötigen.

Vorhandene Daten-Modelle (konkret, mit Pfad)

Alle in /Users/raffaelsheikh/Documents/GitHub/boilerplate/prisma/schema/:

  • FeatureFlag — featureFlags.prisma:1 Felder: id, createdAt, updatedAt, key String?, scope (default global), tenantId?, userId?, name, description, enabled, sowie v2-Targeting-Felder rules Json?, variants Json[], enabledFrom?, enabledUntil?, parentFlagId? (Self-Relation FeatureFlagDependency). Relationen: audits, events (Analytics), filters. Indizes: @@unique([name, description]), [key, scope], [tenantId, key], [userId, key], [parentFlagId].
  • FeatureFlagFilter — featureFlags.prisma:32 Felder: id, createdAt, featureFlagId, type String, value String?, action String? (onDelete: Cascade).
  • FeatureFlagAudit — featureFlags.prisma:44 Append-only: id, flagId, actorUserId?, action (create/update/delete/toggle), oldValue Json?, newValue Json?, createdAt. Indizes [flagId, createdAt], [actorUserId, createdAt].
  • AuditEvent — core.prisma:55 (Querschnitt-Audit, Hash-Chain, tenant-aware).
  • IdempotencyKey — core.prisma:84.
  • Tenant — accounts.prisma (für Filter-Criteria relevant: slug, name, active, createdAt, subscription/productConfiguration/featureOverrides). Achtung: Es gibt kein tenant_size-, tenant_industry- oder tenant_status(trial/active/past_due/frozen/suspended)-Feld am Boilerplate-Tenant — nur active Boolean + deactivatedReason. Die Spec-Filter-Criteria brauchen also entweder zusätzliche Tenant-Felder (HiveGrid-Tenant-Modell, Modul 37) oder eine Ableitung (z.B. MA-Zahl aus HR-Hub).

Lücken / komplett neu zu bauen

Datenmodell (größte Lücke)

Das Boilerplate-Schema folgt einem anderen Konzept (An/Aus + Targeting-Rules-Tree pro Flag, Filter = analytics-/session-/percentage-Match). Die Spec verlangt ein dreiteiliges Modell mit Tenant-Override und priorisierten Filtern. Konkret fehlt / weicht ab:

  • FeatureFlag — fehlende Spec-Felder: label, default_value (es gibt nur enabled), lifecycle_stage Enum (beta|rollout|ga|deprecated), owner_admin_user_id, created_by_admin_user_id, target_module, archived_at (Soft-Delete). key ist String? und nur via [name, description] unique — Spec verlangt key global unique + non-null + nach Anlage nicht editierbar.
  • FeatureFlagFilter — fehlende Spec-Felder komplett: name, priority Int, value Boolean, criteria JSONB (strukturiertes Schema), active Boolean, created_by_admin_user_id. Boilerplate-Filter (type+value String+action) ist semantisch ein anderes Konstrukt.
  • TenantFeatureFlag (Tenant-Override) — existiert nicht. Komplett neu: feature_flag_id, tenant_id, value Boolean, set_by_admin_user_id, note?, expires_at?, @@unique([feature_flag_id, tenant_id]), Indizes [tenant_id, feature_flag_id] + expires_at.

Logik

  • Auswertungs-Reihenfolge der Spec (Override → aktive Filter nach priority desc, bei Gleichstand ältester → default_value) — neu zu implementieren. Die Paket-Engine (evaluate.ts) macht Zeitfenster + Parent-Dependency + Rule-Tree, nicht die priorisierte Override/Filter/Default-Kaskade.
  • tenantHasFlag(tenantId, key) (Block E) — neue Convenience-API mit: wirft bei unbekanntem key in Dev/Staging (Schema-Drift-Schutz), loggt im Prod; Boolean-Only; Request-scoped-Cache. Vorlage: featureFlagEvaluator.server.ts, aber andere Resolution.
  • Filter-Criteria-Matcher für tenant_size/industry/status/subscription_product_id/created_*/id_in/id_not_in — neue Leaf-Evaluatoren (Pattern aus targeting/evaluator.ts).
  • Live-Vorschau „X Tenants matchen" (Block D, §32.5.4) — neue Query gegen Tenant-Tabelle (Spec: Read-Replica). Komplett neu.
  • Effektive-Auswertungs-Statistik „X aktiv / Y nicht" (Block C, §32.5.3, M033) — neue Aggregation über alle Tenants. Komplett neu.
  • Bulk-Override „12 Tenants gleichzeitig" (Block C, §32.5.6, M033) — neue idempotente Action (Vorlage IdempotencyKey/withIdempotency). Komplett neu.
  • Lifecycle-Wechsel-Workflow mit Bestätigungs-Dialog + Edge-Case-Warnungen (Block F, §32.5.7) + Archivierung/Reaktivierung (§32.5.8). Komplett neu (kein Lifecycle-Konzept in BP).
  • Expires-At-Cron (Tenant-Override-Auto-Reset) — neuer Worker-Job. Komplett neu.
  • Audit-Diff-History pro Flag im Detail-View (Block G/§32.7) — FeatureFlagAudit existiert als Tabelle, aber UI + Befüllung über alle Spec-Aktionen (Filter-, Override-, Lifecycle-, Archiv-Änderungen mit Diff) neu zu verdrahten; alternativ AuditEvent (Querschnitt M21) nutzen.

UI (HiveGrid-spezifisch, komplett neu in packages/ui-hivegrid + app/routes)

  • Listen-View mit Spalten/Filter/Suche/Sortierung/„Archivierte anzeigen"/Quick-Actions (Lifecycle, Archiv) — BP-flags.tsx deckt nur Teil ab.
  • Detail-View mit Sektionen Stammdaten/Filter/Tenant-Overrides/Statistik/Audit, Inline-Edit, Filter-Editor mit Criteria-Builder + Live-Vorschau, Tenant-Override-Editor mit Tenant-Autocomplete + Expires-At, Bulk-Override-UI, Lifecycle-Confirm-Dialog.
  • Alle als View-Model (Loader) + reine UI-Component (kein Prisma-Import in packages/ui-hivegrid/**), Subframe-Output via Adapter (DoD).
  • Sidebar-Eintrag in packages/ui-hivegrid/src/app-shell/sidebar.config.ts + Breadcrumbs + Smoke-Test (e2e/smoke/) — Infrastruktur existiert in HiveGrid noch nicht.

Permissions

  • BP nutzt admin.featureFlags.view / admin.featureFlags.manage. Spec verlangt 3 atomare Permissions (admin.feature_flags.read/write/lifecycle) + 4 Bundles (none/viewer/operator/owner). Mapping/Definition neu (final mit Modul 37 abzustimmen — offener Spec-Punkt).

Plattform-Admin-Fundament (Vorbedingung, außerhalb M32)

  • admin.hivegrid.de-Subdomain-App-Shell, Plattform-Admin-Auth (M034), Admin-User-Modell, AdminAuditLog/Cross-Tenant-Audit (M037). In Boilerplate liegt Admin als Bereich innerhalb apps/web — HiveGrid plant separate Admin-App-Surface (INTEGRATION-CONTRACTS §1: „separate Sidebar-Struktur M034-M041"). Diese Vorbedingungen sind nicht Teil von M32 selbst, aber blockierend.

Empfohlenes Vorgehen (Reihenfolge)

  1. Querschnitt 1:1 übernehmen (kein Neubau): @toolctrl/foundation (audit, permissions, errors), @toolctrl/view-models, @toolctrl/i18n, @toolctrl/url, @toolctrl/shared-store, AuditEvent/IdempotencyKey (core.prisma). Das ist das stabile Fundament für DoD-Wiring.
  2. Engine-Paket als Basis ziehen, Resolver anpassen: @toolctrl/feature-flags (cache, publisher, client, percentage, targeting-Pattern) übernehmen; darüber einen HiveGrid-Resolver bauen, der die Spec-Reihenfolge (Override → priorisierte Filter → default) implementiert. tenantHasFlag als neue Convenience-API mit Schema-Drift-Schutz + Request-Cache (Vorlage: featureFlagEvaluator.server.ts).
  3. Datenmodell neu/erweitert (M031-Fundament): HiveGrid-Prisma-Schema anlegen. FeatureFlag um Spec-Felder erweitern (label, default_value, lifecycle_stage, owner/created_by, target_module, archived_at, key unique non-null), FeatureFlagFilter um (name, priority, value Boolean, criteria JSONB, active, created_by), TenantFeatureFlag neu. Forward-Only-Migration mit Inverse-SQL-Kommentar. Entscheiden: bestehende BP-FeatureFlagAudit nutzen oder Querschnitt-AuditEvent (Empfehlung: AuditEvent für plattformweite Durchsuchbarkeit, §32.7.2).
  4. M031 — Schalter-Definition + Lifecycle: DB-Server-Layer (.db.server.ts, Vorlage BP), Permissions (3 atomar + 4 Bundles), Routen Liste/Detail/New/Edit auf admin.hivegrid.de (Vorlage BP-Routen-Struktur), Sidebar-Registry, Lifecycle-Wechsel mit Confirm + Audit. Form-Component aus BP FeatureFlagForm.tsx als Vorlage.
  5. M032 — Filter-Editor + Einzel-Ausnahme: Criteria-Builder-UI + neue Leaf-Matcher (Pattern targeting/evaluator.ts), Live-Vorschau-Query gegen Tenant-Tabelle, Tenant-Override-Editor mit Autocomplete + Expires-At, priorisierte Auswertung + Edge-Case-Klartext (Block D). Vorab klären: welche Tenant-Felder (tenant_size/industry/status) das HiveGrid-Tenant-Modell (M37) bereitstellt — BP-Tenant hat sie nicht.
  6. M033 — Massen + Statistik + Audit: Bulk-Override (idempotent via withIdempotency), Wirkungs-Statistik-Aggregation, Audit-History-Sektion im Detail-View, Archiv-/Reaktivierungs-Flow, Expires-At-Cron-Worker, Klartext-Hinweise (§32.9 / Block I).
  7. Querschnitt-Wiring + DoD: publishFeatureFlagInvalidationOnce bei jeder Mutation, i18n-Keys durchgängig, Smoke-Tests pro Route, VM-Unit-Tests mit Zod, Visual-Regression. Permission-Denied → 404.

Kurzfazit: Das Querschnitt- und Engine-Gerüst (Paket + foundation) ist exzellent und großteils 1:1/als-Vorlage nutzbar — daher nicht „low". Aber das fachliche Kernmodell der Spec (Lifecycle + Tenant-Override + priorisierte Criteria-Filter + Owner/Audit-Diff + Statistik/Bulk) und die komplette Admin-UI sind in der Boilerplate nicht vorhanden bzw. konzeptuell abweichend → medium.