Categories
Implementation Specs (157)
- specs/AnomalyDetection/TASK1.1.md
- specs/AnomalyDetection/TASK1.2.md
- specs/AnomalyDetection/TASK1.3.md
- specs/AnomalyDetection/TASK1.4.md
- specs/AnomalyDetection/TASK2.1.md
- specs/AnomalyDetection/TASK2.2.md
- specs/AnomalyDetection/TASK3.1.md
- specs/AnomalyDetection/TASK3.2.md
- specs/AnomalyDetection/TASK3.3.md
- specs/AnomalyDetection/TASK4.1.md
- specs/AnomalyDetection/TASK4.2.md
- specs/AnomalyDetection/TASK4.3.md
- specs/AnomalyDetection/TASK4.4.md
- specs/AnomalyDetection/TASK5.1.md
- specs/AnomalyDetection/TASK5.2.md
- specs/AnomalyDetection/TASK5.3.md
- specs/AnomalyDetection/TASK6.1.md
- specs/AnomalyDetection/TASK6.2.md
- specs/AnomalyDetection/TASK6.3.md
- specs/AnomalyDetection/TASKS.md
- specs/ApiServicePostgresTestStability/TASK.md
- specs/BackendDatabaseConsolidation/TASK.md
- specs/BackendDatabaseConsolidation/TASK1.1.md
- specs/BackendDatabaseConsolidation/TASK1.2.md
- specs/BackendDatabaseConsolidation/TASK1.3.md
- specs/BackendDatabaseConsolidation/TASK2.1.md
- specs/BackendDatabaseConsolidation/TASK2.2.md
- specs/BackendDatabaseConsolidation/TASK2.3.md
- specs/BackendDatabaseConsolidation/TASK3.1.md
- specs/BackendDatabaseConsolidation/TASK3.2.md
- specs/BackendDatabaseConsolidation/TASK4.1.md
- specs/BackendDatabaseConsolidation/TASK4.2.md
- specs/BackendDatabaseConsolidation/TASK4.3.md
- specs/BackendDatabaseConsolidation/TASK5.1.md
- specs/BackendDatabaseConsolidation/TASK5.2.md
- specs/BrinkLaborGetShiftsStaging/TASK.md
- specs/BrinkPosOrdersFirstEtlJob/TASK.md
- specs/BrinkPosOrdersFirstEtlJob/TASK0.md
- specs/BrinkPosOrdersFirstEtlJob/TASK1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.md
- specs/BrinkPosOrdersFirstEtlJob/TASK7.md
- specs/BrinkPosOrdersFirstEtlJob/TASK8.md
- specs/BrinkPosOrdersFirstEtlJob/TASK9.md
- specs/BrinkSettings2ToStaging/TASK.MD
- specs/CuratedToS3Stage/TASK.md
- specs/CuratedToS3Stage/TASK0.md
- specs/CuratedToS3Stage/TASK1.md
- specs/CuratedToS3Stage/TASK2.md
- specs/CuratedToS3Stage/TASK3.md
- specs/CuratedToS3Stage/TASK4.md
- specs/CustomerCredentialCustomHeaders/TASK.md
- specs/CustomerCredentialCustomHeaders/TASK1.1.md
- specs/CustomerCredentialCustomHeaders/TASK1.2.md
- specs/CustomerCredentialCustomHeaders/TASK2.1.md
- specs/CustomerCredentialCustomHeaders/TASK2.2.md
- specs/CustomerCredentialCustomHeaders/TASK3.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK.md
- specs/CustomerCredentialTriggeredProvisioning/TASK1.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK1.2.md
- specs/CustomerCredentialTriggeredProvisioning/TASK2.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK2.2.md
- specs/CustomerCredentialTriggeredProvisioning/TASK3.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK3.2.md
- specs/CustomerCredentialTriggeredProvisioning/TASK4.1.md
- specs/EtlSourceAdapterFramework/TASK.md
- specs/EtlSourceAdapterFramework/TASK0.md
- specs/EtlSourceAdapterFramework/TASK1.md
- specs/EtlSourceAdapterFramework/TASK2.md
- specs/EtlSourceAdapterFramework/TASK3.md
- specs/EtlSourceAdapterFramework/TASK4.md
- specs/EtlSourceAdapterFramework/TASK5.md
- specs/EtlSourceAdapterFramework/TASK6.md
- specs/KdsCdcDebeziumIntegration/TASK.md
- specs/KdsCdcDebeziumIntegration/TASK1.md
- specs/KdsCdcDebeziumIntegration/TASK2.md
- specs/KdsCdcDebeziumIntegration/TASK3.md
- specs/KdsCdcDebeziumIntegration/TASK4.md
- specs/KdsCdcDebeziumIntegration/TASK5.md
- specs/KdsCdcDurableRelationRouting/TASK.md
- specs/KdsCdcDurableRelationRouting/TASK1.md
- specs/KdsCdcDurableRelationRouting/TASK2.md
- specs/KdsCdcDurableRelationRouting/TASK3.md
- specs/KdsCdcDurableRelationRouting/TASK4.md
- specs/KdsCdcDurableRelationRouting/TASK5.md
- specs/KdsCdcIngestion/TASK.md
- specs/KdsCdcIngestion/TASK1.md
- specs/KdsCdcIngestion/TASK2.md
- specs/KdsCdcIngestion/TASK3.md
- specs/KdsCdcIngestion/TASK4.md
- specs/KdsCdcIngestion/TASK5.md
- specs/KdsCdcIngestion/TASK6.md
- specs/KdsCdcIngestion/TASK7.md
- specs/KdsCdcIngestion/TASK8.md
- specs/KdsCdcIngestion/TASK9.md
- specs/KdsCdcReplayExecution/TASK.md
- specs/KdsCdcReplayExecution/TASK1.md
- specs/KdsCdcReplayExecution/TASK2.md
- specs/KdsCdcReplayExecution/TASK3.md
- specs/KdsCdcReplayExecution/TASK4.md
- specs/KdsMonitorServingContractMigration/TASK.md
- specs/KdsMonitorServingContractMigration/TASK1.1.md
- specs/KdsMonitorServingContractMigration/TASK1.2.md
- specs/KdsMonitorServingContractMigration/TASK2.1.md
- specs/KdsMonitorServingContractMigration/TASK2.2.md
- specs/KdsMonitorServingContractMigration/TASK3.1.md
- specs/KdsMonitorServingContractMigration/TASK3.2.md
- specs/RedshiftFoundation/TASK.md
- specs/RedshiftFoundation/TASK1.1.md
- specs/RedshiftFoundation/TASK1.2.md
- specs/RedshiftFoundation/TASK1.3.md
- specs/RedshiftFoundation/TASK1.4.md
- specs/RedshiftFoundation/TASK2.1.md
- specs/RedshiftFoundation/TASK2.2.md
- specs/RedshiftFoundation/TASK3.1.md
- specs/RedshiftFoundation/TASK3.2.md
- specs/RedshiftFoundation/TASK3.3.md
- specs/RedshiftSyntheticDataFeed/TASK.md
- specs/RedshiftSyntheticDataFeed/TASK1.1.md
- specs/RedshiftSyntheticDataFeed/TASK1.2.md
- specs/RedshiftSyntheticDataFeed/TASK1.3.md
- specs/RedshiftSyntheticDataFeed/TASK2.1.md
- specs/RedshiftSyntheticDataFeed/TASK2.2.md
- specs/RedshiftSyntheticDataFeed/TASK3.1.md
- specs/RedshiftSyntheticDataFeed/TASK3.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK1.1.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK1.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK2.1.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK2.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK2.3.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK3.1.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK3.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK4.1.md
TASK 9: Customer Onboarding, Warehouse Provisioning, And Manual Brink ETL Alignment
Summary
Add the missing application-level flow that makes a Brink-enabled customer ETL-ready on the Keycloak branch without changing the existing CLI operational path.
This task connects the already existing pieces that are still separate today:
- backend customer creation and update
- Keycloak-backed membership assignment
- tenant warehouse mapping registration
- Redshift tenant bootstrap
- Brink credential persistence
- manual Brink ETL request alignment with stored customer identity
The goal is small and focused: after this task, admin onboarding in the application should be able to create or update a Brink-enabled customer and leave that customer ready for scheduled or manual Brink ETL, while the current CLI commands remain available as they are.
Dependencies
./TASK1.md- source binding and dispatch./TASK2.md- extract boundary and tenant-aware ETL runtime./TASK5.md- warehouse staging load depends on tenant warehouse mapping./TASK6.md- curated flow depends on tenant warehouse mapping and bootstrap./THN-106-keycloak-connection-data-analysis.md- Keycloak/customer credential storage direction
Files to Modify
1. Customer onboarding orchestration
Modify the admin customer application flow so a Brink-enabled customer can be provisioned for warehouse-backed ETL from the backend application layer.
Likely touchpoints:
backend/Kds.Ai.ApiService/Services/CustomerManagementService.csbackend/Kds.Ai.ApiService/Endpoints/AdminCustomerEndpoints.csbackend/Kds.Ai.ApiService/Services/for a new orchestration service if needed
2. Tenant warehouse naming and provisioning seam
Add or finalize one backend seam that:
- derives the tenant warehouse registration key from tenant identity
- derives the Redshift database name from customer data
- registers the mapping
- triggers bootstrap through the existing warehouse bootstrapper
This task must not redesign the existing CLI commands. CLI stays as-is.
3. Manual Brink ETL request alignment
Modify the manual Brink ETL entry so the request no longer trusts a free-form companyId + tenantId pair.
The backend should resolve customer-backed identity and pass the canonical values into the existing pipeline.
Likely touchpoints:
backend/Kds.Ai.ApiService/Endpoints/BrinkPosEtlEndpoints.csbackend/Kds.Ai.ApiService/Jobs/BrinkPosEtlJobs.cs
Required Behavior
Onboarding rule
When an admin creates or updates a Brink-enabled customer through the application flow, the backend should be able to coordinate:
- customer persistence
- membership assignment when requested
- tenant warehouse mapping registration
- tenant warehouse bootstrap
- Brink credential persistence
This should be one application flow, not a sequence of manual post-steps.
CLI compatibility rule
- the current CLI warehouse commands must remain available
- this task adds a new application onboarding path
- this task does not replace, remove, or redesign the CLI path
Database naming rule
The tenant warehouse database name must be created by backend application logic, not manually supplied by UI callers.
Required direction:
- normalize the customer company/name into a database-safe slug
- append
customer.Idto keep the final database name unique and stable - use a deterministic format such as
<normalized-customer-name>-<customer-id> - keep
customer.TenantId.ToString("D")as the registration key for tenant mapping
The database name and tenant id are related, but they are not the same string.
Manual ETL identity rule
Manual Brink ETL must not rely on the caller submitting an arbitrary companyId + tenantId pair.
This task should change the manual path so backend code resolves the stored customer and derives:
companyId = customer.Id.ToString("D")tenantId = customer.TenantId.ToString("D")
Authorization rule
The manual Brink ETL endpoint must be aligned with the Keycloak-backed admin authorization model used by the rest of the admin operational surface.
Minimum expected behavior:
/etl/brink/runrequires admin authorization
Status visibility rule
Admin customer flows should expose enough status to understand whether Brink ETL provisioning is complete.
Minimum useful state:
- warehouse mapping exists or not
- mapped tenant database
- warehouse mapping active or not
- Brink credential configured/enabled state
Testing
Unit tests
Add unit tests for:
- deterministic tenant warehouse database-name generation from customer data
- onboarding orchestration behavior when warehouse mapping does not exist yet
- onboarding behavior when the mapping already exists
- manual ETL request resolution from stored customer identity
- manual ETL authorization behavior
Integration tests
Add integration coverage that proves at least:
- creating a Brink-enabled customer through the application flow can leave the customer ETL-ready
- the tenant warehouse mapping is registered with the expected tenant id and generated database name
- the bootstrap path is invoked from the application flow
- the manual Brink ETL path resolves canonical identifiers from stored customer data instead of trusting free-form request identity
Acceptance Criteria
- [ ] A Brink-enabled customer can be onboarded through backend application flow without separate manual warehouse setup in the normal case
- [ ] Tenant warehouse mapping registration uses
customer.TenantId.ToString("D")as the mapping key - [ ] Redshift tenant database name is generated by backend code from normalized customer name plus
customer.Id - [ ] Existing CLI warehouse commands remain unchanged and usable
- [ ] Manual Brink ETL no longer relies on a caller-provided free-form
companyId + tenantIdpair - [ ] Manual Brink ETL endpoint is protected by admin authorization
- [ ] Admin flows expose enough provisioning state to diagnose ETL readiness
- [ ] Relevant tests cover onboarding, naming, provisioning, and manual-trigger alignment
Notes
- Keep the implementation scope small. This is not a redesign of the whole ETL pipeline.
- The ETL stage implementations already work with tenant warehouse mapping and customer-backed Brink credentials. The missing piece is orchestration.
- Prefer adding one focused application service over spreading provisioning logic across endpoints and controllers.