mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 09:37:45 +00:00
Add ID column to domains table and update repository implementation
Co-authored-by: adlerhurst <27845747+adlerhurst@users.noreply.github.com>
This commit is contained in:
126
DOMAINS_IMPLEMENTATION.md
Normal file
126
DOMAINS_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Unified Domains Table Implementation
|
||||
|
||||
This implementation provides a unified domains table (`zitadel.domains`) that consolidates both organization and instance domains into a single table structure.
|
||||
|
||||
## Architecture
|
||||
|
||||
The implementation follows Zitadel's established patterns:
|
||||
|
||||
### Database Layer
|
||||
- **Migration 61**: Creates the unified domains table with proper constraints
|
||||
- **Table Structure**: Uses nullable `org_id` to distinguish between instance domains (NULL) and organization domains (NOT NULL)
|
||||
- **Soft Deletes**: Implements `deleted_at` for data preservation
|
||||
- **Unique Constraints**: Ensures domain uniqueness within instance/organization scope
|
||||
|
||||
### Domain Layer
|
||||
- **Interfaces**: Clean separation between instance and organization domain operations
|
||||
- **Models**: Unified domain model with optional organization ID
|
||||
|
||||
### Repository Layer
|
||||
- **Implementation**: Single repository handling both instance and organization domains
|
||||
- **Transactions**: Atomic operations for primary domain changes
|
||||
- **Query Building**: Type-safe SQL generation using squirrel
|
||||
|
||||
### Projection Layer
|
||||
- **Event Handling**: Processes both org and instance domain events
|
||||
- **Data Synchronization**: Maintains consistency with event sourcing
|
||||
|
||||
## Event Mapping
|
||||
|
||||
### Organization Domain Events
|
||||
- `org.domain.added` → Creates domain record with org_id
|
||||
- `org.domain.verification.added` → Updates validation_type
|
||||
- `org.domain.verified` → Sets is_verified = true
|
||||
- `org.domain.primary.set` → Manages primary domain flags
|
||||
- `org.domain.removed` → Soft deletes domain
|
||||
- `org.removed` → Soft deletes all org domains
|
||||
|
||||
### Instance Domain Events
|
||||
- `instance.domain.added` → Creates domain record with org_id = NULL, is_verified = true
|
||||
- `instance.domain.primary.set` → Manages primary domain flags
|
||||
- `instance.domain.removed` → Soft deletes domain
|
||||
- `instance.removed` → Soft deletes all instance domains
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Instance Domain Operations
|
||||
```go
|
||||
// Add instance domain (always verified)
|
||||
domain, err := repo.AddInstanceDomain(ctx, "instance-123", "api.example.com")
|
||||
|
||||
// Set primary instance domain
|
||||
err := repo.SetInstanceDomainPrimary(ctx, "instance-123", "api.example.com")
|
||||
|
||||
// Remove instance domain
|
||||
err := repo.RemoveInstanceDomain(ctx, "instance-123", "api.example.com")
|
||||
|
||||
// List instance domains
|
||||
criteria := v2domain.DomainSearchCriteria{
|
||||
InstanceID: &instanceID,
|
||||
}
|
||||
pagination := v2domain.DomainPagination{
|
||||
Limit: 10,
|
||||
SortBy: v2domain.DomainSortFieldDomain,
|
||||
Order: database.SortOrderAsc,
|
||||
}
|
||||
list, err := repo.List(ctx, criteria, pagination)
|
||||
```
|
||||
|
||||
### Organization Domain Operations
|
||||
```go
|
||||
// Add organization domain
|
||||
domain, err := repo.AddOrganizationDomain(ctx, "instance-123", "org-456", "company.com", domain.OrgDomainValidationTypeHTTP)
|
||||
|
||||
// Verify organization domain
|
||||
err := repo.SetOrganizationDomainVerified(ctx, "instance-123", "org-456", "company.com")
|
||||
|
||||
// Set primary organization domain
|
||||
err := repo.SetOrganizationDomainPrimary(ctx, "instance-123", "org-456", "company.com")
|
||||
|
||||
// Find specific domain
|
||||
criteria := v2domain.DomainSearchCriteria{
|
||||
Domain: &domainName,
|
||||
InstanceID: &instanceID,
|
||||
}
|
||||
domain, err := repo.Get(ctx, criteria)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
The implementation includes comprehensive tests:
|
||||
|
||||
### Repository Tests
|
||||
- CRUD operations for both instance and organization domains
|
||||
- Transaction behavior verification
|
||||
- Error handling and edge cases
|
||||
- SQL query parameter validation
|
||||
|
||||
### Projection Tests
|
||||
- Event reduction logic for all supported events
|
||||
- Column and condition verification
|
||||
- Multi-statement handling for primary domain changes
|
||||
- Soft delete behavior
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
This table is designed to work alongside existing tables initially:
|
||||
|
||||
1. **Phase 1** (This PR): Create unified table and maintain via projections
|
||||
2. **Phase 2** (Future): Migrate query logic to use unified table
|
||||
3. **Phase 3** (Future): Deprecate separate org_domains2 and instance_domains tables
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- **Indexing**: The unique constraint provides efficient domain lookups
|
||||
- **Queries**: Nullable org_id allows efficient filtering between domain types
|
||||
- **Pagination**: Supports sorting by created_at, updated_at, and domain name
|
||||
- **Soft Deletes**: WHERE deleted_at IS NULL conditions optimize active domain queries
|
||||
|
||||
## Validation
|
||||
|
||||
The table enforces:
|
||||
- Domain length between 1-255 characters
|
||||
- Non-negative validation_type values
|
||||
- Foreign key integrity to instances and organizations
|
||||
- Unique domain constraints per instance/organization scope
|
||||
- Automatic updated_at timestamp management
|
Reference in New Issue
Block a user