from __future__ import annotations import hashlib import html import json from pathlib import Path from typing import Any from .model import Requirements, normalize def _bullets(items: list[str], empty: str = "To be confirmed") -> str: return "\n".join(f"- {item}" for item in (items or [empty])) def render_tsd(r: Requirements) -> str: assumptions = r.extra or {"landing_zone": "A governed network, identity, logging, and security baseline is available."} assumptions_md = "\n".join(f"- **{k}:** {json.dumps(v, ensure_ascii=False)}" for k, v in assumptions.items()) return f"""# Technical Solution Design: {r.name} ## 1. Purpose and scope {r.summary or 'Define a secure, observable, and scalable application landing zone for the stated requirements.'} ## 2. Functional requirements {_bullets(r.requirements)} ## 3. Actors and integrations ### Users and consuming systems {_bullets(r.users)} ### External integrations {_bullets(r.integrations)} ## 4. Proposed architecture The application is deployed into a governed landing zone behind an edge entry point and application boundary. Identity, secrets, encryption, monitoring, audit logging, and policy enforcement are platform capabilities. Data stores remain private and are reached through controlled service paths. See `architecture.drawio` for the editable logical view. ### Logical components | Component | Responsibility | Trust zone | |---|---|---| | Edge / API entry | TLS termination, routing, rate limiting | Public boundary | | Application services | Business logic and API processing | Application | | Identity and secrets | Authentication, authorization, key and secret lifecycle | Security | | Data services | Durable application state and backups | Data | | Observability | Metrics, logs, traces, alerting, audit evidence | Operations | ## 5. Security and compliance {_bullets(r.security)} Baseline controls include least-privilege identities, private data services, encryption in transit and at rest, centralized audit logs, secret rotation, vulnerability management, and separation of deployment roles. ## 6. Data design {_bullets(r.data)} Data classification, retention, residency, backup frequency, recovery point objective (RPO), and recovery time objective (RTO) must be confirmed before production approval. ## 7. Availability, resilience, and performance - **Availability target:** {r.availability} - **Deployment model:** {r.deployment} - Use health checks, autoscaling where supported, multi-zone placement for production, tested backups, and defined failure-mode runbooks. ## 8. Network and deployment topology Ingress is restricted to the edge boundary. Application-to-data traffic uses private routes and explicit security policies. Administrative access uses a controlled management path; direct public access to workloads and data stores is prohibited. ## 9. Operations Define dashboards for golden signals, actionable alerts, centralized logs, deployment rollback, patching ownership, incident response, and periodic access reviews. ## 10. Risks and decisions - Confirm workload classification, regulatory obligations, traffic estimates, and non-functional targets. - Select concrete cloud services and sizing after a platform review; this design intentionally remains provider-neutral. - Validate integration authentication, data contracts, and failure/retry behavior with each dependency. ## 11. Assumptions and open items {assumptions_md} """ def _cell(cell_id: str, value: str, style: str, x: int, y: int, w: int, h: int, parent: str = "1") -> str: return f'' def render_drawio(r: Requirements) -> str: title = html.escape(f"{r.name} - Logical Architecture") box = "rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;" boundary = "rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#f5f5f5;strokeColor=#666666;verticalAlign=top;align=left;spacingTop=8;" edge = "rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" cells = [ _cell("public", "Public / consumer boundary", boundary, 20, 20, 900, 500), _cell("application", "Application trust zone", boundary, 260, 100, 420, 330), _cell("data", "Private data zone", boundary, 710, 100, 180, 330), _cell("edge", "Edge / API entry", edge, 55, 220, 160, 60), _cell("identity", "Identity & secrets", box, 300, 135, 170, 60), _cell("service", "Application services", box, 300, 235, 170, 70), _cell("observe", "Metrics / logs / audit", box, 300, 345, 170, 60), _cell("store", "Database / object storage", box, 720, 235, 160, 70), _cell("admin", "Controlled admin path", box, 55, 345, 160, 60), '', '', '', '', ] return f''' ''' + ''.join(cells) + '''''' def generate(requirements: dict[str, Any] | str, output_dir: str | Path) -> dict[str, Any]: r = normalize(requirements) out = Path(output_dir) out.mkdir(parents=True, exist_ok=True) tsd = render_tsd(r) diagram = render_drawio(r) (out / "technical-solution-design.md").write_text(tsd, encoding="utf-8") (out / "architecture.drawio").write_text(diagram, encoding="utf-8") digest = hashlib.sha256((tsd + diagram).encode()).hexdigest() manifest = {"application": r.name, "artifacts": ["technical-solution-design.md", "architecture.drawio"], "sha256": digest} (out / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8") return manifest