"""The application profile of an organization's single app (filled by the wizard).""" from __future__ import annotations from dataclasses import dataclass from typing import Any APP_TYPES = ("web_app", "api", "static_site", "bot", "worker", "other") GIT_SOURCES = ("platform", "external") @dataclass(slots=True, frozen=True, kw_only=True) class AppProfile: """Everything the engine, the sandbox and CI/CD need to build and run the app. Secrets never live here: external git credentials and deploy targets have their own encrypted tables. """ project_id: str app_type: str | None = None language: str | None = None framework: str | None = None runtime_version: str | None = None package_manager: str | None = None setup_command: str | None = None build_command: str | None = None test_command: str | None = None start_command: str | None = None app_port: int | None = None healthcheck_path: str = "/" git_source: str = "platform" external_repo_url: str | None = None default_branch: str = "main" wizard_completed: bool = False @classmethod def from_row(cls, row: Any) -> AppProfile: """Build from a ``ProjectRow`` (duck-typed so the domain stays ORM-free).""" return cls( project_id=row.id, app_type=row.app_type, language=row.language, framework=row.framework, runtime_version=row.runtime_version, package_manager=row.package_manager, setup_command=row.setup_command, build_command=row.build_command, test_command=row.test_command, start_command=row.start_command, app_port=row.app_port, healthcheck_path=row.healthcheck_path or "/", git_source=row.git_source or "platform", external_repo_url=row.external_repo_url, default_branch=row.default_branch or "main", wizard_completed=row.wizard_completed_at is not None, )