What this project is start here
metals-simple-deploy is a small, complete application: a Python API backed by a PostgreSQL database, with a browser UI in front of it, all running in Azure. “Complete” means it isn't just application code — it also includes everything needed to package that code into containers, stand up the cloud resources they run on, and deploy changes to both safely and repeatably.
The six parts of this project overview
Each part has a narrow, distinct job, and every one has its own tutorial. The first three are the application itself, the fourth is how it gets packaged, and the last two are two different routes for getting that package running in Azure.
Part 1
The API
A Python web application (built with Flask) that answers requests over the internet — for example, looking up or saving metals-pricing data. It contains the actual business logic of the app: what happens when someone calls a given endpoint, and who's allowed to call it.
Part 2
The Database
A PostgreSQL database that stores the application's data persistently. The API connects to it to read and write records, so the data survives even if the API itself restarts or redeploys.
Part 3
The UI
A framework-free browser app that calls the API. Anyone can view the landing page, but the catalog itself is visible only once logged in, and only accounts with the Admin role can add, edit, or delete anything.
Part 4
Docker
The packaging layer. Three Dockerfiles turn the API, the UI, and this tutorial site into self-contained images holding their code, runtime, and dependencies — and one Compose file runs them all, plus a database, on your machine with a single command.
Part 5
Manual Deployment
Building the whole Azure environment by hand, one az command at a time, with the scripts in utility_scripts/. No preview, no state file — which makes it the clearest way to see exactly which Azure calls a deployment really makes.
Part 6
Automated Deployment — With Terraform
The same environment, declared as code instead of typed: Terraform creates and updates the infrastructure with a preview before every change, and GitHub Actions builds and ships the two container images whenever a pull request is merged.
Running the entire application in development quickstart
All three application pieces — database, API, and UI — start together with one command. Docker Compose builds the images, starts PostgreSQL alongside them, and waits for each service to report healthy before starting the next. No local Python or PostgreSQL installation is needed.
| Step | What it does | Command |
|---|---|---|
| 1 | One-time setup: create the environment file Compose requires | Copy .env.example to .env and set JWT_SECRET_KEY to any long random string |
| 2 | Build the images and start every service | docker compose up -d --build |
| 3 | Confirm everything came up healthy | docker compose ps |
| 4 | When you're done, stop it all (keeping your data) | docker compose down |
How the six parts fit together the big picture
Infrastructure comes first — whether you build it by hand (part 5) or declare it in Terraform (part 6), the result is the same empty, configured Azure environment: the database server, the container registry, and the two web app hosting slots, along with the identities that let them talk to each other. Only once that exists does it make sense to build the Docker images, push them to the registry, and have the web apps pull them. The UI is no longer a folder of files you serve yourself; it's an Nginx container that serves the pages and forwards /api/ requests on to the API, so the browser only ever talks to one address. Change the infrastructure through whichever path you picked, change the application by building a new image — the two move independently, but neither works without the other underneath.