L17 Pakete: Stufen Basis/Profi, Lotse-Chat-Plätze und Kontingent
- Datenmodell: Tenant.tier (Default PROFI), lotseChatSeats, lotseChatHardLimit;
Tabelle lotse_chat_seats (RLS, TENANT_MODELS, pii-fields), Index für die
Monatszählung der Chat-Nachrichten (Migration 20260921100000_pakete)
- src/lib/plans.ts: Stufenregeln, 150 Chats je Platz, Mehrverbrauch in 100er-Paketen
- src/server/plan.ts: effektive Freischaltung = Stufe UND TenantModule, genutzt von
requireModule, assertModuleEnabled, API, Sync (Offline-Op → rejected mit Klartext),
Navigation, isLotseEnabled und planningAccess (Planung nur in Profi)
- Lotse-Chat: Platzprüfung (no_seat), Testphase ohne Platz, Kontingent mit
hartem Limit (quota_exhausted); Platzvergabe durch den Mandanten-Admin
- Betreiber: Stufe/Plätze/hartes Limit im Mandantendetail mit Bestätigung
und Plattform-Audit, Verbrauch laufender Monat/Vormonat, Stufe als Badge
- Demo-Seed: demo = Profi mit 3 Plätzen, demo2 = Basis
- Tests: test-pakete-{rules,gates,seats}
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
-- L17 Pakete (Basis/Profi) & Lotse-Chat-Plätze
|
||||
-- Additiv: Stufe + Platzanzahl + hartes Limit am Mandanten (Default PROFI = bestehende Mandanten unverändert),
|
||||
-- Tabelle lotse_chat_seats (Mandanten-RLS), Index für die Monatszählung der Chat-Nachrichten.
|
||||
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TenantTier" AS ENUM ('BASIS', 'PROFI');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "tenants" ADD COLUMN "lotse_chat_hard_limit" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "lotse_chat_seats" INTEGER NOT NULL DEFAULT 0,
|
||||
ADD COLUMN "tier" "TenantTier" NOT NULL DEFAULT 'PROFI';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "lotse_chat_seats" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenant_id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"assigned_by_id" TEXT,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "lotse_chat_seats_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "lotse_chat_seats_tenant_id_created_at_idx" ON "lotse_chat_seats"("tenant_id", "created_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "lotse_chat_seats_tenant_id_user_id_key" ON "lotse_chat_seats"("tenant_id", "user_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "lotse_messages_tenant_id_role_created_at_idx" ON "lotse_messages"("tenant_id", "role", "created_at");
|
||||
|
||||
|
||||
-- Mandantentrennung (docs/craftvia/MIGRATIONS.md)
|
||||
SELECT enable_tenant_rls('lotse_chat_seats');
|
||||
@@ -61,6 +61,13 @@ model Tenant {
|
||||
trialExpiredNoticeAt DateTime? @map("trial_expired_notice_at")
|
||||
trialDeletionNoticeAt DateTime? @map("trial_deletion_notice_at")
|
||||
|
||||
// L17 Pakete: Stufe (Basis ohne KI/Planung) + Lotse-Chat-Plätze (Plattform-Daten, nur Betreiber ändert)
|
||||
tier TenantTier @default(PROFI)
|
||||
/// Anzahl gekaufter Lotse-Chat-Plätze (Vergabe durch den Mandanten-Admin)
|
||||
lotseChatSeats Int @default(0) @map("lotse_chat_seats")
|
||||
/// true = nach Ausschöpfen des Monatskontingents gesperrt statt Mehrverbrauch
|
||||
lotseChatHardLimit Boolean @default(false) @map("lotse_chat_hard_limit")
|
||||
|
||||
users User[]
|
||||
roles Role[]
|
||||
auditLogs AuditLog[]
|
||||
@@ -1505,6 +1512,8 @@ model LotseMessage {
|
||||
conversation LotseConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([tenantId, conversationId, createdAt])
|
||||
// L17 Pakete: Monatszählung der Chats (role = user) je Mandant
|
||||
@@index([tenantId, role, createdAt])
|
||||
@@map("lotse_messages")
|
||||
}
|
||||
|
||||
@@ -1595,3 +1604,23 @@ model TenantExport {
|
||||
@@index([tenantId, createdAt])
|
||||
@@map("tenant_exports")
|
||||
}
|
||||
|
||||
// ── L17 Pakete (Basis/Profi) & Lotse-Chat-Plätze ───────────────────────────────
|
||||
|
||||
enum TenantTier {
|
||||
BASIS
|
||||
PROFI
|
||||
}
|
||||
|
||||
/// Vergebener Lotse-Chat-Platz (Mandanten-Admin vergibt bis zur vom Betreiber gesetzten Anzahl).
|
||||
model LotseChatSeat {
|
||||
id String @id @default(cuid())
|
||||
tenantId String @map("tenant_id")
|
||||
userId String @map("user_id")
|
||||
assignedById String? @map("assigned_by_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@unique([tenantId, userId])
|
||||
@@index([tenantId, createdAt])
|
||||
@@map("lotse_chat_seats")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user