Landing page cookbook implementation (Weeks 1-4): Domain Infrastructure: - Add project_domains table with migration (013_project_domains.sql) - Add ProjectDomain model with domain types (primary_auto, primary_custom, alias) - Add SlugGenerator and ProjectDomainRepository interfaces - Implement postgres adapters for domain and slug management Service Layer: - Add domain CRUD methods to ProjectInfraService - Generate 8-char random slugs for auto-domains - Support custom subdomains during project creation - Add site_live health check to project status - Trigger CI build after template seeding Handler Updates: - Add DomainService interface and adapter pattern - Rewrite domain handlers to use database-backed service - Add proper error handling for duplicate/missing domains CI Integration: - Add TriggerBuild to CIProvider interface - Implement TriggerBuild in Woodpecker adapter - Manually trigger initial build after template seed Cookbook & Scripts: - Add landing-test.sh script for E2E testing - Add release.sh for version releases - Add logs.sh for quick log access Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
58 lines
2.0 KiB
Go
58 lines
2.0 KiB
Go
// Package port defines interfaces (ports) for external dependencies.
|
|
package port
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/orchard9/rdev/internal/domain"
|
|
)
|
|
|
|
// ProjectDomainRepository manages project-domain associations.
|
|
type ProjectDomainRepository interface {
|
|
// Create adds a new domain association for a project.
|
|
// Returns error if domain already exists (unique constraint).
|
|
Create(ctx context.Context, pd *domain.ProjectDomain) error
|
|
|
|
// GetByID retrieves a domain by its ID.
|
|
GetByID(ctx context.Context, id int64) (*domain.ProjectDomain, error)
|
|
|
|
// GetByDomain retrieves a domain by its FQDN.
|
|
// Returns nil, nil if not found.
|
|
GetByDomain(ctx context.Context, fqdn string) (*domain.ProjectDomain, error)
|
|
|
|
// ListByProject returns all domains for a project.
|
|
ListByProject(ctx context.Context, projectID string) ([]*domain.ProjectDomain, error)
|
|
|
|
// GetPrimary returns the primary domain for a project.
|
|
// Prefers primary_custom over primary_auto if both exist.
|
|
GetPrimary(ctx context.Context, projectID string) (*domain.ProjectDomain, error)
|
|
|
|
// Update modifies an existing domain record.
|
|
Update(ctx context.Context, pd *domain.ProjectDomain) error
|
|
|
|
// Delete removes a domain by ID.
|
|
Delete(ctx context.Context, id int64) error
|
|
|
|
// DeleteByDomain removes a domain by FQDN.
|
|
DeleteByDomain(ctx context.Context, fqdn string) error
|
|
|
|
// DeleteByProject removes all domains for a project.
|
|
DeleteByProject(ctx context.Context, projectID string) error
|
|
|
|
// Exists checks if a domain already exists.
|
|
Exists(ctx context.Context, fqdn string) (bool, error)
|
|
|
|
// CountByProject returns the number of domains for a project.
|
|
CountByProject(ctx context.Context, projectID string) (int, error)
|
|
}
|
|
|
|
// SlugGenerator generates unique slugs for projects.
|
|
type SlugGenerator interface {
|
|
// Generate creates a new unique slug.
|
|
// Implementations should retry on collision.
|
|
Generate(ctx context.Context) (string, error)
|
|
|
|
// IsUnique checks if a slug is unique (not in use).
|
|
IsUnique(ctx context.Context, slug string) (bool, error)
|
|
}
|