"""Projects domain: projects, their Git repositories and per-project credentials.""" from __future__ import annotations from dataclasses import dataclass, field from datetime import datetime from app.domain.base import new_id, utcnow @dataclass(slots=True, kw_only=True) class Project: organization_id: str name: str slug: str description: str = "" created_by_user_id: str | None = None default_branch: str = "main" id: str = field(default_factory=new_id) created_at: datetime = field(default_factory=utcnow) @dataclass(slots=True, kw_only=True) class ProjectGitRepo: """The Git repository attached to a project. Named ``ProjectGitRepo`` rather than ``ProjectRepository`` on purpose: the latter collided with the *infrastructure* repository that manages ``Project`` rows, and the shadowing silently broke every Git endpoint at runtime. """ project_id: str provider: str = "gitea" owner: str = "" repo_name: str = "" clone_url: str = "" web_url: str = "" default_branch: str = "main" id: str = field(default_factory=new_id) created_at: datetime = field(default_factory=utcnow) @property def full_name(self) -> str: return f"{self.owner}/{self.repo_name}" @dataclass(slots=True, kw_only=True) class ProjectGitCredential: """Per-project Git identity. The password is encrypted at rest and never returned to the frontend.""" project_id: str username: str encrypted_password: str id: str = field(default_factory=new_id) created_at: datetime = field(default_factory=utcnow)