Some checks failed
- Add complete hosting module (models, routes, schemas, services, templates, migrations) - Add HostWizard platform to init_production seed (code=hosting, domain=hostwizard.lu) - Fix cms_002 migration down_revision to z_unique_subdomain_domain - Fix prospecting_001 migration to chain after cms_002 (remove branch label) - Add hosting/prospecting version_locations to alembic.ini - Fix admin_services delete endpoint to use proper response model - Add hostwizard.lu to deployment docs (DNS, Caddy, Cloudflare) - Add hosting and prospecting user journey docs to mkdocs nav Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
4.3 KiB
Python
126 lines
4.3 KiB
Python
"""hosting: initial tables for hosted sites and client services
|
|
|
|
Revision ID: hosting_001
|
|
Revises: prospecting_001
|
|
Create Date: 2026-03-03
|
|
"""
|
|
|
|
import sqlalchemy as sa
|
|
|
|
from alembic import op
|
|
|
|
revision = "hosting_001"
|
|
down_revision = "prospecting_001"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
# --- hosted_sites ---
|
|
op.create_table(
|
|
"hosted_sites",
|
|
sa.Column("id", sa.Integer(), primary_key=True, index=True),
|
|
sa.Column(
|
|
"store_id",
|
|
sa.Integer(),
|
|
sa.ForeignKey("stores.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
unique=True,
|
|
),
|
|
sa.Column(
|
|
"prospect_id",
|
|
sa.Integer(),
|
|
sa.ForeignKey("prospects.id", ondelete="SET NULL"),
|
|
nullable=True,
|
|
),
|
|
sa.Column(
|
|
"status",
|
|
sa.String(20),
|
|
nullable=False,
|
|
server_default="draft",
|
|
),
|
|
sa.Column("business_name", sa.String(255), nullable=False),
|
|
sa.Column("contact_name", sa.String(255), nullable=True),
|
|
sa.Column("contact_email", sa.String(255), nullable=True),
|
|
sa.Column("contact_phone", sa.String(50), nullable=True),
|
|
sa.Column("proposal_sent_at", sa.DateTime(), nullable=True),
|
|
sa.Column("proposal_accepted_at", sa.DateTime(), nullable=True),
|
|
sa.Column("went_live_at", sa.DateTime(), nullable=True),
|
|
sa.Column("proposal_notes", sa.Text(), nullable=True),
|
|
sa.Column("live_domain", sa.String(255), nullable=True, unique=True),
|
|
sa.Column("internal_notes", sa.Text(), nullable=True),
|
|
sa.Column(
|
|
"created_at",
|
|
sa.DateTime(),
|
|
server_default=sa.func.now(),
|
|
nullable=False,
|
|
),
|
|
sa.Column(
|
|
"updated_at",
|
|
sa.DateTime(),
|
|
server_default=sa.func.now(),
|
|
nullable=False,
|
|
),
|
|
)
|
|
op.create_index("ix_hosted_sites_status", "hosted_sites", ["status"])
|
|
op.create_index("ix_hosted_sites_prospect_id", "hosted_sites", ["prospect_id"])
|
|
|
|
# --- client_services ---
|
|
op.create_table(
|
|
"client_services",
|
|
sa.Column("id", sa.Integer(), primary_key=True, index=True),
|
|
sa.Column(
|
|
"hosted_site_id",
|
|
sa.Integer(),
|
|
sa.ForeignKey("hosted_sites.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
index=True,
|
|
),
|
|
sa.Column("service_type", sa.String(30), nullable=False),
|
|
sa.Column("name", sa.String(255), nullable=False),
|
|
sa.Column("description", sa.Text(), nullable=True),
|
|
sa.Column(
|
|
"status",
|
|
sa.String(20),
|
|
nullable=False,
|
|
server_default="pending",
|
|
),
|
|
sa.Column("billing_period", sa.String(20), nullable=True),
|
|
sa.Column("price_cents", sa.Integer(), nullable=True),
|
|
sa.Column("currency", sa.String(3), nullable=False, server_default="EUR"),
|
|
sa.Column(
|
|
"addon_product_id",
|
|
sa.Integer(),
|
|
sa.ForeignKey("addon_products.id", ondelete="SET NULL"),
|
|
nullable=True,
|
|
),
|
|
sa.Column("domain_name", sa.String(255), nullable=True),
|
|
sa.Column("registrar", sa.String(100), nullable=True),
|
|
sa.Column("mailbox_count", sa.Integer(), nullable=True),
|
|
sa.Column("expires_at", sa.DateTime(), nullable=True),
|
|
sa.Column("period_start", sa.DateTime(), nullable=True),
|
|
sa.Column("period_end", sa.DateTime(), nullable=True),
|
|
sa.Column("auto_renew", sa.Boolean(), nullable=False, server_default="true"),
|
|
sa.Column("notes", sa.Text(), nullable=True),
|
|
sa.Column(
|
|
"created_at",
|
|
sa.DateTime(),
|
|
server_default=sa.func.now(),
|
|
nullable=False,
|
|
),
|
|
sa.Column(
|
|
"updated_at",
|
|
sa.DateTime(),
|
|
server_default=sa.func.now(),
|
|
nullable=False,
|
|
),
|
|
)
|
|
op.create_index("ix_client_services_service_type", "client_services", ["service_type"])
|
|
op.create_index("ix_client_services_status", "client_services", ["status"])
|
|
op.create_index("ix_client_services_expires_at", "client_services", ["expires_at"])
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_table("client_services")
|
|
op.drop_table("hosted_sites")
|