diff --git a/.gitignore b/.gitignore index 20f0bd7..5f8b213 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ node_modules/ dist/ .env *.local +.pytest_cache/ +frontend/dist/ +backend/var/ diff --git a/backend/.importlinter b/backend/.importlinter new file mode 100644 index 0000000..2312042 --- /dev/null +++ b/backend/.importlinter @@ -0,0 +1,14 @@ +# Enforces SD-0001 §6.2: the four-layer contract main > domains > platform, with +# imports flowing only downward. The GraphQL `api` layer is deferred (§2), so the +# MVP contract has three layers; `app.api` is added back between main and domains +# when GraphQL arrives. Run from backend/: .venv/bin/lint-imports +[importlinter] +root_package = app + +[importlinter:contract:layers] +name = App layering (main > domains > platform) +type = layers +layers = + app.main + app.domains + app.platform diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/domains/__init__.py b/backend/app/domains/__init__.py new file mode 100644 index 0000000..ed76d05 --- /dev/null +++ b/backend/app/domains/__init__.py @@ -0,0 +1,6 @@ +"""domains layer — bounded contexts (accounts, storefronts). + +Empty in SLICE-1; the accounts domain lands in SLICE-2 and storefronts in SLICE-3. +The package exists now so the layer contract (.importlinter) has a target and later +slices add to a stable seam. Domains import only from app.platform, never upward. +""" diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..987c786 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,5 @@ +"""ecomm backend — FastAPI app factory + the REST BFF. + +Stub in SLICE-1 Task 1 so the top layer of the import-linter contract exists from the +start; the FastAPI factory and /healthz are added in Task 5. +""" diff --git a/backend/app/platform/__init__.py b/backend/app/platform/__init__.py new file mode 100644 index 0000000..11523dd --- /dev/null +++ b/backend/app/platform/__init__.py @@ -0,0 +1,5 @@ +"""platform layer — cross-cutting primitives (config, db, deps). + +The bottom layer: imports nothing from app.domains or app.main. Owns the schema +lifecycle and request wiring, never business rules (SD-0001 §6.2). +""" diff --git a/backend/pytest.ini b/backend/pytest.ini new file mode 100644 index 0000000..0a80e15 --- /dev/null +++ b/backend/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +testpaths = tests +python_files = test_*.py +addopts = -q +# Put backend/ (this rootdir) on sys.path so tests import the `app` package under +# pytest's default prepend import mode (tests/ has no __init__.py). +pythonpath = . diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..ad1b99c --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,7 @@ +fastapi>=0.110 +uvicorn[standard]>=0.29 +httpx>=0.27 +psycopg[binary]>=3.1 +psycopg-pool>=3.2 +pytest>=8.0 +import-linter>=2.0