Initial state for GitNexus analysis

This commit is contained in:
Zaid Marzguioui
2026-03-29 19:44:57 +02:00
parent 9d7c7f8030
commit 61ff48cb73
155 changed files with 23483 additions and 1722 deletions

View File

@@ -0,0 +1,97 @@
/**
* CMS Billing Plans — Stripe product configuration
* Phase 12: Three tiers for the SaaS product
*/
export const CMS_BILLING_PLANS = {
starter: {
name: 'Starter',
description: 'Für kleine Vereine und Organisationen',
limits: {
modules: 1,
records: 100,
members: 50,
storageGb: 1,
users: 3,
},
features: [
'Module Builder (1 Modul)',
'Mitgliederverwaltung (bis 50)',
'Basisfunktionen',
'Deutsche Oberfläche',
'E-Mail-Support',
],
pricing: {
monthly: { amount: 1900, currency: 'eur' }, // 19,00 €
yearly: { amount: 19000, currency: 'eur' }, // 190,00 € (2 Monate gratis)
},
},
professional: {
name: 'Professional',
description: 'Für aktive Vereine und Volkshochschulen',
limits: {
modules: -1, // unlimited
records: -1,
members: -1,
storageGb: 10,
users: 20,
},
features: [
'Unbegrenzte Module',
'Unbegrenzte Mitglieder',
'Kursverwaltung',
'SEPA-Lastschriften',
'Newsletter',
'Dokumentengenerierung',
'Import/Export',
'Prioritäts-Support',
],
pricing: {
monthly: { amount: 4900, currency: 'eur' }, // 49,00 €
yearly: { amount: 49000, currency: 'eur' }, // 490,00 €
},
},
enterprise: {
name: 'Enterprise',
description: 'Für große Organisationen mit individuellen Anforderungen',
limits: {
modules: -1,
records: -1,
members: -1,
storageGb: 100,
users: -1,
},
features: [
'Alles aus Professional',
'White-Label / eigenes Branding',
'REST-API Zugang',
'Multi-Mandanten-Verwaltung',
'Dedizierte Instanz (optional)',
'Individuelle Anpassungen',
'Persönlicher Ansprechpartner',
'SLA-Garantie',
],
pricing: {
monthly: { amount: 14900, currency: 'eur' }, // 149,00 €
yearly: { amount: 149000, currency: 'eur' }, // 1.490,00 €
},
},
} as const;
export type BillingPlanKey = keyof typeof CMS_BILLING_PLANS;
/**
* Check if a plan allows a given feature/limit.
*/
export function checkPlanLimit(
plan: BillingPlanKey,
limit: keyof typeof CMS_BILLING_PLANS.starter.limits,
currentUsage: number,
): boolean {
const planLimits = CMS_BILLING_PLANS[plan].limits;
const max = planLimits[limit];
if (max === -1) return true; // unlimited
return currentUsage < max;
}

View File

@@ -41,6 +41,15 @@ const FeatureFlagsSchema = z.object({
enableTeamsOnly: z.boolean({
error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_ONLY',
}),
// CMS feature flags
enableModuleBuilder: z.boolean().default(true),
enableMemberManagement: z.boolean().default(true),
enableCourseManagement: z.boolean().default(true),
enableBookingManagement: z.boolean().default(false),
enableSepaPayments: z.boolean().default(true),
enableDocumentGeneration: z.boolean().default(true),
enableNewsletter: z.boolean().default(true),
enableGdprCompliance: z.boolean().default(true),
});
const featuresFlagConfig = FeatureFlagsSchema.parse({
@@ -90,6 +99,39 @@ const featuresFlagConfig = FeatureFlagsSchema.parse({
process.env.NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_ONLY,
false,
),
// CMS feature flags
enableModuleBuilder: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_MODULE_BUILDER,
true,
),
enableMemberManagement: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_MEMBER_MANAGEMENT,
true,
),
enableCourseManagement: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_COURSE_MANAGEMENT,
true,
),
enableBookingManagement: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_BOOKING_MANAGEMENT,
false,
),
enableSepaPayments: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_SEPA_PAYMENTS,
true,
),
enableDocumentGeneration: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_DOCUMENT_GENERATION,
true,
),
enableNewsletter: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_NEWSLETTER,
true,
),
enableGdprCompliance: getBoolean(
process.env.NEXT_PUBLIC_ENABLE_GDPR_COMPLIANCE,
true,
),
} satisfies z.output<typeof FeatureFlagsSchema>);
export default featuresFlagConfig;

View File

@@ -22,6 +22,14 @@ const PathsSchema = z.object({
accountProfileSettings: z.string().min(1),
createTeam: z.string().min(1),
joinTeam: z.string().min(1),
// CMS paths
accountModules: z.string().min(1),
accountCmsMembers: z.string().min(1),
accountCourses: z.string().min(1),
accountBookings: z.string().min(1),
accountFinance: z.string().min(1),
accountDocuments: z.string().min(1),
accountNewsletter: z.string().min(1),
}),
});
@@ -47,6 +55,14 @@ const pathsConfig = PathsSchema.parse({
accountProfileSettings: `/home/[account]/settings/profile`,
createTeam: '/home/create-team',
joinTeam: '/join',
// CMS paths
accountModules: `/home/[account]/modules`,
accountCmsMembers: `/home/[account]/members-cms`,
accountCourses: `/home/[account]/courses`,
accountBookings: `/home/[account]/bookings`,
accountFinance: `/home/[account]/finance`,
accountDocuments: `/home/[account]/documents`,
accountNewsletter: `/home/[account]/newsletter`,
},
} satisfies z.output<typeof PathsSchema>);

View File

@@ -1,4 +1,8 @@
import { CreditCard, LayoutDashboard, Settings, Users } from 'lucide-react';
import {
CreditCard, LayoutDashboard, Settings, Users, Database,
UserCheck, GraduationCap, Hotel, Calendar, Wallet,
FileText, Mail,
} from 'lucide-react';
import { NavigationConfigSchema } from '@kit/ui/navigation-schema';
@@ -17,7 +21,61 @@ const getRoutes = (account: string) => [
Icon: <LayoutDashboard className={iconClasses} />,
highlightMatch: `${pathsConfig.app.home}$`,
},
],
featureFlagsConfig.enableModuleBuilder
? {
label: 'common.routes.modules',
path: createPath(pathsConfig.app.accountModules, account),
Icon: <Database className={iconClasses} />,
}
: undefined,
featureFlagsConfig.enableMemberManagement
? {
label: 'common.routes.cmsMembers',
path: createPath(pathsConfig.app.accountCmsMembers, account),
Icon: <UserCheck className={iconClasses} />,
}
: undefined,
featureFlagsConfig.enableCourseManagement
? {
label: 'common.routes.courses',
path: createPath(pathsConfig.app.accountCourses, account),
Icon: <GraduationCap className={iconClasses} />,
}
: undefined,
featureFlagsConfig.enableBookingManagement
? {
label: 'common.routes.bookings',
path: createPath(pathsConfig.app.accountBookings, account),
Icon: <Hotel className={iconClasses} />,
}
: undefined,
{
label: 'common.routes.events',
path: createPath(`/home/[account]/events`, account),
Icon: <Calendar className={iconClasses} />,
},
featureFlagsConfig.enableSepaPayments
? {
label: 'common.routes.finance',
path: createPath(pathsConfig.app.accountFinance, account),
Icon: <Wallet className={iconClasses} />,
}
: undefined,
featureFlagsConfig.enableDocumentGeneration
? {
label: 'common.routes.documents',
path: createPath(pathsConfig.app.accountDocuments, account),
Icon: <FileText className={iconClasses} />,
}
: undefined,
featureFlagsConfig.enableNewsletter
? {
label: 'common.routes.newsletter',
path: createPath(pathsConfig.app.accountNewsletter, account),
Icon: <Mail className={iconClasses} />,
}
: undefined,
].filter(Boolean),
},
{
label: 'common.routes.settings',