diff --git a/apps/cloud-api/cloud_api/__init__.py b/apps/cloud-api/cloud_api/__init__.py new file mode 100644 index 0000000..34d376b --- /dev/null +++ b/apps/cloud-api/cloud_api/__init__.py @@ -0,0 +1,3 @@ +from cloud_api.app import create_app + +__all__ = ["create_app"] diff --git a/apps/cloud-api/cloud_api/app.py b/apps/cloud-api/cloud_api/app.py new file mode 100644 index 0000000..bc24738 --- /dev/null +++ b/apps/cloud-api/cloud_api/app.py @@ -0,0 +1,8 @@ +from __future__ import annotations + +from fastapi import FastAPI + + +def create_app() -> FastAPI: + """Create the independently deployable cloud API application.""" + return FastAPI(title="Device Cloud API") diff --git a/apps/cloud-api/cloud_api/cli.py b/apps/cloud-api/cloud_api/cli.py new file mode 100644 index 0000000..031cc64 --- /dev/null +++ b/apps/cloud-api/cloud_api/cli.py @@ -0,0 +1,20 @@ +from __future__ import annotations + +import argparse +from collections.abc import Sequence + + +def main(argv: Sequence[str] | None = None) -> None: + parser = argparse.ArgumentParser(description="Run the Device Cloud API") + parser.add_argument("--host", default="127.0.0.1") + parser.add_argument("--port", default=8001, type=int) + args = parser.parse_args(argv) + + import uvicorn + + uvicorn.run( + "cloud_api.app:create_app", + factory=True, + host=args.host, + port=args.port, + ) diff --git a/apps/cloud-api/pyproject.toml b/apps/cloud-api/pyproject.toml new file mode 100644 index 0000000..859debc --- /dev/null +++ b/apps/cloud-api/pyproject.toml @@ -0,0 +1,24 @@ +[project] +name = "device-cloud-api" +version = "0.1.0" +description = "Deployable Cloud Control Plane API for Device Agent Runtime." +requires-python = ">=3.14" +dependencies = [ + "device-cloud-platform==0.1.0", + "fastapi>=0.115.0", + "uvicorn[standard]>=0.30.0", +] + +[project.scripts] +device-cloud-api = "cloud_api.cli:main" + +[build-system] +requires = ["setuptools>=69"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["."] +include = ["cloud_api*"] + +[tool.uv.sources] +device-cloud-platform = { workspace = true } diff --git a/apps/cloud-api/tests/test_app.py b/apps/cloud-api/tests/test_app.py new file mode 100644 index 0000000..0f8f3de --- /dev/null +++ b/apps/cloud-api/tests/test_app.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from cloud_api.app import create_app + + +def test_create_app_returns_independent_cloud_application() -> None: + app = create_app() + + assert app.title == "Device Cloud API" + assert callable(create_app) diff --git a/openspec/changes/cloud-control-plane-integration/tasks.md b/openspec/changes/cloud-control-plane-integration/tasks.md index 21eec41..3f8dbf0 100644 --- a/openspec/changes/cloud-control-plane-integration/tasks.md +++ b/openspec/changes/cloud-control-plane-integration/tasks.md @@ -2,7 +2,7 @@ - [x] 1.1 Complete and verify every task in `uv-workspace-packaging` before changing cloud behavior. - Verified 17/17 tasks complete, strict OpenSpec validation passed, and the shared lockfile is current. -- [ ] 1.2 Add `apps/cloud-api` as the `device-cloud-api` workspace project with an app factory and CLI/server entry point. +- [x] 1.2 Add `apps/cloud-api` as the `device-cloud-api` workspace project with an app factory and CLI/server entry point. - [ ] 1.3 Add `apps/device-host-agent` as the `device-host-agent` workspace project with a CLI entry point and explicit Runtime/cloud dependencies. - [ ] 1.4 Add configuration models that validate environment, database URL, scheduler intervals, lease durations, retry limits, poll settings, host identity, and insecure-development overrides. diff --git a/pyproject.toml b/pyproject.toml index a96b2c7..9a461b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,10 @@ dev = [ ] [tool.uv.workspace] -members = ["packages/cloud-platform"] +members = [ + "apps/cloud-api", + "packages/cloud-platform", +] [tool.setuptools.packages.find] include = [ diff --git a/uv.lock b/uv.lock index afb734a..9357b2d 100644 --- a/uv.lock +++ b/uv.lock @@ -12,6 +12,7 @@ resolution-markers = [ [manifest] members = [ "device-agent-runtime", + "device-cloud-api", "device-cloud-platform", ] @@ -462,6 +463,23 @@ requires-dist = [ [package.metadata.requires-dev] dev = [{ name = "pytest", specifier = ">=8.3.0" }] +[[package]] +name = "device-cloud-api" +version = "0.1.0" +source = { editable = "apps/cloud-api" } +dependencies = [ + { name = "device-cloud-platform" }, + { name = "fastapi" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[package.metadata] +requires-dist = [ + { name = "device-cloud-platform", editable = "packages/cloud-platform" }, + { name = "fastapi", specifier = ">=0.115.0" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.30.0" }, +] + [[package]] name = "device-cloud-platform" version = "0.1.0"