Skip to content

Revamp: security patch, Next.js 15 migration, and low-cost AWS deployment via Terraform#151

Open
thasup wants to merge 8 commits into
mainfrom
claude/legacy-microservices-aws-migration-hxmgxx
Open

Revamp: security patch, Next.js 15 migration, and low-cost AWS deployment via Terraform#151
thasup wants to merge 8 commits into
mainfrom
claude/legacy-microservices-aws-migration-hxmgxx

Conversation

@thasup

@thasup thasup commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Full revamp of the 3-years-unmaintained stack so Aurapan can run again — locally on Docker Desktop and on AWS at roughly half the old DigitalOcean cost — with a security audit, patched dependencies, and a one-command Terraform deployment.

💸 AWS deployment (new — infra/terraform/)

~$15/month (vs ~$30 on DO): one t4g.small Graviton EC2 running single-node k3s + Elastic IP + 20 GB encrypted gp3. No EKS control plane ($73/mo), no NAT gateway ($32/mo), no managed load balancer ($16/mo) — ingress-nginx binds 80/443 directly on the node. terraform apply bootstraps k3s, ingress-nginx, cert-manager (Let's Encrypt TLS), all manifests and secrets; you only point your domain's A record at the output IP. No SSH port — access via SSM Session Manager; IMDSv2 required. MongoDB Atlas M0 (free) recommended for durable data, or in-cluster MongoDB at $0. Cost details in infra/terraform/README.md.

🔒 Security audit & dependency patch (docs/SECURITY-AUDIT.md)

npm audit: 0 vulnerabilities in all 5 services and the client. Highlights:

  • jsonwebtoken 8 → 9 (CVE-2022-23529 family), with npm overrides patching the copy nested in @thasup-dev/common
  • express 4.17 → 4.21, mongoose 6.2 → 8.16, express-validator 7, stripe 8 → 18, bull 4.16, swiper prototype-pollution fix (GHSA-hmx5-qpq5-p643), axios 1.x, postcss override
  • Node 16 (EOL) → Node 22 LTS everywhere; multi-stage production images with compiled TS, USER node, no dev toolchain
  • k8s hardening: liveness/readiness probes on new /healthz endpoints, resource limits, non-root securityContext, pinned images (mongo:7, nats-streaming:0.25.6), MongoDB on PersistentVolumeClaims
  • Remaining known risks documented (NATS Streaming EOL — internal-only, JetStream migration recommended as follow-up)

⚛️ Next.js 15 + React 19 App Router migration (full refactor)

  • Every page converted from pages/ to app/ with server components and per-page data fetching — removes the legacy _app.getInitialProps that fetched all products, users and orders on every page view
  • Server-side auth guards via redirect(); per-request fetch helper forwards Host/Cookie to the ingress with cache()-deduped currentUser
  • Abandoned libs replaced: react-stripe-checkout@stripe/react-stripe-js (same /api/payments token contract), react-paypal-button-v2@paypal/react-paypal-js, react-rating-stars-component → local component
  • next build: ✅ 32 dynamic routes, standalone output, /api/healthz for probes

🧰 Local dev & seed

  • skaffold dev on Docker Desktop k8s with per-service dev.Dockerfile hot reload (guide: docs/DEPLOYMENT.md)
  • scripts/seed.mjs: idempotent, seeds an admin + 2 demo customers + 10 realistic products through the real APIs, so product data replicates to the order/payment services via NATS events exactly like production traffic

🤖 CI

  • tests-*: Node 22, npm ci, full suites on PR (payment needs the STRIPE_KEY repo secret)
  • deploy-*: multi-arch (amd64+arm64 for Graviton) buildx pushes; optional zero-SSH rollout to the AWS node via SSM, enabled by setting AWS_REGION/AURAPAN_INSTANCE_ID repo variables
  • Legacy DigitalOcean/doctl and initial-deploy-* workflows removed

⚠️ Notes for the reviewer

  • Backend test suites compile cleanly but were not executed in the authoring sandbox (mongod binary download blocked there) — the tests-* workflows on this PR are the gate. Add the STRIPE_KEY secret for the payment suite.
  • @thasup-dev/common is still on its old pins (you own that package — republishing it with updated deps is the cleanest follow-up; the jwt CVE inside it is already neutralized via overrides).
  • .gitignore previously ignored infra/ — fixed, which is why the Terraform files show up at all.

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv


Generated by Claude Code

claude added 8 commits June 10, 2026 17:20
- README now documents the Next.js 15 client, hardened services, local
  Docker Desktop workflow, seed script, and low-cost AWS/Terraform path
- skaffold.yaml upgraded from v2alpha3 to v4beta11 schema, builds per-service
  dev.Dockerfile images with hot-reload sync, deploys k8s + k8s-local-db +
  k8s-dev manifests

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
…dened k8s manifests, seed script

- infra/terraform: default-VPC + t4g.small EC2 + Elastic IP + SSM-only access,
  k3s with ingress-nginx (hostNetwork) and cert-manager bootstrapped via
  user_data; all app secrets created from Terraform variables; no EKS/NAT/ELB
  fees (~$15/mo total vs ~$30 on DigitalOcean)
- infra/k8s: resource requests/limits, liveness/readiness probes, non-root
  securityContext on all services; nats-streaming 0.17.0 -> 0.25.6; mongo:7
- infra/k8s-local-db: MongoDB split out with 1Gi PVCs (local dev / optional
  in-cluster prod DBs); infra/k8s-aws: TLS ingress + Let's Encrypt issuers
- removed DigitalOcean-specific k8s-prod/issuer manifests
- scripts/seed.mjs: idempotent API-driven seeding (admin + demo users +
  10 products through real endpoints so NATS events replicate data correctly)
- skaffold.yaml: v4 schema, dev Dockerfiles, hot-reload sync
- README: rewritten for the new local + AWS workflows

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
- jsonwebtoken 8 -> 9 (CVE-2022-23529/23539/23540), with npm overrides so the
  copy nested in @thasup-dev/common is patched too
- express 4.17 -> 4.21, mongoose 6.2 -> 8.16, express-validator 6 -> 7,
  cookie-session 2.1, bull 4.16, stripe 8 -> 18, typescript 5.8
- test stack: jest 29, ts-jest 29, supertest 7, mongodb-memory-server 10
- npm audit: 0 vulnerabilities across all services
- GET /healthz endpoint on every service (incl. a minimal HTTP server for the
  expiration worker) for Kubernetes liveness/readiness probes
- production Dockerfiles: multi-stage node:22-alpine, compiled TypeScript
  (no ts-node/nodemon in prod), npm ci --omit=dev, non-root USER node
- new dev.Dockerfile per service for skaffold hot-reload development
- tsconfig: es2022 target, dist/ output, tests excluded from prod build

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
… audit

- tests-*: actions v4, Node 22, npm ci (payment tests get STRIPE_KEY secret)
- deploy-*: buildx multi-arch images (amd64+arm64 for the Graviton node),
  docker/build-push-action, optional SSM-based rollout to the AWS k3s node
  gated on AWS_REGION/AURAPAN_INSTANCE_ID repository variables
- deploy-manifests: DigitalOcean doctl replaced with SSM apply
- removed legacy initial-deploy workflows and trigger-*.txt files
- docs/DEPLOYMENT.md: end-to-end local (Docker Desktop) + AWS guides
- docs/SECURITY-AUDIT.md: full audit record and remaining risks
- .env.example: documented all current variables

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
Layout, home, auth, cart, category pages and shared helpers converted;
product detail, checkout flow, orders and dashboards still being migrated.

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
- all routes converted to app/ with server-side data fetching and auth
  guards (redirect()); legacy pages/ and getInitialProps removed — including
  the global _app fetch-everything-on-every-page performance bug
- per-request server fetch helper forwards Host/Cookie to the ingress;
  currentUser deduped via React cache()
- payments: react-stripe-checkout -> @stripe/react-stripe-js (CardElement
  token flow against the same /api/payments contract); react-paypal-button-v2
  -> @paypal/react-paypal-js
- react-rating-stars-component -> local StarRating component
- swiper 8 -> 12 (prototype-pollution advisory GHSA-hmx5-qpq5-p643),
  axios 1.x, react-share 5, postcss override (GHSA-qx2v-qp2m-jg93)
- npm audit: 0 vulnerabilities
- production Dockerfile: node:22-alpine multi-stage, standalone output,
  non-root, NEXT_PUBLIC_* build args; dev.Dockerfile for skaffold
- GA tracking via next/script + usePathname/useSearchParams

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
Mongoose <7 silently stripped the unknown 'id' path from the filter
(strictQuery default), so the lookup accidentally matched by version alone.
Mongoose 8 keeps the filter, so OrderUpdatedListener could never find the
order. Query by _id as intended.

https://claude.ai/code/session_01WBtAYmdHyGPNvoPRXGY1xv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants