domain

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 18, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllocatePortOffset

func AllocatePortOffset(envName string) int

AllocatePortOffset computes a deterministic port offset from an environment name using FNV-1a hashing. The offset is in the range [1, maxOffset].

func RenderEnvMap

func RenderEnvMap(envMap map[string]string, ctx *TemplateContext) (map[string]string, error)

RenderEnvMap renders all template variables in a map of env vars.

func RenderTemplate

func RenderTemplate(tmpl string, ctx *TemplateContext) (string, error)

RenderTemplate replaces {{var}} placeholders in a string with values from the context. Supported variable patterns:

  • {{ports.<service>}} — allocated port for a service
  • {{core.databases.<name>.connectionString}} — database connection string
  • {{core.databases.<name>.host}} — database host
  • {{core.databases.<name>.port}} — database port
  • {{core.databases.<name>.user}} — database user
  • {{core.databases.<name>.password}} — database password
  • {{core.databases.<name>.database}} — database name

func ResolveEnvironmentFromCwd

func ResolveEnvironmentFromCwd(cwd string, environments map[string]*EnvironmentEntry) (string, error)

ResolveEnvironmentFromCwd determines the environment name by checking if the current working directory is inside any known worktree path from state.

func TopologicalSort

func TopologicalSort(services map[string]ServiceConfig) ([]string, error)

TopologicalSort performs Kahn's algorithm to produce a topological ordering of services based on their dependsOn relationships. Returns an error if a cycle is detected or a dependency references an unknown service.

func ValidateConfig

func ValidateConfig(cfg *ProjectConfig) error

ValidateConfig performs deep validation of a ProjectConfig. It checks structural correctness, port collisions, dependency references, template variable references, and supported engine types. It does NOT check file system paths — use ValidateConfigWithFS for that.

func ValidateConfigWithFS

func ValidateConfigWithFS(cfg *ProjectConfig, projectRoot string, fileExists func(string) bool) error

ValidateConfigWithFS performs all config validation plus file system checks. projectRoot is the directory containing previewctl.yaml. fileExists is a function that checks if a path exists (allows testing).

Types

type ComputePort

type ComputePort interface {
	// Create sets up compute resources for an environment.
	Create(ctx context.Context, envName string, branch string) (*ComputeResources, error)

	// Start starts per-environment services (infra containers, etc).
	Start(ctx context.Context, envName string, ports PortMap) error

	// Stop stops services without destroying data or resources.
	Stop(ctx context.Context, envName string) error

	// Destroy tears down all compute resources.
	Destroy(ctx context.Context, envName string) error

	// IsRunning checks if environment compute resources are active.
	IsRunning(ctx context.Context, envName string) (bool, error)
}

ComputePort manages the compute substrate for an environment. Local: git worktree + docker compose for per-env infrastructure. Preview: VM provisioning + full compose stack. Sandbox: isolated VM with network policies.

type ComputeResources

type ComputeResources struct {
	WorktreePath string `json:"worktreePath,omitempty"` // local mode
	VMId         string `json:"vmId,omitempty"`         // preview/sandbox mode
	ExternalIP   string `json:"externalIp,omitempty"`   // preview/sandbox mode
}

ComputeResources holds the result of creating compute resources for an environment.

type CoreConfig

type CoreConfig struct {
	Databases map[string]DatabaseConfig `yaml:"databases,omitempty"`
}

CoreConfig holds managed services requiring engine-specific lifecycle.

type DatabaseConfig

type DatabaseConfig struct {
	Engine     string      `yaml:"engine"`
	Image      string      `yaml:"image"`
	Port       int         `yaml:"port"`
	User       string      `yaml:"user"`
	Password   string      `yaml:"password"`
	TemplateDb string      `yaml:"templateDb"`
	Seed       *SeedConfig `yaml:"seed,omitempty"`
}

DatabaseConfig defines a core database.

type DatabaseInfo

type DatabaseInfo struct {
	Host             string `json:"host"`
	Port             int    `json:"port"`
	User             string `json:"user"`
	Password         string `json:"password"`
	Database         string `json:"database"`
	ConnectionString string `json:"connectionString"`
}

DatabaseInfo holds connection details for a database instance.

type DatabasePort

type DatabasePort interface {
	// EnsureInfrastructure ensures the database server is running and reachable.
	EnsureInfrastructure(ctx context.Context) error

	// SeedTemplate populates the template database from a snapshot or migration.
	// snapshotPath is optional; adapters may use config defaults.
	SeedTemplate(ctx context.Context, snapshotPath string) error

	// CreateDatabase creates an isolated database for the given environment.
	CreateDatabase(ctx context.Context, envName string) (*DatabaseInfo, error)

	// DestroyDatabase drops the environment's database.
	DestroyDatabase(ctx context.Context, envName string) error

	// ResetDatabase drops and re-creates the environment's database.
	ResetDatabase(ctx context.Context, envName string) (*DatabaseInfo, error)

	// DatabaseExists checks if the environment's database exists.
	DatabaseExists(ctx context.Context, envName string) (bool, error)
}

DatabasePort manages per-environment database lifecycle. Local: template cloning on shared Postgres. Preview/Sandbox: Neon branching, RDS snapshot, or full pg_dump restore.

type DatabaseRef

type DatabaseRef struct {
	Name     string `json:"name"`
	Provider string `json:"provider"`
}

DatabaseRef is a lightweight reference to a database stored in state.

type EnvPort

type EnvPort interface {
	// Generate writes .env.local files for all services in the environment.
	Generate(ctx context.Context, envName string, workdir string, ports PortMap, databases map[string]*DatabaseInfo) error

	// SymlinkSharedEnvFiles symlinks shared .env files from the main worktree.
	SymlinkSharedEnvFiles(ctx context.Context, workdir string) error

	// Cleanup removes generated env files.
	Cleanup(ctx context.Context, workdir string) error
}

EnvPort generates environment configuration files (.env.local, etc).

type EnvironmentDetail

type EnvironmentDetail struct {
	Entry          *EnvironmentEntry         `json:"entry"`
	InfraRunning   bool                      `json:"infraRunning"`
	DatabaseExists map[string]bool           `json:"databaseExists"`
	SnapshotInfo   map[string]*SnapshotState `json:"snapshotInfo"`
}

EnvironmentDetail is an enriched view with live infrastructure checks.

type EnvironmentEntry

type EnvironmentEntry struct {
	Name      string                 `json:"name"`
	Mode      EnvironmentMode        `json:"mode"`
	Branch    string                 `json:"branch"`
	Status    EnvironmentStatus      `json:"status"`
	CreatedAt time.Time              `json:"createdAt"`
	UpdatedAt time.Time              `json:"updatedAt"`
	Ports     PortMap                `json:"ports"`
	Databases map[string]DatabaseRef `json:"databases"`
	Local     *LocalMeta             `json:"local,omitempty"`
	Remote    *RemoteMeta            `json:"remote,omitempty"`
}

EnvironmentEntry is a tracked environment persisted in state.

type EnvironmentMode

type EnvironmentMode string

EnvironmentMode represents the deployment mode of an environment.

const (
	ModeLocal   EnvironmentMode = "local"
	ModePreview EnvironmentMode = "preview"
	ModeSandbox EnvironmentMode = "sandbox"
)

type EnvironmentStatus

type EnvironmentStatus string

EnvironmentStatus represents the lifecycle status of an environment.

const (
	StatusCreating EnvironmentStatus = "creating"
	StatusRunning  EnvironmentStatus = "running"
	StatusStopped  EnvironmentStatus = "stopped"
	StatusError    EnvironmentStatus = "error"
)

type HookContext

type HookContext struct {
	EnvName      string
	Branch       string
	ProjectName  string
	ProjectRoot  string
	WorktreePath string
	Ports        PortMap
	Databases    map[string]*DatabaseInfo
	Step         string
	Phase        string // "before" or "after"
}

HookContext provides environment variables and working directory for hook execution.

type HookDef

type HookDef struct {
	Run             string `yaml:"run"`
	ContinueOnError bool   `yaml:"continueOnError,omitempty"`
}

HookDef defines a single hook to execute.

type HookRunner

type HookRunner struct {
	// contains filtered or unexported fields
}

HookRunner executes hooks defined in the config.

func NewHookRunner

func NewHookRunner(hooks HooksConfig, progress ProgressReporter) *HookRunner

NewHookRunner creates a new hook runner.

func (*HookRunner) RunAfter

func (r *HookRunner) RunAfter(ctx context.Context, step string, hctx *HookContext) error

RunAfter executes all "after" hooks for the given step.

func (*HookRunner) RunBefore

func (r *HookRunner) RunBefore(ctx context.Context, step string, hctx *HookContext) error

RunBefore executes all "before" hooks for the given step.

type HooksConfig

type HooksConfig map[string]StepHooks

HooksConfig maps step names to their before/after hooks. Step names match the lifecycle steps: allocate_ports, create_compute, ensure_database_<name>, clone_database_<name>, symlink_env, generate_env, start_infra, save_state, load_state, destroy_compute, destroy_database_<name>, cleanup_env, remove_state, reset_database, ensure_infra, seed_template.

Additionally, lifecycle-level hooks can be defined: create, delete, seed, reset — these run before/after the entire operation.

type InfraServiceConfig

type InfraServiceConfig struct {
	Image string `yaml:"image"`
	Port  int    `yaml:"port"`
}

InfraServiceConfig defines a generic docker infrastructure service.

type LocalConfig

type LocalConfig struct {
	Worktree WorktreeConfig `yaml:"worktree"`
	// ComposeFile is the path to the docker compose file for per-env infrastructure,
	// relative to the project root. If empty, no per-env containers are started.
	ComposeFile string `yaml:"composeFile,omitempty"`
}

LocalConfig holds local-mode specific configuration.

type LocalMeta

type LocalMeta struct {
	WorktreePath       string `json:"worktreePath"`
	ComposeProjectName string `json:"composeProjectName"`
}

LocalMeta holds local-mode specific metadata.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager orchestrates environment lifecycle by coordinating all ports. It is the single source of truth — all inbound adapters delegate to it.

func NewManager

func NewManager(deps ManagerDeps) *Manager

NewManager creates a new Manager with the given dependencies.

func (*Manager) Destroy

func (m *Manager) Destroy(ctx context.Context, envName string) error

Destroy tears down an environment and cleans up all resources.

func (*Manager) Init

func (m *Manager) Init(ctx context.Context, envName string, branch string) (*EnvironmentEntry, error)

Init creates a new environment end-to-end.

func (*Manager) List

func (m *Manager) List(ctx context.Context) ([]*EnvironmentEntry, error)

List returns all tracked environments.

func (*Manager) ResetDatabase

func (m *Manager) ResetDatabase(ctx context.Context, envName string, dbName string) error

ResetDatabase resets an environment's database from the template.

func (*Manager) SeedTemplate

func (m *Manager) SeedTemplate(ctx context.Context, dbName string, snapshotPath string) error

SeedTemplate seeds or refreshes a template database.

func (*Manager) Status

func (m *Manager) Status(ctx context.Context, envName string) (*EnvironmentDetail, error)

Status returns detailed status of an environment with live infrastructure checks.

type ManagerDeps

type ManagerDeps struct {
	Databases   map[string]DatabasePort
	Compute     ComputePort
	Networking  NetworkingPort
	EnvGen      EnvPort
	State       StatePort
	Progress    ProgressReporter
	Config      *ProjectConfig
	ProjectRoot string
}

ManagerDeps holds the dependencies for creating a Manager.

type NetworkingPort

type NetworkingPort interface {
	// AllocatePorts returns deterministic port assignments for all services and infrastructure.
	AllocatePorts(envName string) PortMap

	// GetServiceURL returns the URL to reach a named service in the environment.
	GetServiceURL(envName string, service string) (string, error)
}

NetworkingPort handles port allocation and service URL resolution. Local: deterministic offset from base ports. Preview: reverse proxy with subdomain routing (future).

type NoopReporter

type NoopReporter struct{}

NoopReporter is a ProgressReporter that discards all events.

func (NoopReporter) OnStep

func (NoopReporter) OnStep(StepEvent)

type PortMap

type PortMap map[string]int

PortMap maps service names to allocated ports.

func AllocatePorts

func AllocatePorts(envName string, basePorts map[string]int) PortMap

AllocatePorts applies a deterministic offset to all base ports for the given environment name.

type ProgressReporter

type ProgressReporter interface {
	OnStep(event StepEvent)
}

ProgressReporter receives lifecycle step events from the manager. Inbound adapters implement this to render progress (CLI spinners, SSE, etc).

type ProjectConfig

type ProjectConfig struct {
	Version        int                           `yaml:"version"`
	Name           string                        `yaml:"name"`
	PackageManager string                        `yaml:"packageManager,omitempty"`
	Core           CoreConfig                    `yaml:"core"`
	Infrastructure map[string]InfraServiceConfig `yaml:"infrastructure,omitempty"`
	Services       map[string]ServiceConfig      `yaml:"services"`
	Local          *LocalConfig                  `yaml:"local,omitempty"`
	Hooks          HooksConfig                   `yaml:"hooks,omitempty"`
}

ProjectConfig is the top-level previewctl.yaml configuration.

func LoadConfig

func LoadConfig(path string) (*ProjectConfig, error)

LoadConfig reads and parses a previewctl.yaml file.

func ParseConfig

func ParseConfig(data []byte) (*ProjectConfig, error)

ParseConfig parses YAML bytes into a ProjectConfig.

func (*ProjectConfig) AllBasePorts

func (c *ProjectConfig) AllBasePorts() map[string]int

AllBasePorts returns a map of all service and infrastructure names to their base ports.

type ProvisionerPort

type ProvisionerPort interface {
	Provision(ctx context.Context, envName string, spec VMSpec) (*VMInfo, error)
	Deprovision(ctx context.Context, vmID string) error
	Status(ctx context.Context, vmID string) (*VMInfo, error)
}

ProvisionerPort manages VM lifecycle for preview/sandbox modes. Not implemented in POC; exists to validate interface design.

type RemoteMeta

type RemoteMeta struct {
	VMId       string `json:"vmId"`
	ExternalIP string `json:"externalIp"`
}

RemoteMeta holds remote-mode specific metadata (future).

type SeedConfig

type SeedConfig struct {
	Strategy string          `yaml:"strategy"`
	Snapshot *SnapshotConfig `yaml:"snapshot,omitempty"`
	Script   string          `yaml:"script,omitempty"`
}

SeedConfig defines how a database template is seeded.

type ServiceConfig

type ServiceConfig struct {
	Path      string            `yaml:"path"`
	Port      int               `yaml:"port"`
	Command   string            `yaml:"command,omitempty"`
	DependsOn []string          `yaml:"dependsOn,omitempty"`
	Env       map[string]string `yaml:"env,omitempty"`
}

ServiceConfig defines an application service.

type SnapshotConfig

type SnapshotConfig struct {
	Source string `yaml:"source"`
	Bucket string `yaml:"bucket"`
	Prefix string `yaml:"prefix"`
	Region string `yaml:"region"`
}

SnapshotConfig defines S3 snapshot source.

type SnapshotState

type SnapshotState struct {
	LastSeeded    *time.Time `json:"lastSeeded"`
	TemplateReady bool       `json:"templateReady"`
}

SnapshotState tracks the seeding status of a database template.

type SnapshotUpdate

type SnapshotUpdate struct {
	LastSeeded    *time.Time
	TemplateReady *bool
}

SnapshotUpdate holds fields to update on snapshot state.

type State

type State struct {
	Version      int                          `json:"version"`
	Snapshots    map[string]*SnapshotState    `json:"snapshots"`
	Environments map[string]*EnvironmentEntry `json:"environments"`
}

State is the top-level persisted state.

func NewState

func NewState() *State

NewState returns an initialized empty state.

type StatePort

type StatePort interface {
	// Load returns the full state.
	Load(ctx context.Context) (*State, error)

	// Save persists the full state.
	Save(ctx context.Context, state *State) error

	// GetEnvironment returns a single environment entry, or nil if not found.
	GetEnvironment(ctx context.Context, name string) (*EnvironmentEntry, error)

	// SetEnvironment creates or updates an environment entry.
	SetEnvironment(ctx context.Context, name string, entry *EnvironmentEntry) error

	// RemoveEnvironment deletes an environment entry.
	RemoveEnvironment(ctx context.Context, name string) error

	// UpdateSnapshot updates snapshot metadata for a named database.
	UpdateSnapshot(ctx context.Context, dbName string, info *SnapshotUpdate) error
}

StatePort persists previewctl state. File-based for POC; interface accommodates Postgres/etcd later.

type StepEvent

type StepEvent struct {
	Step    string // e.g. "allocate_ports", "create_worktree", "create_database"
	Status  StepStatus
	Message string // human-readable detail
	Error   error  // non-nil when Status == StepFailed
}

StepEvent is emitted by the manager at each lifecycle transition.

type StepHooks

type StepHooks struct {
	Before []HookDef `yaml:"before,omitempty"`
	After  []HookDef `yaml:"after,omitempty"`
}

StepHooks defines before and after hooks for a step.

type StepStatus

type StepStatus string

StepStatus represents the status of a lifecycle step.

const (
	StepStarted   StepStatus = "started"
	StepCompleted StepStatus = "completed"
	StepFailed    StepStatus = "failed"
	StepSkipped   StepStatus = "skipped"
)

type TemplateContext

type TemplateContext struct {
	Ports     PortMap
	Databases map[string]*DatabaseInfo
}

TemplateContext holds the values available for template substitution.

type VMInfo

type VMInfo struct {
	ID         string
	ExternalIP string
	Status     string
}

VMInfo describes a provisioned VM (future).

type VMSpec

type VMSpec struct {
	MachineType string
	DiskSizeGB  int
	Image       string
	Region      string
}

VMSpec defines requirements for provisioning a VM (future).

type ValidationError

type ValidationError struct {
	Errors []string
}

ValidationError collects multiple validation issues.

func (*ValidationError) Error

func (e *ValidationError) Error() string

type WorktreeConfig

type WorktreeConfig struct {
	BasePath string `yaml:"basePath"`
	// SymlinkPatterns are glob patterns for gitignored files to symlink from the
	// main worktree into each new worktree (e.g. ".env" matches .env files recursively).
	// These are typically secret/config files that exist in the main repo but aren't
	// tracked by git. Each pattern is matched recursively across the entire repo.
	SymlinkPatterns []string `yaml:"symlinkPatterns,omitempty"`
}

WorktreeConfig defines worktree settings.

Jump to

Keyboard shortcuts

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