Guide
How to use this template
This solution is the GFT Tech Office Azure template. To spin up a new prototype, clone it, rebrand it, point the infra at a unique name, and deploy — the deploy also registers the solution on the Solutions Lab Hub. The steps below are the manual runbook (creating the Azure DevOps repo is not automated).
- 1
Create the repository in Azure DevOps
Each solution lives in its own repo under the Tech Office Azure DevOps project, named GftUs.SolutionsLab.<Name>. Create it, seed it from this template, then clone it locally.
- In Azure DevOps (org GFT-SE, project KE-065357-007) → Repos → New repository. Name it GftUs.SolutionsLab.<Name> (Git).
- Bring the template code in: either import this repo as the initial commit, or push the template contents as your first commit.
- Clone your new repo locally and work from there.
git clone https://dev.azure.com/GFT-SE/KE-065357-007/_git/GftUs.SolutionsLab.<Name> cd GftUs.SolutionsLab.<Name> - 2
Rebrand the solution
Everything in the UI (wordmark, page titles, hero copy) reads from one file. Edit it and the whole app renames.
- Edit app/lib/brand.ts — wordmark, name, description, eyebrow, headline.
- Don't hardcode the product name anywhere else; the UI already reads it from brand.ts.
app/lib/brand.ts - 3
Set the infrastructure names
Infra names are parameterised in Terraform. Copy the example tfvars and set a unique service name, database name/user and vanity hostname under azure.techoffice.gftus.com.
- Copy terraform/terraform.tfvars.example to terraform/terraform.tfvars.
- Set service_name (the Container App name), db_name, db_user and app_hostname (a unique subdomain — the parent zone azure.techoffice.gftus.com already exists).
- Set the Hub metadata vars (solution_key, solution_name, solution_summary, solution_team, solution_owner, solution_repo, solution_tags) so the entry reads as your solution. Keep a 'Azure' tag so the Hub groups it under the Azure stack.
cd terraform cp terraform.tfvars.example terraform.tfvars # edit terraform.tfvars - 4
Edit the Terraform state key by hand
Terraform backends can't use variables, so the remote-state key must be changed by hand — once per solution. Pick a unique slug so you don't clash with the template's own state lock or Hub entry.
- In terraform/providers.tf, change the backend key from solutions/solutionslab-template-azure/terraform.tfstate to solutions/<your-slug>/terraform.tfstate.
key = "solutions/<your-slug>/terraform.tfstate" - 5
Implement application-level authentication
There is NO platform sign-in (no EasyAuth). Authentication is the app's job and is mandatory before you expose the deployment — otherwise every visitor is treated as the same user. The single integration point is resolveAuthenticatedEmail() in app/lib/auth.ts.
- Add a login gate (login page + session cookie, a shared passcode, or an in-app identity provider).
- Make resolveAuthenticatedEmail() return the verified signed-in email, and null when there's no session so the app redirects to your login.
- Roles still live in the users table: first sign-in is bootstrapped as admin (or seed SOLUTION_ADMIN_EMAILS).
app/lib/auth.ts - 6
Authenticate the CLIs
A single apply builds the image in the shared ACR, talks to Azure, and publishes the Hub entry to the shared (GCP) registry bucket — so both the Azure CLI and gcloud must be authenticated on the machine running apply.
- az login and az account set --subscription d68eb082-646c-48b8-97fc-7fcb9bd04d38 (the Tech Office subscription).
- gcloud auth application-default login (only needed for the Solutions Lab Hub registration step; the Hub registry lives on GCP).
- No Entra permissions are needed: the image pulls with the shared ACR admin account and Blob uses the storage access key — no managed identity or RBAC role assignments.
- 7
Deploy to Azure Container Apps
A single apply builds the image via az acr build, provisions the database + role on the shared Flexible Server, deploys the Container App into the shared Container Apps environment, and binds the vanity domain with a managed certificate. The shared Database, Network, Registry and ContainerApps stacks must already exist.
- Run terraform init then terraform apply from the terraform/ directory.
- The managed TLS cert for the vanity domain finishes provisioning a few minutes after the DNS records (asuid TXT + CNAME) resolve.
- Prerequisites (one-time, shared): the shared Container Apps environment (GftUs.TechOffice.ContainerApps), the Flexible Server allowing Azure-internal connections ('Allow Azure services'), and the shared ACR admin account enabled (admin_enabled = true).
cd terraform terraform init terraform apply - 8
Confirm the Solution Hub listing
The same apply publishes solutions/<key>/solution.json to the shared Hub registry bucket, so the solution appears on the Solutions Lab Hub automatically. No separate step is needed.
- Open the Solutions Lab Hub and confirm your solution is listed under Azure with the right name, status and tags.
- Re-running apply re-publishes the metadata; bump solution_updated_at (or let it default to the apply date).
- To remove the listing, set register_with_hub = false (or terraform destroy).
- 9
Build your first feature
The Team Backlog is the reference CRUD slice. To model whatever your prototype tracks, copy it end to end and rename.
- Schema: add a table to SCHEMA_SQL (and DROP_SQL) in data/seed-core.ts; seed sample rows in data/seed-data.ts.
- Types → queries.ts (read) → actions.ts (write, each guarded by requireAdmin()) → a route under app/app/<feature>/ + a <Feature>View.tsx.
- Add the page to the nav array in components/Header.tsx.