first commit

This commit is contained in:
debu-2 2026-10-03 21:14:44 +05:30
commit cce9a8c9ba
73 changed files with 8665 additions and 0 deletions

View file

@ -0,0 +1,81 @@
import ipaddress
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import get_settings
from app.database import get_postgres_session
from app.deps.dns_setup_auth import require_dns_setup_auth
from app.schemas import DnsSetupRequest, DnsSetupResponse
from app.services.domain_provisioning import (
build_deployment_dns_records,
get_domain_by_name,
validate_domain,
)
router = APIRouter(prefix="/dns-setup", tags=["dns-setup"])
def validate_mail_server_ip(value: str) -> str:
candidate = value.strip()
try:
return str(ipaddress.ip_address(candidate))
except ValueError as error:
raise ValueError("Enter a valid IPv4 or IPv6 address.") from error
@router.post("/preview", response_model=DnsSetupResponse)
async def preview_dns_setup(
payload: DnsSetupRequest,
_: None = Depends(require_dns_setup_auth),
session: AsyncSession = Depends(get_postgres_session),
) -> DnsSetupResponse:
settings = get_settings()
try:
domain_name = validate_domain(payload.domain)
mail_server_ip = validate_mail_server_ip(payload.mail_server_ip)
except ValueError as error:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=str(error),
) from error
domain = await get_domain_by_name(session, domain_name)
sections = build_deployment_dns_records(
domain_name=domain_name,
mail_server_ip=mail_server_ip,
dkim_selector=settings.dkim_selector,
dkim_public_key=domain.dkim_public_key if domain else None,
app_public_host=settings.app_public_host,
)
mail_host = f"mail.{domain_name}"
return DnsSetupResponse(
domain=domain_name,
mail_host=mail_host,
app_public_host=settings.app_public_host,
mail_server_ip=mail_server_ip,
is_platform_domain=domain_name == settings.platform_domain,
sections=sections,
notes=_build_notes(
domain_name,
settings.app_public_host,
mail_server_ip,
),
)
def _build_notes(
domain_name: str,
app_public_host: str,
mail_server_ip: str,
) -> list[str]:
return [
"Add these records in Namecheap Advanced DNS for the zone.",
f"Point mail.{domain_name} and {app_public_host} A records to {mail_server_ip}.",
f"Keep the root {domain_name} A record on your main website server if it hosts the marketing site.",
f"Set {domain_name} MX to mail.{domain_name} (priority 10) so inbound mail reaches Postfix on this host.",
"Postfix accepts inbound mail on :25 and delivers outbound mail for the app over the Docker network.",
f"Users open the web UI at https://{app_public_host} (Caddy terminates TLS).",
f"Ask your VPS provider to set reverse DNS (PTR) for {mail_server_ip} → mail.{domain_name}.",
"SPF, DKIM, and DMARC authenticate outbound mail signed by Agmail (selector agmail).",
]