feat(projects): gate Project Overview behind a projects feature flag + cockpit email actions

- Migration 120 seeds the projects flag (default OFF), idempotent.
- Backend feature-flags whitelist + DEFAULT_FLAGS + clients derivation.
- adminProjects routes 403 PROJECTS_DISABLED when the flag is off.
- projectService email actions (resend/cancel/retry/send-now) + routes.
- Frontend flag type, DEFAULT_FLAGS, Features tab card (en+de).
This commit is contained in:
Luca
2026-06-06 12:59:57 +02:00
parent 874c91f944
commit 1bf0b34ea5
9 changed files with 136 additions and 1 deletions
@@ -45,6 +45,10 @@ export const DEFAULT_FLAGS: FeatureFlags = {
// Settings → Features once they've reviewed the seeded block
// library with their lawyer.
contracts: false,
// Projects (migration 120). Admin-only grouping layer above events +
// the Project Overview cockpit. Off by default — admin opts in under
// Settings → Features once they want the CRM → Overview area.
projects: false,
};
export const FEATURE_FLAGS_QUERY_KEY = ['feature-flags'] as const;
@@ -16,6 +16,7 @@ import {
Briefcase,
Wrench,
Calculator,
FolderKanban,
} from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Button, Card } from '../../../components/common';
@@ -291,6 +292,20 @@ export const FeaturesTab: React.FC = () => {
enabled={staged.hoursLogging}
onToggle={(next) => setFlag('hoursLogging', next)}
/>
<FeatureCard
icon={FolderKanban}
title={t('settings.features.projects.title', 'Projects')}
description={t(
'settings.features.projects.description',
'Admin-only grouping layer above events. Bundle several events under one project and open a 360° Project Overview cockpit — milestone timeline plus a dated feed of every email (with the actual sent preview + resend/cancel/retry actions), quote, contract, invoice, gallery and logged hour. Adds a "book to project" control when logging hours. Customers never see projects.',
)}
status="new"
statusLabel={statusLabel('new')}
sidebarLabel={t('settings.features.projects.sidebar', 'Overview')}
enabled={staged.projects}
onToggle={(next) => setFlag('projects', next)}
/>
</Section>
{/* Insights & Access */}
+5
View File
@@ -1666,6 +1666,11 @@
"title": "Stundenerfassung",
"description": "Zeiterfassung pro Kunde. Admin erfasst Datum + Start-/Endzeit + optionalen Satz-Override + Notiz. Kunden im Monatsmodus akkumulieren Stunden automatisch in den laufenden Monatsentwurf; Kunden pro Anlass sehen eine Schaltfläche „Entwurfsrechnung erstellen“, die eine eigenständige Entwurfsrechnung mit einer Zeile pro Eintrag erzeugt. Unabhängig von Rechnungen — Stunden erfassen, noch bevor die volle Abrechnungsoberfläche aktiviert ist.",
"sidebar": "Stunden"
},
"projects": {
"title": "Projekte",
"description": "Nur-Admin-Gruppierungsebene über Events. Bündle mehrere Events unter einem Projekt und öffne ein 360°-Projektübersichts-Cockpit — Meilenstein-Zeitleiste plus ein datierter Verlauf aller E-Mails (mit der tatsächlich gesendeten Vorschau + Erneut-senden/Abbrechen/Wiederholen-Aktionen), Angebote, Verträge, Rechnungen, Galerien und erfassten Stunden. Fügt beim Erfassen von Stunden eine „Auf Projekt buchen“-Option hinzu. Kunden sehen Projekte nie.",
"sidebar": "Übersicht"
}
},
"customerSurface": {
+5
View File
@@ -1224,6 +1224,11 @@
"title": "Hours logging",
"description": "Per-customer time tracking. Admin logs date + start/end times + optional rate override + note. Monthly-mode customers auto-accumulate hours into the running monthly draft; per-event customers see a \"Create draft invoice\" button that mints a standalone draft invoice with one line per entry. Independent of Bills — log hours even before turning the full billing surface on.",
"sidebar": "Hours"
},
"projects": {
"title": "Projects",
"description": "Admin-only grouping layer above events. Bundle several events under one project and open a 360° Project Overview cockpit — milestone timeline plus a dated feed of every email (with the actual sent preview + resend/cancel/retry actions), quote, contract, invoice, gallery and logged hour. Adds a \"book to project\" control when logging hours. Customers never see projects.",
"sidebar": "Overview"
}
},
"customerSurface": {
@@ -41,7 +41,11 @@ export type FeatureKey =
// upload. Independent of quotes / bills — contracts can be sent on
// their own. Seeded block bodies are examples only; admins must
// have their lawyer review before sending. See docs/crm-disclaimers.md.
| 'contracts';
| 'contracts'
// Projects (migration 120). Admin-only grouping layer above events with the
// 360° Project Overview cockpit + the "book to project" hours control. Off
// by default; gates the CRM → Overview area entirely.
| 'projects';
export type FeatureFlags = Record<FeatureKey, boolean>;