#!/usr/bin/env python3 """프레임워크 중립 최소 스타터 — Python 표준 라이브러리만(의존성 0). 배포 계약만 보여준다: · PORT 환경변수로 리슨(기본 8080) · GET /healthz → 200 {"ok": true} (매니페스트 health 경로) · GET / → 앱 정보 + 바인딩된 소스의 _URL '키'만(값은 노출 안 함) 새 프로젝트는 이 파일을 원하는 스택으로 교체하되, 위 3가지 계약만 지키면 된다. """ import http.server import json import os import socketserver PORT = int(os.environ.get("PORT", "8080")) def bound_source_keys() -> list[str]: """바인딩된 데이터 소스가 주입한 _URL 키만(값 미노출) — 무엇이 연결됐는지 확인용.""" return sorted( k for k, v in os.environ.items() if k.endswith("_URL") and isinstance(v, str) and "://" in v ) class Handler(http.server.BaseHTTPRequestHandler): def _send(self, code: int, obj: dict) -> None: body = json.dumps(obj, ensure_ascii=False).encode() self.send_response(code) self.send_header("content-type", "application/json; charset=utf-8") self.send_header("content-length", str(len(body))) self.end_headers() self.wfile.write(body) def do_GET(self) -> None: # noqa: N802 path = self.path.split("?", 1)[0].rstrip("/") or "/" if path in ("/healthz", "/health"): self._send(200, {"ok": True}) return self._send(200, { "app": os.environ.get("APP_NAME", "yakcloud-starter"), "host": os.environ.get("HOSTNAME", "?"), "bound_sources": bound_source_keys(), # 연결된 소스 _URL 키(값 미노출) "path": self.path, }) def log_message(self, *_args) -> None: # 로그 조용히 return if __name__ == "__main__": socketserver.ThreadingTCPServer.allow_reuse_address = True with socketserver.ThreadingTCPServer(("", PORT), Handler) as httpd: print(f"yakcloud-starter listening on :{PORT}", flush=True) httpd.serve_forever()