Architecture Overview¶
This document explains the application architecture, how data flows end‑to‑end, and how the system is deployed to Azure Kubernetes Service (AKS) using GitOps.
Application Stack¶
- Next.js (App Router)
- Server Components with selective Client Components ("use client")
- API routes only where required (e.g., auth, health); all business logic goes through tRPC
- TypeScript
- tRPC
- Routers in
src/server/api/routers - Aggregated in
src/server/api/root.ts - Client created in
src/app/providers.tsxviahttpBatchLinkandsuperjson - Drizzle ORM + PostgreSQL
- Schema:
src/server/db/schema.ts - Client:
src/server/db.ts - NextAuth.js (Credentials)
- Route:
src/app/api/auth/[...nextauth]/route.ts - Options:
src/server/auth.tswith JWT strategy and role on session - Tailwind CSS
- Config:
tailwind.config.ts
Data Model (Drizzle)¶
User— id, email, name, role,passwordHashPost— title, slug, content, excerpt, published,publishedAt,seo*fieldsTagandPostTag— tagging relationshipComponentDemo— example code/demos
Request Flow¶
- UI (Next.js) calls tRPC hooks (client) created in
src/app/providers.tsx. - Requests hit the Next.js serverless functions (or Node runtime) and invoke tRPC routers.
- Routers use Drizzle via
src/server/db.ts. - Responses go back through superjson to the client.
Security & Auth¶
- NextAuth Credentials provider validates against
User.passwordHash(bcrypt). - Session JWT enriched with
rolefor admin‑only routes/mutations. - Admin UI under
src/app/admin/*uses protected procedures in tRPC.
Kubernetes (AKS)¶
Manifests live under k8s/apps/portfolio:
- Deployment:
base/deployment.yaml - App container runs on port 3000 (health endpoint
/api/health) - ServiceAccount: Workload Identity enabled (
portfolio-workload-identity) - Env from ConfigMap/Secrets (
portfolio-config,portfolio-secrets,portfolio-db-secret) - Service:
base/service.yaml(ClusterIP) - Istio Gateway + VirtualService:
base/istio-gateway.yaml,base/istio-virtualservice.yaml - Static IP configuration
- TLS certificate management
- NetworkPolicy:
base/networkpolicy.yaml - Database configuration via Azure Database for PostgreSQL
- Admin utility job:
base/admin-password-reset-job.yaml
Environment overlays in k8s/apps/portfolio/overlays/* adjust namespace, DNS, and any env‑specific values.
Database Connectivity¶
- The app connects to Azure Database for PostgreSQL
- Connection string is supplied via Secret (
portfolio-db-secret) - Workload Identity provides Azure AD authentication without secrets
Ingress¶
- Client traffic terminates at the Istio IngressGateway (Azure Load Balancer)
VirtualServiceroutes HTTP(S) to theServiceon port 80 → container 3000- TLS is managed by cert-manager or Azure Front Door
CI/CD & GitOps¶
- Build: GitHub Actions build/push image to Azure Container Registry (
docker.yml) - CI: Lint/tests/quality checks in
ci.yml - GitOps: Flux CD (
k8s/flux-system/*) watches the registry and updates image tags viaImageRepository+ImagePolicy+ImageUpdateAutomation - Kustomizations per environment reconcile manifests into the cluster
References:
AZURE_CI_CD_SETUP.md— Complete Azure CI/CD setup guideFLUX_CD_MIGRATION.md— GitOps image automationAUTOMATIC_DEPLOYMENT_SETUP.md— branch → environment deploymentsPODS_IMAGE_POLICY.md— security and policy notes
Local Development¶
- Use
pnpmonly (see AGENTS.md). - Commands:
pnpm db:generate,pnpm db:migratepnpm devpnpm lintbefore commits
Notes¶
- App Router code can run on the server — guard any
windowusage. - Avoid Node‑only APIs on the request path (fs, net) to stay serverless‑friendly.
- Large uploads should use GCS and stream; do not buffer in memory.