feat(sdk): Multi-Projekt-Architektur — mehrere Projekte pro Tenant
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 33s
CI / test-python-backend-compliance (push) Successful in 34s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 19s
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 33s
CI / test-python-backend-compliance (push) Successful in 34s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 19s
Jeder Tenant kann jetzt mehrere Compliance-Projekte anlegen (z.B. verschiedene Produkte, Tochterunternehmen). CompanyProfile ist pro Projekt kopierbar und danach unabhaengig editierbar. Multi-Tab-Support via separater BroadcastChannel und localStorage Keys pro Projekt. - Migration 039: compliance_projects Tabelle, sdk_states.project_id - Backend: FastAPI CRUD-Routes fuer Projekte mit Tenant-Isolation - Frontend: ProjectSelector UI, SDKProvider mit projectId, URL ?project= - State API: UPSERT auf (tenant_id, project_id) mit Abwaertskompatibilitaet - Tests: pytest fuer Model-Validierung, Row-Konvertierung, Tenant-Isolation - Docs: MKDocs Seite, CLAUDE.md, Backend README Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,7 @@ const DEFAULT_MAX_RETRIES = 3
|
||||
export class StateSyncManager {
|
||||
private apiClient: SDKApiClient
|
||||
private tenantId: string
|
||||
private projectId: string | undefined
|
||||
private options: Required<SyncOptions>
|
||||
private callbacks: SyncCallbacks
|
||||
private syncState: SyncState
|
||||
@@ -71,10 +72,12 @@ export class StateSyncManager {
|
||||
apiClient: SDKApiClient,
|
||||
tenantId: string,
|
||||
options: SyncOptions = {},
|
||||
callbacks: SyncCallbacks = {}
|
||||
callbacks: SyncCallbacks = {},
|
||||
projectId?: string
|
||||
) {
|
||||
this.apiClient = apiClient
|
||||
this.tenantId = tenantId
|
||||
this.projectId = projectId
|
||||
this.callbacks = callbacks
|
||||
this.options = {
|
||||
debounceMs: options.debounceMs ?? DEFAULT_DEBOUNCE_MS,
|
||||
@@ -105,7 +108,10 @@ export class StateSyncManager {
|
||||
}
|
||||
|
||||
try {
|
||||
this.broadcastChannel = new BroadcastChannel(`${SYNC_CHANNEL}-${this.tenantId}`)
|
||||
const channelName = this.projectId
|
||||
? `${SYNC_CHANNEL}-${this.tenantId}-${this.projectId}`
|
||||
: `${SYNC_CHANNEL}-${this.tenantId}`
|
||||
this.broadcastChannel = new BroadcastChannel(channelName)
|
||||
this.broadcastChannel.onmessage = this.handleBroadcastMessage.bind(this)
|
||||
} catch (error) {
|
||||
console.warn('BroadcastChannel not available:', error)
|
||||
@@ -209,7 +215,9 @@ export class StateSyncManager {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
private getStorageKey(): string {
|
||||
return `${STORAGE_KEY_PREFIX}-${this.tenantId}`
|
||||
return this.projectId
|
||||
? `${STORAGE_KEY_PREFIX}-${this.tenantId}-${this.projectId}`
|
||||
: `${STORAGE_KEY_PREFIX}-${this.tenantId}`
|
||||
}
|
||||
|
||||
saveToLocalStorage(state: SDKState): void {
|
||||
@@ -476,7 +484,8 @@ export function createStateSyncManager(
|
||||
apiClient: SDKApiClient,
|
||||
tenantId: string,
|
||||
options?: SyncOptions,
|
||||
callbacks?: SyncCallbacks
|
||||
callbacks?: SyncCallbacks,
|
||||
projectId?: string
|
||||
): StateSyncManager {
|
||||
return new StateSyncManager(apiClient, tenantId, options, callbacks)
|
||||
return new StateSyncManager(apiClient, tenantId, options, callbacks, projectId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user