The backend
Environment setup
Clone the starter, install the backend with uv, point your editor at the right interpreter, and fill in the environment file.
By the end of this stage the project runs on your machine. The starter repo is cloned, the backend environment is installed with uv, your editor resolves imports from the right virtual environment, and the .env file carries the four Azure values from the setup stages.
Clone and orient
Start from the main branch. It is deliberately minimal. It holds the brief, the sample corpus, environment templates, and pinned dependencies, and the application code is intentionally absent.
git clone https://github.com/daveebbelaar/e2e-invoice-review.git
cd e2e-invoice-reviewThe repo is a monorepo, one repository holding both halves of the app plus everything around them:
backend/app starts almost empty. Building it up, folder by folder, is the rest of this tutorial.
Install the backend
The backend uses uv for dependency management. One command creates the virtual environment and installs everything:
cd backend
uv syncThe dependencies are already declared in backend/pyproject.toml, pinned to exact versions so your install matches the video:
[project]
name = "invoice-review-backend"
requires-python = ">=3.12"
dependencies = [
"azure-ai-documentintelligence==1.0.2",
"fastapi==0.139.0",
"openai==2.45.0",
"pydantic==2.13.4",
"pydantic-ai-slim[openai]==2.11.0",
"python-stdnum==2.2",
"sqlalchemy==2.0.51",
"uvicorn[standard]==0.51.0",
]
[tool.uv]
add-bounds = "exact"
exclude-newer = "7 days"add-bounds = "exact" pins every future uv add to an exact version, and exclude-newer = "7 days" ignores packages published in the last week, so a freshly broken release cannot slip into your environment.
The interpreter gotcha
In a monorepo your editor opens at the repo root, but the virtual environment lives one level down at backend/.venv. Cursor and VS Code only auto-detect environments in the project root, so imports show as unresolved even though uv sync just worked.
The fix is manual. Open the interpreter picker (Cmd+Shift+P, then "Python: Select Interpreter"), choose "Enter interpreter path", and point it at backend/.venv/bin/python. Dave hits this exact wall in the video, and it is worth knowing the shape of the problem because every monorepo does this to you.
Prove the imports work
A quick throwaway file confirms the environment and the interpreter agree:
import pydantic
print(pydantic.VERSION)
# 2.13.4Run it with uv run python test.py. If the version prints and the editor shows no unresolved import, the environment is wired. The file itself is scaffolding, it does not survive into the finished project. The playground/ folder takes over that experimentation job in the next stage.
Fill in the environment file
Copy the template and fill in the values you collected during the Azure setup stages:
cp .env.example .envAZURE_DOCUMENT_INTELLIGENCE_ENDPOINT=https://your-resource.cognitiveservices.azure.com/
AZURE_DOCUMENT_INTELLIGENCE_KEY=replace-with-your-local-key
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/openai/v1/
AZURE_OPENAI_DEPLOYMENT=gpt-5.6-terra
AZURE_OPENAI_API_KEY=replace-with-your-local-keyThe Document Intelligence pair comes from the Document Intelligence stage, where the CLI commands to fetch endpoint and key are listed. The Azure OpenAI pair comes from the Foundry stage, and the deployment name must match the model deployment you created there.
The .env file stays local
.env is gitignored and never committed. Only .env.example, with placeholders, lives in version control.
Checkpoint
uv synccompletes andbackend/.venvexists- Your editor uses
backend/.venv/bin/pythonand shows no unresolved imports uv run python test.pyprints the Pydantic versionbackend/.envholds all four Azure values plus the deployment name
Document Intelligence
Provision the F0 Document Intelligence resource with the CLI, fetch the endpoint and key, and analyze a first invoice in the Studio.
The extraction service
Wrap Document Intelligence in a service class, run the first real extraction from the playground, and read what actually comes back.