port

package
v1.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 5, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ContentValidationResult

type ContentValidationResult struct {
	Valid                bool
	Errors               []ValidationError
	Warnings             []ValidationWarning
	ExtractedInjectables []*entity.TemplateVersionInjectable // Populated only on successful publish validation
}

ContentValidationResult holds the result of content validation.

func NewValidationResult

func NewValidationResult() *ContentValidationResult

NewValidationResult creates a new validation result.

func (*ContentValidationResult) AddError

func (r *ContentValidationResult) AddError(code, path, message string)

AddError adds a validation error and marks the result as invalid.

func (*ContentValidationResult) AddWarning

func (r *ContentValidationResult) AddWarning(code, path, message string)

AddWarning adds a validation warning (does not affect validity).

func (*ContentValidationResult) AddWarningWithSuggestion

func (r *ContentValidationResult) AddWarningWithSuggestion(code, path, message, suggestion string)

AddWarningWithSuggestion adds a validation warning with a suggestion.

func (*ContentValidationResult) ErrorCount

func (r *ContentValidationResult) ErrorCount() int

ErrorCount returns the number of validation errors.

func (*ContentValidationResult) HasErrors

func (r *ContentValidationResult) HasErrors() bool

HasErrors returns true if there are any validation errors.

func (*ContentValidationResult) HasWarnings

func (r *ContentValidationResult) HasWarnings() bool

HasWarnings returns true if there are any validation warnings.

func (*ContentValidationResult) Merge

Merge combines another validation result into this one.

func (*ContentValidationResult) WarningCount

func (r *ContentValidationResult) WarningCount() int

WarningCount returns the number of validation warnings.

type ContentValidator

type ContentValidator interface {
	// ValidateForDraft performs minimal validation (JSON parseability only).
	// Empty content is considered valid for drafts.
	ValidateForDraft(ctx context.Context, content []byte) *ContentValidationResult

	// ValidateForPublish performs complete business logic validation.
	// This includes:
	// - Document structure validation
	// - Variable/injectable access validation
	// - Conditional expression validation
	ValidateForPublish(ctx context.Context, workspaceID, versionID string, content []byte) *ContentValidationResult
}

ContentValidator defines the content validation interface.

type DocumentTypeFilters

type DocumentTypeFilters struct {
	Search string
	Limit  int
	Offset int
}

DocumentTypeFilters contains optional filters for document type queries.

type DocumentTypeRepository

type DocumentTypeRepository interface {
	// Create creates a new document type.
	Create(ctx context.Context, docType *entity.DocumentType) (string, error)

	// FindByID finds a document type by ID.
	FindByID(ctx context.Context, id string) (*entity.DocumentType, error)

	// FindByCode finds a document type by code within a tenant.
	FindByCode(ctx context.Context, tenantID, code string) (*entity.DocumentType, error)

	// FindByTenant lists all document types for a tenant with pagination.
	FindByTenant(ctx context.Context, tenantID string, filters DocumentTypeFilters) ([]*entity.DocumentType, int64, error)

	// FindByTenantWithTemplateCount lists document types with template usage count.
	FindByTenantWithTemplateCount(ctx context.Context, tenantID string, filters DocumentTypeFilters) ([]*entity.DocumentTypeListItem, int64, error)

	// Update updates a document type (name and description only, code is immutable).
	Update(ctx context.Context, docType *entity.DocumentType) error

	// Delete deletes a document type.
	Delete(ctx context.Context, id string) error

	// ExistsByCode checks if a document type with the given code exists in the tenant.
	ExistsByCode(ctx context.Context, tenantID, code string) (bool, error)

	// ExistsByCodeExcluding checks excluding a specific document type ID.
	ExistsByCodeExcluding(ctx context.Context, tenantID, code, excludeID string) (bool, error)

	// CountTemplatesByType returns the number of templates using this document type.
	CountTemplatesByType(ctx context.Context, documentTypeID string) (int, error)

	// FindTemplatesByType returns templates assigned to this document type.
	FindTemplatesByType(ctx context.Context, documentTypeID string) ([]*entity.DocumentTypeTemplateInfo, error)

	// IsSysTenant checks if the given tenant is the system tenant.
	IsSysTenant(ctx context.Context, tenantID string) (bool, error)

	// FindByTenantWithGlobalFallback lists document types including global (SYS tenant) types.
	// Tenant's own types take priority over global types with the same code.
	FindByTenantWithGlobalFallback(ctx context.Context, tenantID string, filters DocumentTypeFilters) ([]*entity.DocumentType, int64, error)

	// FindByTenantWithTemplateCountAndGlobal lists document types with template count, including global types.
	FindByTenantWithTemplateCountAndGlobal(ctx context.Context, tenantID string, filters DocumentTypeFilters) ([]*entity.DocumentTypeListItem, int64, error)

	// FindByCodeWithGlobalFallback finds a document type by code, checking tenant first then SYS tenant.
	FindByCodeWithGlobalFallback(ctx context.Context, tenantID, code string) (*entity.DocumentType, error)
}

DocumentTypeRepository defines the interface for document type data access.

type FolderRepository

type FolderRepository interface {
	// Create creates a new folder.
	Create(ctx context.Context, folder *entity.Folder) (string, error)

	// FindByID finds a folder by ID.
	FindByID(ctx context.Context, id string) (*entity.Folder, error)

	// FindByIDWithCounts finds a folder by ID including item counts.
	FindByIDWithCounts(ctx context.Context, id string) (*entity.FolderWithCounts, error)

	// FindByWorkspace lists all folders in a workspace.
	FindByWorkspace(ctx context.Context, workspaceID string) ([]*entity.Folder, error)

	// FindByWorkspaceWithCounts lists all folders in a workspace including item counts.
	FindByWorkspaceWithCounts(ctx context.Context, workspaceID string) ([]*entity.FolderWithCounts, error)

	// FindByParent lists all child folders of a parent folder.
	FindByParent(ctx context.Context, workspaceID string, parentID *string) ([]*entity.Folder, error)

	// FindRootFolders lists all root folders in a workspace.
	FindRootFolders(ctx context.Context, workspaceID string) ([]*entity.Folder, error)

	// Update updates a folder.
	Update(ctx context.Context, folder *entity.Folder) error

	// Delete deletes a folder.
	Delete(ctx context.Context, id string) error

	// HasChildren checks if a folder has child folders.
	HasChildren(ctx context.Context, id string) (bool, error)

	// HasTemplates checks if a folder contains templates.
	HasTemplates(ctx context.Context, id string) (bool, error)

	// ExistsByNameAndParent checks if a folder with the same name exists under the same parent.
	ExistsByNameAndParent(ctx context.Context, workspaceID string, parentID *string, name string) (bool, error)

	// ExistsByNameAndParentExcluding checks excluding a specific folder ID.
	ExistsByNameAndParentExcluding(ctx context.Context, workspaceID string, parentID *string, name, excludeID string) (bool, error)
}

FolderRepository defines the interface for folder data access.

type GetInjectablesResult

type GetInjectablesResult struct {
	// Injectables is the list of available injectables for the workspace.
	Injectables []ProviderInjectable

	// Groups contains custom groups defined by the provider (optional).
	// These are merged with YAML-defined groups. Provider groups appear at the end.
	Groups []ProviderGroup
}

GetInjectablesResult contains the list of available injectables and groups.

type GroupConfig

type GroupConfig struct {
	Key   string
	Name  string
	Icon  string
	Order int
}

GroupConfig represents a resolved group with localized name.

type InitFunc

type InitFunc func(ctx context.Context, injCtx *entity.InjectorContext) (any, error)

InitFunc is the global initialization function that runs BEFORE all injectors. The user defines ONE Init function that prepares shared data. The result (user's custom struct) will be available via InjectorContext.InitData().

type InjectableRepository

type InjectableRepository interface {
	// FindByID finds an injectable definition by ID.
	FindByID(ctx context.Context, id string) (*entity.InjectableDefinition, error)

	// FindByWorkspace lists all injectable definitions for a workspace (including global).
	FindByWorkspace(ctx context.Context, workspaceID string) ([]*entity.InjectableDefinition, error)

	// FindGlobal lists all global injectable definitions.
	FindGlobal(ctx context.Context) ([]*entity.InjectableDefinition, error)

	// FindByKey finds an injectable by key within a workspace or globally.
	FindByKey(ctx context.Context, workspaceID *string, key string) (*entity.InjectableDefinition, error)

	// ExistsByKey checks if an injectable with the given key exists.
	ExistsByKey(ctx context.Context, workspaceID *string, key string) (bool, error)

	// ExistsByKeyExcluding checks excluding a specific injectable ID.
	ExistsByKeyExcluding(ctx context.Context, workspaceID *string, key, excludeID string) (bool, error)

	// IsInUse checks if an injectable is used by any template versions.
	IsInUse(ctx context.Context, id string) (bool, error)

	// GetVersionCount returns the number of template versions using this injectable.
	GetVersionCount(ctx context.Context, id string) (int, error)

	// ExistsByKeysForWorkspace returns a set of keys that are accessible to the workspace.
	// It checks both workspace-specific and global injectables.
	ExistsByKeysForWorkspace(ctx context.Context, workspaceID string, keys []string) (map[string]bool, error)
}

InjectableRepository defines the interface for injectable definition data access. Note: Injectables are read-only - they are managed via database migrations/seeds.

type Injector

type Injector interface {
	// Code returns the unique identifier of the injector.
	// It maps with injectors.i18n.yaml to get name and description.
	Code() string

	// Resolve returns the resolution function and the list of dependencies.
	// Dependencies are codes of other injectors that must be executed first.
	Resolve() (ResolveFunc, []string)

	// IsCritical indicates if an error in this injector should stop the process.
	// If false, the error is only logged and processing continues.
	IsCritical() bool

	// Timeout returns the timeout for this injector.
	// If 0, the global default timeout (30s) is used.
	Timeout() time.Duration

	// DataType returns the type of value this injector produces.
	// Used by frontend for display and validation.
	DataType() entity.ValueType

	// DefaultValue returns the default value if resolution fails.
	// Return nil for no default (error will be raised if critical).
	DefaultValue() *entity.InjectableValue

	// Formats returns the format configuration for this injector.
	// Return nil if formatting is not applicable.
	// The system will pass the selected format via InjectorContext.SelectedFormat().
	Formats() *entity.FormatConfig
}

Injector defines the interface that users implement.

type InjectorRegistry

type InjectorRegistry interface {
	// Register registra un inyector en el registry.
	Register(injector Injector) error

	// Get obtiene un inyector por su code.
	Get(code string) (Injector, bool)

	// GetAll retorna todos los inyectores registrados.
	GetAll() []Injector

	// Codes retorna todos los codes de inyectores registrados.
	Codes() []string

	// GetName retorna el nombre traducido del inyector.
	// Si no existe traducción, retorna el code.
	GetName(code, locale string) string

	// GetDescription retorna la descripción traducida del inyector.
	// Si no existe traducción, retorna cadena vacía.
	GetDescription(code, locale string) string

	// GetAllNames retorna todas las traducciones del nombre para un code.
	GetAllNames(code string) map[string]string

	// GetAllDescriptions retorna todas las traducciones de la descripción para un code.
	GetAllDescriptions(code string) map[string]string

	// GetGroup retorna el grupo al que pertenece un inyector.
	// Retorna nil si el inyector no tiene grupo asignado.
	GetGroup(code string) *string

	// GetGroups retorna todos los grupos traducidos al locale especificado.
	GetGroups(locale string) []GroupConfig

	// SetInitFunc registra la función de inicialización GLOBAL.
	// Se ejecuta UNA vez antes de todos los inyectores.
	SetInitFunc(fn InitFunc)

	// GetInitFunc retorna la función de inicialización registrada.
	GetInitFunc() InitFunc
}

InjectorRegistry gestiona el registro de inyectores.

type ListSchemaProvider

type ListSchemaProvider interface {
	// ListSchema returns the default list schema for this list injector.
	ListSchema() entity.ListSchema
}

ListSchemaProvider is an optional interface that list injectors can implement to expose their default configuration at the API level. This allows the frontend to know the symbol and header of a LIST injectable.

type MapperContext

type MapperContext struct {
	ExternalID      string            // external ID of the request
	TemplateID      string            // template ID to use
	TransactionalID string            // transactional ID for traceability
	Operation       string            // operation type
	Headers         map[string]string // HTTP request headers
	RawBody         []byte            // unparsed body
}

MapperContext contains the context for request mapping. The system extracts this information from the request and provides it to the mapper.

type MapperRegistry

type MapperRegistry interface {
	// Set registers the request mapper.
	// Returns error if mapper is nil or already set.
	Set(mapper RequestMapper) error

	// Get returns the registered mapper.
	// Returns false if no mapper is registered.
	Get() (RequestMapper, bool)
}

MapperRegistry manages a single request mapper. Only ONE mapper is allowed; if multiple document types are needed, the user handles routing internally in their mapper implementation.

type PDFRenderer

type PDFRenderer interface {
	// RenderPreview generates a preview PDF with injected values.
	// The document is rendered with all variables replaced by their provided values.
	// Conditional blocks are evaluated based on the injectable values.
	RenderPreview(ctx context.Context, req *RenderPreviewRequest) (*RenderPreviewResult, error)

	// Close releases any resources held by the renderer.
	// This should be called when the renderer is no longer needed.
	Close() error
}

PDFRenderer defines the interface for PDF rendering operations.

type ProviderFormat

type ProviderFormat struct {
	// Key is the format identifier (e.g., "DD/MM/YYYY", "HH:mm:ss").
	// This key is passed back in ResolveInjectablesRequest.SelectedFormats.
	Key string `json:"key" bson:"key"`

	// Label is the display label shown in the format selector.
	// Map of locale → translated label (e.g., {"es": "1.234,56", "en": "1,234.56"}).
	Label map[string]string `json:"label" bson:"label"`
}

ProviderFormat represents a format option for an injectable.

type ProviderGroup

type ProviderGroup struct {
	// Key is the unique group identifier.
	// REQUIRED. Must be unique across YAML-defined groups.
	Key string `json:"key" bson:"key"`

	// Name is the display name shown in the editor.
	// REQUIRED. Map of locale → translated name (e.g., {"es": "Datos", "en": "Data"}).
	Name map[string]string `json:"name" bson:"name"`

	// Icon is the optional icon name (e.g., "calendar", "user", "database").
	Icon string `json:"icon,omitempty" bson:"icon,omitempty"`
}

ProviderGroup represents a custom group for organizing injectables.

type ProviderInjectable

type ProviderInjectable struct {
	// Code is the unique identifier for this injectable.
	// REQUIRED. Must not collide with registry-defined injector codes.
	Code string `json:"code" bson:"code"`

	// Label is the display name shown in the editor.
	// REQUIRED. Map of locale → translated label (e.g., {"es": "Nombre", "en": "Name"}).
	Label map[string]string `json:"label" bson:"label"`

	// Description is optional help text shown in the editor.
	// Map of locale → translated description.
	Description map[string]string `json:"description,omitempty" bson:"description,omitempty"`

	// DataType indicates the type of value this injectable produces.
	// REQUIRED. Use InjectableDataType constants: InjectableDataTypeText,
	// InjectableDataTypeNumber, InjectableDataTypeDate, InjectableDataTypeBoolean,
	// InjectableDataTypeImage, InjectableDataTypeTable, InjectableDataTypeList.
	DataType entity.InjectableDataType `json:"dataType" bson:"dataType"`

	// GroupKey is the key of the group to assign this injectable to (optional).
	// Can reference groups from ProviderGroups or existing YAML-defined groups.
	GroupKey string `json:"groupKey,omitempty" bson:"groupKey,omitempty"`

	// Formats defines available format options for this injectable (optional).
	// If empty, no format selection is shown in the editor.
	Formats []ProviderFormat `json:"formats,omitempty" bson:"formats,omitempty"`
}

ProviderInjectable represents an injectable definition from the provider.

type RenderAuthClaims

type RenderAuthClaims struct {
	UserID   string         // Caller identifier (required for audit/tracing)
	Email    string         // Optional
	Name     string         // Optional
	Provider string         // Auth provider/method name (e.g., "api-key", "custom-jwt")
	Extra    map[string]any // Custom claims accessible via middleware.GetRenderAuthExtra()
}

RenderAuthClaims contains authenticated caller information.

type RenderAuthenticator

type RenderAuthenticator interface {
	// Authenticate validates the request and returns claims on success.
	// Return (nil, error) to reject with 401 Unauthorized.
	Authenticate(c *gin.Context) (*RenderAuthClaims, error)
}

RenderAuthenticator defines custom authentication for render endpoints. When registered via engine.SetRenderAuthenticator(), it replaces OIDC for render routes while panel OIDC continues working for login/UI.

type RenderPreviewRequest

type RenderPreviewRequest struct {
	// Document is the parsed portable document to render.
	Document *portabledoc.Document

	// Injectables contains the values to inject into the document.
	// Keys are variable IDs, values are the actual values.
	Injectables map[string]any

	// InjectableDefaults contains default values for injectables.
	// Keys are variable IDs, values are the default string values.
	// Used as fallback when Injectables doesn't contain a value.
	InjectableDefaults map[string]string
}

RenderPreviewRequest contains the data needed to render a preview PDF.

type RenderPreviewResult

type RenderPreviewResult struct {
	// PDF contains the raw PDF bytes.
	PDF []byte

	// Filename is the suggested filename for the PDF.
	Filename string

	// PageCount is the number of pages in the generated PDF.
	PageCount int
}

RenderPreviewResult contains the result of rendering a preview PDF.

type RequestMapper

type RequestMapper interface {
	// Map parses the raw body and returns the business-specific payload.
	// The system handles building InjectorContext from MapperContext + payload.
	Map(ctx context.Context, mapCtx *MapperContext) (any, error)
}

RequestMapper defines the interface that users implement to map requests. The user only needs to parse RawBody and return the typed payload. If multiple document types are needed, the user handles routing internally. The system handles building InjectorContext from MapperContext + payload.

type ResolveFunc

type ResolveFunc func(ctx context.Context, injCtx *entity.InjectorContext) (*entity.InjectorResult, error)

ResolveFunc is the function that resolves the injector value.

type ResolveInjectablesRequest

type ResolveInjectablesRequest struct {
	// TenantCode is the tenant identifier.
	TenantCode string

	// WorkspaceCode is the workspace identifier.
	WorkspaceCode string

	// TemplateID is the ID of the template being rendered.
	TemplateID string

	// Codes is the list of injectable codes to resolve.
	// Only codes belonging to this provider are included.
	Codes []string

	// SelectedFormats maps injectable codes to their selected format keys.
	// Example: {"my_date": "DD/MM/YYYY", "my_time": "HH:mm"}
	SelectedFormats map[string]string

	// Headers contains HTTP headers from the original request.
	// Useful for extracting auth tokens or other context.
	Headers map[string]string

	// Payload contains the request body data.
	// Type depends on what was sent in the render request.
	Payload any

	// InitData contains shared initialization data from InitFunc.
	// Available if the user registered an InitFunc.
	InitData any
}

ResolveInjectablesRequest contains parameters for resolving injectable values.

type ResolveInjectablesResult

type ResolveInjectablesResult struct {
	// Values maps injectable codes to their resolved values.
	// Use entity.StringValue(), entity.NumberValue(), etc. to create values.
	Values map[string]*entity.InjectableValue

	// Errors maps injectable codes to error messages for non-critical failures.
	// These injectables will use empty/default values and render will continue.
	// For critical failures that should stop the render, return an error from ResolveInjectables instead.
	Errors map[string]string
}

ResolveInjectablesResult contains the resolved values and any non-critical errors.

type SystemInjectableRepository

type SystemInjectableRepository interface {
	// FindActiveKeysForWorkspace returns the keys of system injectables that are active
	// for a given workspace. Respects priority: WORKSPACE > TENANT > PUBLIC.
	// Both the definition and assignment must be active (is_active = true).
	FindActiveKeysForWorkspace(ctx context.Context, workspaceID string) ([]string, error)

	// FindAllDefinitions returns a map of all definition keys to their is_active status.
	FindAllDefinitions(ctx context.Context) (map[string]bool, error)

	// UpsertDefinition creates or updates a system injectable definition.
	// If the key doesn't exist, creates it. If it exists, updates is_active.
	UpsertDefinition(ctx context.Context, key string, isActive bool) error

	// FindAssignmentsByKey returns all assignments for a given injectable key.
	FindAssignmentsByKey(ctx context.Context, key string) ([]*entity.SystemInjectableAssignment, error)

	// CreateAssignment creates a new assignment.
	CreateAssignment(ctx context.Context, assignment *entity.SystemInjectableAssignment) error

	// DeleteAssignment removes an assignment by ID.
	DeleteAssignment(ctx context.Context, id string) error

	// SetAssignmentActive updates the is_active flag for an assignment.
	SetAssignmentActive(ctx context.Context, id string, isActive bool) error

	// FindPublicActiveKeys returns a set of injectable keys that have an active PUBLIC assignment.
	FindPublicActiveKeys(ctx context.Context) (map[string]bool, error)

	// BulkUpsertDefinitions creates or updates definitions for multiple keys with the given is_active status.
	BulkUpsertDefinitions(ctx context.Context, keys []string, isActive bool) error

	// CreateScopedAssignments creates assignments for multiple keys at the given scope.
	// Uses ON CONFLICT DO NOTHING for idempotency. Returns number created.
	CreateScopedAssignments(ctx context.Context, keys []string, scopeType string, tenantID *string, workspaceID *string) (int, error)

	// DeleteScopedAssignments deletes assignments for multiple keys at the given scope.
	// Returns number deleted.
	DeleteScopedAssignments(ctx context.Context, keys []string, scopeType string, tenantID *string, workspaceID *string) (int, error)

	// FindScopedAssignmentsByKeys returns a map of key -> assignmentID for assignments at the given scope.
	FindScopedAssignmentsByKeys(ctx context.Context, keys []string, scopeType string, tenantID *string, workspaceID *string) (map[string]string, error)
}

SystemInjectableRepository defines the interface for system injectable data access. System injectables are code-defined injectors whose availability is controlled via database.

type SystemRoleRepository

type SystemRoleRepository interface {
	// Create creates a new system role assignment.
	Create(ctx context.Context, assignment *entity.SystemRoleAssignment) (string, error)

	// FindByUserID finds a system role assignment by user ID.
	FindByUserID(ctx context.Context, userID string) (*entity.SystemRoleAssignment, error)

	// FindAll lists all system role assignments.
	FindAll(ctx context.Context) ([]*entity.SystemRoleAssignment, error)

	// Delete removes a system role assignment by user ID.
	Delete(ctx context.Context, userID string) error

	// UpdateRole updates a user's system role.
	UpdateRole(ctx context.Context, userID string, role entity.SystemRole) error
}

SystemRoleRepository defines the interface for system role data access.

type TableSchemaProvider

type TableSchemaProvider interface {
	// ColumnSchema returns the column definitions for this table injector.
	ColumnSchema() []entity.TableColumn
}

TableSchemaProvider is an optional interface that table injectors can implement to expose their column structure at the API level. This allows the frontend to know what columns a TABLE injectable will have.

type TagRepository

type TagRepository interface {
	// Create creates a new tag.
	Create(ctx context.Context, tag *entity.Tag) (string, error)

	// FindByID finds a tag by ID.
	FindByID(ctx context.Context, id string) (*entity.Tag, error)

	// FindByWorkspace lists all tags in a workspace.
	FindByWorkspace(ctx context.Context, workspaceID string) ([]*entity.Tag, error)

	// FindByWorkspaceWithCount lists all tags with template counts.
	FindByWorkspaceWithCount(ctx context.Context, workspaceID string) ([]*entity.TagWithCount, error)

	// FindByName finds a tag by name within a workspace.
	FindByName(ctx context.Context, workspaceID, name string) (*entity.Tag, error)

	// Update updates a tag.
	Update(ctx context.Context, tag *entity.Tag) error

	// Delete deletes a tag.
	Delete(ctx context.Context, id string) error

	// ExistsByName checks if a tag with the given name exists in the workspace.
	ExistsByName(ctx context.Context, workspaceID, name string) (bool, error)

	// ExistsByNameExcluding checks excluding a specific tag ID.
	ExistsByNameExcluding(ctx context.Context, workspaceID, name, excludeID string) (bool, error)

	// IsInUse checks if a tag is attached to any templates.
	IsInUse(ctx context.Context, id string) (bool, error)

	// GetTemplateCount returns the number of templates using this tag.
	GetTemplateCount(ctx context.Context, id string) (int, error)
}

TagRepository defines the interface for tag data access.

type TemplateFilters

type TemplateFilters struct {
	FolderID            *string
	RootOnly            bool  // Filter for root folder only (folder_id IS NULL)
	HasPublishedVersion *bool // Filter by whether template has a published version
	TagIDs              []string
	DocumentTypeID      *string // Filter by document type ID
	DocumentTypeCode    string  // Filter by document type code
	Search              string
	Limit               int
	Offset              int
}

TemplateFilters contains optional filters for template queries.

type TemplateRepository

type TemplateRepository interface {
	// Create creates a new template.
	Create(ctx context.Context, template *entity.Template) (string, error)

	// FindByID finds a template by ID.
	FindByID(ctx context.Context, id string) (*entity.Template, error)

	// FindByIDWithDetails finds a template by ID with published version, tags, and folder.
	FindByIDWithDetails(ctx context.Context, id string) (*entity.TemplateWithDetails, error)

	// FindByIDWithAllVersions finds a template by ID with all versions.
	FindByIDWithAllVersions(ctx context.Context, id string) (*entity.TemplateWithAllVersions, error)

	// FindByWorkspace lists all templates in a workspace.
	FindByWorkspace(ctx context.Context, workspaceID string, filters TemplateFilters) ([]*entity.TemplateListItem, error)

	// FindByFolder lists all templates in a folder.
	FindByFolder(ctx context.Context, folderID string) ([]*entity.TemplateListItem, error)

	// FindPublicLibrary lists all public library templates.
	FindPublicLibrary(ctx context.Context, workspaceID string) ([]*entity.TemplateListItem, error)

	// Update updates a template.
	Update(ctx context.Context, template *entity.Template) error

	// Delete deletes a template.
	Delete(ctx context.Context, id string) error

	// ExistsByTitle checks if a template with the given title exists in the workspace.
	ExistsByTitle(ctx context.Context, workspaceID, title string) (bool, error)

	// ExistsByTitleExcluding checks excluding a specific template ID.
	ExistsByTitleExcluding(ctx context.Context, workspaceID, title, excludeID string) (bool, error)

	// CountByFolder returns the number of templates in a folder.
	CountByFolder(ctx context.Context, folderID string) (int, error)

	// FindByDocumentType finds the template assigned to a document type in a workspace.
	// Returns nil if no template is assigned to this type in the workspace.
	FindByDocumentType(ctx context.Context, workspaceID, documentTypeID string) (*entity.Template, error)

	// FindByDocumentTypeCode finds templates by document type code across a tenant.
	FindByDocumentTypeCode(ctx context.Context, tenantID, documentTypeCode string) ([]*entity.TemplateListItem, error)

	// UpdateDocumentType updates the document type assignment for a template.
	UpdateDocumentType(ctx context.Context, templateID string, documentTypeID *string) error
}

TemplateRepository defines the interface for template data access.

type TemplateTagRepository

type TemplateTagRepository interface {
	// AddTag adds a tag to a template.
	AddTag(ctx context.Context, templateID, tagID string) error

	// RemoveTag removes a tag from a template.
	RemoveTag(ctx context.Context, templateID, tagID string) error

	// FindTagsByTemplate lists all tags for a template.
	FindTagsByTemplate(ctx context.Context, templateID string) ([]*entity.Tag, error)

	// FindTemplatesByTag lists all templates with a specific tag.
	FindTemplatesByTag(ctx context.Context, tagID string) ([]string, error)

	// Exists checks if a tag is already linked to a template.
	Exists(ctx context.Context, templateID, tagID string) (bool, error)

	// DeleteByTemplate removes all tag associations for a template.
	DeleteByTemplate(ctx context.Context, templateID string) error
}

TemplateTagRepository defines the interface for template-tag relationship data access.

type TemplateVersionFilters

type TemplateVersionFilters struct {
	Status *entity.VersionStatus
	Limit  int
	Offset int
}

TemplateVersionFilters contains optional filters for version queries.

type TemplateVersionInjectableRepository

type TemplateVersionInjectableRepository interface {
	// Create creates a new template version injectable configuration.
	Create(ctx context.Context, injectable *entity.TemplateVersionInjectable) (string, error)

	// FindByID finds a template version injectable by ID.
	FindByID(ctx context.Context, id string) (*entity.TemplateVersionInjectable, error)

	// FindByVersionID lists all injectables for a template version with their definitions.
	FindByVersionID(ctx context.Context, versionID string) ([]*entity.VersionInjectableWithDefinition, error)

	// Update updates a template version injectable configuration.
	Update(ctx context.Context, injectable *entity.TemplateVersionInjectable) error

	// Delete deletes a template version injectable configuration.
	Delete(ctx context.Context, id string) error

	// DeleteByVersionID deletes all injectable configurations for a template version.
	DeleteByVersionID(ctx context.Context, versionID string) error

	// Exists checks if an injectable definition is already linked to a version.
	Exists(ctx context.Context, versionID, injectableDefID string) (bool, error)

	// ExistsSystemKey checks if a system injectable key is already linked to a version.
	ExistsSystemKey(ctx context.Context, versionID, systemKey string) (bool, error)

	// CopyFromVersion copies all injectable configurations from one version to another.
	CopyFromVersion(ctx context.Context, sourceVersionID, targetVersionID string) error
}

TemplateVersionInjectableRepository defines the interface for template version injectable configuration data access.

type TemplateVersionRepository

type TemplateVersionRepository interface {
	// Create creates a new template version.
	Create(ctx context.Context, version *entity.TemplateVersion) (string, error)

	// FindByID finds a template version by ID.
	FindByID(ctx context.Context, id string) (*entity.TemplateVersion, error)

	// FindByIDWithDetails finds a template version by ID with all related data (injectables).
	FindByIDWithDetails(ctx context.Context, id string) (*entity.TemplateVersionWithDetails, error)

	// FindByTemplateID lists all versions for a template.
	FindByTemplateID(ctx context.Context, templateID string) ([]*entity.TemplateVersion, error)

	// FindByTemplateIDWithDetails lists all versions for a template with full details.
	FindByTemplateIDWithDetails(ctx context.Context, templateID string) ([]*entity.TemplateVersionWithDetails, error)

	// FindPublishedByTemplateID finds the currently published version for a template.
	FindPublishedByTemplateID(ctx context.Context, templateID string) (*entity.TemplateVersion, error)

	// FindPublishedByTemplateIDWithDetails finds the published version with all details.
	FindPublishedByTemplateIDWithDetails(ctx context.Context, templateID string) (*entity.TemplateVersionWithDetails, error)

	// FindScheduledToPublish finds all versions scheduled to publish before the given time.
	FindScheduledToPublish(ctx context.Context, before time.Time) ([]*entity.TemplateVersion, error)

	// FindScheduledToArchive finds all published versions scheduled to archive before the given time.
	FindScheduledToArchive(ctx context.Context, before time.Time) ([]*entity.TemplateVersion, error)

	// Update updates a template version.
	Update(ctx context.Context, version *entity.TemplateVersion) error

	// UpdateStatus updates a version's status with optional user tracking.
	UpdateStatus(ctx context.Context, id string, status entity.VersionStatus, userID *string) error

	// Delete deletes a template version.
	Delete(ctx context.Context, id string) error

	// ExistsByVersionNumber checks if a version number already exists for the template.
	ExistsByVersionNumber(ctx context.Context, templateID string, versionNumber int) (bool, error)

	// ExistsByName checks if a version name already exists for the template.
	ExistsByName(ctx context.Context, templateID, name string) (bool, error)

	// ExistsByNameExcluding checks if a version name exists excluding a specific version ID.
	ExistsByNameExcluding(ctx context.Context, templateID, name, excludeID string) (bool, error)

	// GetNextVersionNumber returns the next available version number for a template.
	GetNextVersionNumber(ctx context.Context, templateID string) (int, error)

	// HasScheduledVersion checks if the template has a version with SCHEDULED status.
	HasScheduledVersion(ctx context.Context, templateID string) (bool, error)

	// ExistsScheduledAtTime checks if another version is scheduled at the exact time for the template.
	ExistsScheduledAtTime(ctx context.Context, templateID string, scheduledAt time.Time, excludeVersionID *string) (bool, error)

	// CountByTemplateID returns the number of versions for a template.
	CountByTemplateID(ctx context.Context, templateID string) (int, error)
}

TemplateVersionRepository defines the interface for template version data access.

type TenantFilters

type TenantFilters struct {
	Limit  int
	Offset int
	UserID string // Used for access-based sorting
	Query  string // Optional search filter for name/code
}

TenantFilters defines filters for paginated tenant listing.

type TenantMemberFilters

type TenantMemberFilters struct {
	Limit  int
	Offset int
	Query  string // Optional search filter for name/code
}

TenantMemberFilters defines filters for paginated tenant member queries.

type TenantMemberRepository

type TenantMemberRepository interface {
	// Create creates a new tenant membership.
	Create(ctx context.Context, member *entity.TenantMember) (string, error)

	// FindByID finds a tenant membership by ID.
	FindByID(ctx context.Context, id string) (*entity.TenantMember, error)

	// FindByUserAndTenant finds a membership for a specific user and tenant.
	FindByUserAndTenant(ctx context.Context, userID, tenantID string) (*entity.TenantMember, error)

	// FindByTenant lists all members of a tenant.
	FindByTenant(ctx context.Context, tenantID string) ([]*entity.TenantMemberWithUser, error)

	// FindByUser lists all tenant memberships for a user.
	FindByUser(ctx context.Context, userID string) ([]*entity.TenantMember, error)

	// FindTenantsWithRoleByUser lists all tenants a user belongs to with their roles.
	FindTenantsWithRoleByUser(ctx context.Context, userID string) ([]*entity.TenantWithRole, error)

	// FindActiveByUserAndTenant finds an active membership.
	FindActiveByUserAndTenant(ctx context.Context, userID, tenantID string) (*entity.TenantMember, error)

	// Delete removes a tenant membership.
	Delete(ctx context.Context, id string) error

	// UpdateRole updates a member's tenant role.
	UpdateRole(ctx context.Context, id string, role entity.TenantRole) error

	// CountByRole counts members with a specific role in a tenant.
	CountByRole(ctx context.Context, tenantID string, role entity.TenantRole) (int, error)

	// FindTenantsWithRoleByUserAndIDs lists tenants by specific IDs that the user belongs to with their roles.
	// Returns tenants in the same order as the provided IDs.
	FindTenantsWithRoleByUserAndIDs(ctx context.Context, userID string, tenantIDs []string) ([]*entity.TenantWithRole, error)

	// FindTenantsWithRoleByUserPaginated lists tenants a user belongs to with pagination and optional search.
	// When filters.Query is provided, orders by similarity. Otherwise, orders by access history.
	FindTenantsWithRoleByUserPaginated(ctx context.Context, userID string, filters TenantMemberFilters) ([]*entity.TenantWithRole, int64, error)
}

TenantMemberRepository defines the interface for tenant membership data access.

type TenantRepository

type TenantRepository interface {
	// Create creates a new tenant.
	Create(ctx context.Context, tenant *entity.Tenant) (string, error)

	// FindByID finds a tenant by ID.
	FindByID(ctx context.Context, id string) (*entity.Tenant, error)

	// FindByCode finds a tenant by code.
	FindByCode(ctx context.Context, code string) (*entity.Tenant, error)

	// FindAll lists all tenants.
	FindAll(ctx context.Context) ([]*entity.Tenant, error)

	// FindAllPaginated lists tenants with pagination and returns total count.
	FindAllPaginated(ctx context.Context, filters TenantFilters) ([]*entity.Tenant, int64, error)

	// SearchByNameOrCode searches tenants by name or code similarity using trigram.
	SearchByNameOrCode(ctx context.Context, query string, limit int) ([]*entity.Tenant, error)

	// Update updates a tenant.
	Update(ctx context.Context, tenant *entity.Tenant) error

	// UpdateStatus updates a tenant's status.
	UpdateStatus(ctx context.Context, id string, status entity.TenantStatus, updatedAt *time.Time) error

	// Delete deletes a tenant.
	Delete(ctx context.Context, id string) error

	// ExistsByCode checks if a tenant with the given code exists.
	ExistsByCode(ctx context.Context, code string) (bool, error)

	// FindSystemTenant finds the system tenant (is_system = true).
	FindSystemTenant(ctx context.Context) (*entity.Tenant, error)
}

TenantRepository defines the interface for tenant data access.

type UserAccessHistoryRepository

type UserAccessHistoryRepository interface {
	// RecordAccess records or updates an access entry using UPSERT semantics.
	// If the entry exists, updates accessed_at. Returns the record ID.
	RecordAccess(ctx context.Context, userID string, entityType entity.AccessEntityType, entityID string) (string, error)

	// GetRecentAccessIDs returns the IDs of recently accessed entities of a given type.
	// Returns up to `limit` entity IDs, ordered by most recent first.
	GetRecentAccessIDs(ctx context.Context, userID string, entityType entity.AccessEntityType, limit int) ([]string, error)

	// GetRecentAccesses returns full access records for a user and entity type.
	GetRecentAccesses(ctx context.Context, userID string, entityType entity.AccessEntityType, limit int) ([]*entity.UserAccessHistory, error)

	// GetAccessTimesForEntities returns the last access time for multiple entities.
	// Returns a map of entityID -> accessedAt. Missing entries mean no access recorded.
	GetAccessTimesForEntities(ctx context.Context, userID string, entityType entity.AccessEntityType, entityIDs []string) (map[string]time.Time, error)

	// DeleteOldAccesses removes entries beyond the most recent N for cleanup.
	// This is called after recording access to maintain the limit.
	DeleteOldAccesses(ctx context.Context, userID string, entityType entity.AccessEntityType, keepCount int) error

	// DeleteByEntity removes all access history for a specific entity.
	// Useful when entity is deleted.
	DeleteByEntity(ctx context.Context, entityType entity.AccessEntityType, entityID string) error

	// RecordTenantAccessIfAllowed records tenant access only if user has membership or system role.
	// Returns ErrForbidden if user has no access to the tenant.
	RecordTenantAccessIfAllowed(ctx context.Context, userID, tenantID string) (string, error)

	// RecordWorkspaceAccessIfAllowed records workspace access only if user has membership or system role.
	// Returns ErrForbidden if user has no access to the workspace.
	RecordWorkspaceAccessIfAllowed(ctx context.Context, userID, workspaceID string) (string, error)
}

UserAccessHistoryRepository defines the interface for user access history data access.

type UserRepository

type UserRepository interface {
	// Create creates a new user.
	Create(ctx context.Context, user *entity.User) (string, error)

	// FindByID finds a user by their internal ID.
	FindByID(ctx context.Context, id string) (*entity.User, error)

	// FindByEmail finds a user by email.
	FindByEmail(ctx context.Context, email string) (*entity.User, error)

	// FindByExternalID finds a user by their external IdP ID.
	FindByExternalID(ctx context.Context, externalID string) (*entity.User, error)

	// Update updates a user's information.
	Update(ctx context.Context, user *entity.User) error
}

UserRepository defines the interface for user data access.

type ValidationError

type ValidationError struct {
	Code    string `json:"code"`
	Path    string `json:"path"`
	Message string `json:"message"`
}

ValidationError represents a validation error.

type ValidationWarning

type ValidationWarning struct {
	Code       string  `json:"code"`
	Path       string  `json:"path"`
	Message    string  `json:"message"`
	Suggestion *string `json:"suggestion,omitempty"`
}

ValidationWarning represents a validation warning (non-blocking).

type WorkspaceFilters

type WorkspaceFilters struct {
	Limit  int
	Offset int
	UserID string // Used for access-based sorting
	Query  string // Optional search filter for name
	Status string // Optional status filter (ACTIVE, SUSPENDED, ARCHIVED)
}

WorkspaceFilters defines filters for paginated workspace listing.

type WorkspaceInjectableProvider

type WorkspaceInjectableProvider interface {
	// GetInjectables returns available injectables for a workspace.
	// Called when editor opens to populate the injectable list.
	// Provider is responsible for i18n - return labels/descriptions already translated for the requested locale.
	// Use injCtx.TenantCode() and injCtx.WorkspaceCode() to identify the workspace.
	GetInjectables(ctx context.Context, injCtx *entity.InjectorContext) (*GetInjectablesResult, error)

	// ResolveInjectables resolves a batch of injectable codes.
	// Called during render for workspace-specific injectables.
	//
	// Error handling:
	//   - Return (nil, error) for CRITICAL failures that should stop the render.
	//   - Return (result, nil) with result.Errors[code] for NON-CRITICAL failures (render continues).
	ResolveInjectables(ctx context.Context, req *ResolveInjectablesRequest) (*ResolveInjectablesResult, error)
}

WorkspaceInjectableProvider defines the interface for dynamic workspace-specific injectables. Implementations are provided by users to supply custom injectables per workspace. The provider handles all i18n internally - returned labels and descriptions should be pre-translated.

type WorkspaceInjectableRepository

type WorkspaceInjectableRepository interface {
	// Create creates a new workspace-owned injectable.
	Create(ctx context.Context, injectable *entity.InjectableDefinition) (string, error)

	// Update updates a workspace-owned injectable.
	Update(ctx context.Context, injectable *entity.InjectableDefinition) error

	// SoftDelete marks an injectable as deleted (is_deleted=true).
	SoftDelete(ctx context.Context, id, workspaceID string) error

	// SetActive sets the is_active flag for an injectable.
	SetActive(ctx context.Context, id, workspaceID string, isActive bool) error

	// FindByID finds an injectable by ID, ensuring it belongs to the workspace and is not deleted.
	FindByID(ctx context.Context, id, workspaceID string) (*entity.InjectableDefinition, error)

	// FindByWorkspaceOwned lists injectables owned by a workspace (excluding deleted).
	FindByWorkspaceOwned(ctx context.Context, workspaceID string) ([]*entity.InjectableDefinition, error)

	// ExistsByKey checks if an injectable with the given key exists for the workspace.
	ExistsByKey(ctx context.Context, workspaceID, key string) (bool, error)

	// ExistsByKeyExcluding checks if an injectable with the given key exists, excluding a specific ID.
	ExistsByKeyExcluding(ctx context.Context, workspaceID, key, excludeID string) (bool, error)
}

WorkspaceInjectableRepository defines the interface for workspace-owned injectable management.

type WorkspaceMemberRepository

type WorkspaceMemberRepository interface {
	// Create creates a new workspace membership.
	Create(ctx context.Context, member *entity.WorkspaceMember) (string, error)

	// FindByID finds a membership by ID.
	FindByID(ctx context.Context, id string) (*entity.WorkspaceMember, error)

	// FindByUserAndWorkspace finds a membership for a specific user and workspace.
	FindByUserAndWorkspace(ctx context.Context, userID, workspaceID string) (*entity.WorkspaceMember, error)

	// FindByWorkspace lists all members of a workspace.
	FindByWorkspace(ctx context.Context, workspaceID string) ([]*entity.MemberWithUser, error)

	// FindByUser lists all workspace memberships for a user.
	FindByUser(ctx context.Context, userID string) ([]*entity.WorkspaceMember, error)

	// FindActiveByUserAndWorkspace finds an active membership.
	FindActiveByUserAndWorkspace(ctx context.Context, userID, workspaceID string) (*entity.WorkspaceMember, error)

	// Update updates a membership.
	Update(ctx context.Context, member *entity.WorkspaceMember) error

	// Delete removes a membership.
	Delete(ctx context.Context, id string) error

	// Activate activates a pending membership.
	Activate(ctx context.Context, id string) error

	// UpdateRole updates a member's role.
	UpdateRole(ctx context.Context, id string, role entity.WorkspaceRole) error
}

WorkspaceMemberRepository defines the interface for workspace membership data access.

type WorkspaceRepository

type WorkspaceRepository interface {
	// Create creates a new workspace.
	Create(ctx context.Context, workspace *entity.Workspace) (string, error)

	// FindByID finds a workspace by ID.
	FindByID(ctx context.Context, id string) (*entity.Workspace, error)

	// FindByTenantPaginated lists workspaces for a tenant with pagination and optional search.
	// When filters.Query is provided, orders by similarity. Otherwise, orders by access history.
	FindByTenantPaginated(ctx context.Context, tenantID string, filters WorkspaceFilters) ([]*entity.Workspace, int64, error)

	// FindByUser lists all workspaces a user has access to.
	FindByUser(ctx context.Context, userID string) ([]*entity.WorkspaceWithRole, error)

	// FindSystemByTenant finds the system workspace for a tenant.
	FindSystemByTenant(ctx context.Context, tenantID *string) (*entity.Workspace, error)

	// Update updates a workspace.
	Update(ctx context.Context, workspace *entity.Workspace) error

	// UpdateStatus updates a workspace's status.
	UpdateStatus(ctx context.Context, id string, status entity.WorkspaceStatus) error

	// Delete deletes a workspace (soft delete by archiving).
	Delete(ctx context.Context, id string) error

	// ExistsSystemForTenant checks if a system workspace exists for a tenant.
	ExistsSystemForTenant(ctx context.Context, tenantID *string) (bool, error)

	// FindByCodeAndTenant finds a workspace by code within a tenant.
	FindByCodeAndTenant(ctx context.Context, tenantID, code string) (*entity.Workspace, error)

	// ExistsByCodeForTenant checks if a workspace code exists for a tenant, optionally excluding a workspace ID.
	ExistsByCodeForTenant(ctx context.Context, tenantID string, code string, excludeID string) (bool, error)
}

WorkspaceRepository defines the interface for workspace data access.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL