Files
zitadel/backend/v3/domain/instance.go

118 lines
4.4 KiB
Go
Raw Normal View History

feat(backend): state persisted objects (#9870) This PR initiates the rework of Zitadel's backend to state-persisted objects. This change is a step towards a more scalable and maintainable architecture. ## Changes * **New `/backend/v3` package**: A new package structure has been introduced to house the reworked backend logic. This includes: * `domain`: Contains the core business logic, commands, and repository interfaces. * `storage`: Implements the repository interfaces for database interactions with new transactional tables. * `telemetry`: Provides logging and tracing capabilities. * **Transactional Tables**: New database tables have been defined for `instances`, `instance_domains`, `organizations`, and `org_domains`. * **Projections**: New projections have been created to populate the new relational tables from the existing event store, ensuring data consistency during the migration. * **Repositories**: New repositories provide an abstraction layer for accessing and manipulating the data in the new tables. * **Setup**: A new setup step for `TransactionalTables` has been added to manage the database migrations for the new tables. This PR lays the foundation for future work to fully transition to state-persisted objects for these components, which will improve performance and simplify data access patterns. This PR initiates the rework of ZITADEL's backend to state-persisted objects. This is a foundational step towards a new architecture that will improve performance and maintainability. The following objects are migrated from event-sourced aggregates to state-persisted objects: * Instances * incl. Domains * Orgs * incl. Domains The structure of the new backend implementation follows the software architecture defined in this [wiki page](https://github.com/zitadel/zitadel/wiki/Software-Architecturel). This PR includes: * The initial implementation of the new transactional repositories for the objects listed above. * Projections to populate the new relational tables from the existing event store. * Adjustments to the build and test process to accommodate the new backend structure. This is a work in progress and further changes will be made to complete the migration. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Iraq Jaber <iraq+github@zitadel.com> Co-authored-by: Iraq <66622793+kkrime@users.noreply.github.com> Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
2025-09-05 10:54:34 +02:00
package domain
import (
"context"
"time"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/backend/v3/storage/cache"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type Instance struct {
ID string `json:"id,omitempty" db:"id"`
Name string `json:"name,omitempty" db:"name"`
DefaultOrgID string `json:"defaultOrgId,omitempty" db:"default_org_id"`
IAMProjectID string `json:"iamProjectId,omitempty" db:"iam_project_id"`
ConsoleClientID string `json:"consoleClientId,omitempty" db:"console_client_id"`
ConsoleAppID string `json:"consoleAppId,omitempty" db:"console_app_id"`
DefaultLanguage string `json:"defaultLanguage,omitempty" db:"default_language"`
CreatedAt time.Time `json:"createdAt" db:"created_at"`
UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
Domains []*InstanceDomain `json:"domains,omitempty" db:"-"`
}
type instanceCacheIndex uint8
const (
instanceCacheIndexUndefined instanceCacheIndex = iota
instanceCacheIndexID
)
// Keys implements the [cache.Entry].
func (i *Instance) Keys(index instanceCacheIndex) (key []string) {
if index == instanceCacheIndexID {
return []string{i.ID}
}
return nil
}
var _ cache.Entry[instanceCacheIndex, string] = (*Instance)(nil)
// instanceColumns define all the columns of the instance table.
type instanceColumns interface {
// IDColumn returns the column for the id field.
IDColumn() database.Column
// NameColumn returns the column for the name field.
NameColumn() database.Column
// DefaultOrgIDColumn returns the column for the default org id field
DefaultOrgIDColumn() database.Column
// IAMProjectIDColumn returns the column for the default IAM org id field
IAMProjectIDColumn() database.Column
// ConsoleClientIDColumn returns the column for the default IAM org id field
ConsoleClientIDColumn() database.Column
// ConsoleAppIDColumn returns the column for the console client id field
ConsoleAppIDColumn() database.Column
// DefaultLanguageColumn returns the column for the default language field
DefaultLanguageColumn() database.Column
// CreatedAtColumn returns the column for the created at field.
CreatedAtColumn() database.Column
// UpdatedAtColumn returns the column for the updated at field.
UpdatedAtColumn() database.Column
}
// instanceConditions define all the conditions for the instance table.
type instanceConditions interface {
// IDCondition returns an equal filter on the id field.
IDCondition(instanceID string) database.Condition
// NameCondition returns a filter on the name field.
NameCondition(op database.TextOperation, name string) database.Condition
}
// instanceChanges define all the changes for the instance table.
type instanceChanges interface {
// SetName sets the name column.
SetName(name string) database.Change
// SetUpdatedAt sets the updated at column.
SetUpdatedAt(time time.Time) database.Change
// SetIAMProject sets the iam project column.
SetIAMProject(id string) database.Change
// SetDefaultOrg sets the default org column.
SetDefaultOrg(id string) database.Change
// SetDefaultLanguage sets the default language column.
SetDefaultLanguage(language language.Tag) database.Change
// SetConsoleClientID sets the console client id column.
SetConsoleClientID(id string) database.Change
// SetConsoleAppID sets the console app id column.
SetConsoleAppID(id string) database.Change
}
// InstanceRepository is the interface for the instance repository.
type InstanceRepository interface {
instanceColumns
instanceConditions
instanceChanges
// TODO
// Member returns the member repository which is a sub repository of the instance repository.
// Member() MemberRepository
Get(ctx context.Context, opts ...database.QueryOption) (*Instance, error)
List(ctx context.Context, opts ...database.QueryOption) ([]*Instance, error)
Create(ctx context.Context, instance *Instance) error
Update(ctx context.Context, id string, changes ...database.Change) (int64, error)
Delete(ctx context.Context, id string) (int64, error)
// Domains returns the domain sub repository for the instance.
// If shouldLoad is true, the domains will be loaded from the database and written to the [Instance].Domains field.
// If shouldLoad is set to true once, the Domains field will be set even if shouldLoad is false in the future.
Domains(shouldLoad bool) InstanceDomainRepository
}
type CreateInstance struct {
Name string `json:"name"`
}