- Add CIPipelineError struct to domain with Type, Message, IsWarning fields - Map Woodpecker Pipeline.Errors to domain.CIPipeline.Errors - Fix migration 013: UUID type for project_id, cast id to text for MD5 - Remove invalid domain data migration (columns don't exist) - Update release.sh with --deploy flag and migration support - Fix test nil pointer: check errors in TestAPIKeyRepository_ProjectIDArrayHandling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
69 lines
3.3 KiB
PL/PgSQL
69 lines
3.3 KiB
PL/PgSQL
-- Add slug to projects and create project_domains table for flexible multi-domain support.
|
|
-- This enables:
|
|
-- 1. Auto-generated random subdomains (e.g., k7m2x9p4.threesix.ai)
|
|
-- 2. Optional custom subdomains (e.g., my-app.threesix.ai)
|
|
-- 3. Multiple alias domains per project (e.g., www.myapp.com, myapp.com)
|
|
-- 4. Clean tracking of all DNS records for resource management
|
|
|
|
-- Add slug column to projects (immutable, auto-generated identifier)
|
|
ALTER TABLE projects ADD COLUMN IF NOT EXISTS
|
|
slug VARCHAR(16);
|
|
|
|
-- Backfill existing projects with slugs derived from their IDs
|
|
-- Uses first 8 chars of MD5 hash for consistent, reproducible slugs
|
|
UPDATE projects
|
|
SET slug = LOWER(SUBSTRING(MD5(id::text), 1, 8))
|
|
WHERE slug IS NULL;
|
|
|
|
-- Make slug NOT NULL and UNIQUE after backfill
|
|
ALTER TABLE projects ALTER COLUMN slug SET NOT NULL;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_slug ON projects(slug);
|
|
|
|
-- Project domains table for flexible multi-domain support
|
|
CREATE TABLE IF NOT EXISTS project_domains (
|
|
id SERIAL PRIMARY KEY,
|
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
domain VARCHAR(255) NOT NULL,
|
|
type VARCHAR(20) NOT NULL CHECK (type IN ('primary_auto', 'primary_custom', 'alias')),
|
|
dns_record_id VARCHAR(64), -- Cloudflare record ID for cleanup
|
|
dns_record_type VARCHAR(10), -- A, CNAME, etc.
|
|
verified BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
CONSTRAINT unique_domain UNIQUE (domain)
|
|
);
|
|
|
|
-- Indexes for common queries
|
|
CREATE INDEX IF NOT EXISTS idx_project_domains_project_id ON project_domains(project_id);
|
|
CREATE INDEX IF NOT EXISTS idx_project_domains_type ON project_domains(type);
|
|
|
|
-- Note: Migration of existing domain data was removed as projects table
|
|
-- does not have domain/custom_domain columns. Domains are created via API
|
|
-- when deploying projects with auto-generated slugs.
|
|
|
|
-- Update trigger for project_domains updated_at
|
|
CREATE OR REPLACE FUNCTION update_project_domains_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS project_domains_updated_at ON project_domains;
|
|
CREATE TRIGGER project_domains_updated_at
|
|
BEFORE UPDATE ON project_domains
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_project_domains_updated_at();
|
|
|
|
-- Comments
|
|
COMMENT ON TABLE project_domains IS 'Domains associated with projects - supports multiple domains per project';
|
|
COMMENT ON COLUMN project_domains.project_id IS 'Reference to parent project';
|
|
COMMENT ON COLUMN project_domains.domain IS 'Fully qualified domain name (e.g., k7m2x9p4.threesix.ai or www.myapp.com)';
|
|
COMMENT ON COLUMN project_domains.type IS 'Domain type: primary_auto (system-generated), primary_custom (user subdomain), alias (external domain)';
|
|
COMMENT ON COLUMN project_domains.dns_record_id IS 'Cloudflare DNS record ID for automated cleanup';
|
|
COMMENT ON COLUMN project_domains.dns_record_type IS 'DNS record type: A, CNAME, etc.';
|
|
COMMENT ON COLUMN project_domains.verified IS 'Whether domain ownership has been verified (for external domains)';
|
|
COMMENT ON COLUMN projects.slug IS 'Immutable 8-char random identifier used for auto-generated subdomain';
|