Architecture patterns¶
Design principles and infrastructure patterns that guide how Jersal projects are built and deployed.
Core principles¶
1. Shared infrastructure, independent deployments¶
Shared resources (databases, state backends) live in jersal-projects-core. Each project deploys independently through its own CI/CD pipeline.
graph TB
CORE["jersal-projects-core<br/>(shared infra)"] --> |PostgreSQL, RBAC| P1["Project A"]
CORE --> |PostgreSQL, RBAC| P2["Project B"]
P1 --> |independent deploy| D1["Azure SWA / App Service"]
P2 --> |independent deploy| D2["Azure SWA / App Service"]
Why: Shared infrastructure avoids duplication and cost. Independent deployments prevent one project's release from blocking another.
2. Infrastructure as code¶
All infrastructure is defined in Terraform. No manual Azure portal changes.
Why: Reproducibility, version history, peer review via PRs, and automated provisioning.
3. Secrets never in code¶
- OIDC for CI/CD authentication (no stored Azure credentials)
- Sensitive variables in GitHub Secrets, never committed
.tfvarsfiles gitignored- Future: Azure Key Vault for application secrets
Why: Security. Credentials in code are the most common source of breaches.
4. CI/CD as the deployment mechanism¶
All deployments happen through GitHub Actions on the release branch. Local applies are possible but discouraged.
Why: Consistency, auditability, and reduced risk of drift between environments.
Infrastructure patterns¶
Region strategy¶
| Resource type | Region | Reason |
|---|---|---|
| Compute, databases | swedencentral |
Primary region, EU data residency |
| Static Web Apps | westeurope |
SWA doesn't support swedencentral |
State isolation¶
Each infrastructure concern has its own Terraform state backend:
| State | Storage account | Scope |
|---|---|---|
shared.tfstate |
stjersalprojcore |
PostgreSQL, shared RBAC |
site.tfstate |
stjersalprojcoresite |
Portfolio SWA, site RBAC |
Why: Isolation prevents one terraform apply from accidentally affecting unrelated resources. Blast radius is contained.
Module reuse¶
Common resource patterns are extracted into modules under terraform/modules/:
| Module | What it creates |
|---|---|
resource-group |
Azure Resource Group with tags |
postgres-flex |
PostgreSQL Flexible Server + databases + firewall rules |
rbac |
Role assignments from a list of objects |
swa |
Azure Static Web App |
When to create a module: When a resource pattern appears (or will appear) in more than one environment.
Decision framework¶
When making architecture decisions:
- Document the decision as an ADR
- Prefer boring technology -- well-understood tools over cutting-edge
- Optimize for maintainability -- code is read far more than it's written
- Start simple -- add complexity only when the current approach fails
- Measure before optimizing -- don't solve problems that don't exist yet