amaingot moves Mike's whole stack onto AWS

The fork has quietly re-platformed off Cloudflare and Supabase onto Amazon's cloud, and a routine housekeeping pull request accidentally put the whole rebuild on display.

infrastructure

amaingot's fork no longer runs on the hosting and database services Mike ships with by default. The frontend, backend, and storage layer have all been rebuilt to run on AWS, Amazon's mainstream cloud - the same infrastructure most large firms and vendors already trust and know how to procure.

The rebuild surfaced by accident. amaingot opened a pull request to the main Mike project that was described as a small change - adding automated quality checks so bad code gets caught before it lands. But because the change came from this already-re-platformed fork, the request dragged the entire AWS rebuild along with it. It was closed within about a minute without being merged, so none of it reached the main project. The re-platform and the new checks both stay in amaingot's fork.

So what Worth a look for anyone weighing whether a Mike deployment could live on the cloud infrastructure their organisation already runs on.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from amaingot/mike-aws, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
2dc27676 Re-platform from Cloudflare/Supabase to AWS Alex Maingot 2026-05-14 ↗ GitHub
commit body
Auth: Supabase Auth → AWS Cognito. Frontend uses amazon-cognito-identity-js
behind a supabase-shaped wrapper so existing call sites only changed import
paths. Backend uses aws-jwt-verify (CognitoJwtVerifier for real AWS,
JwtRsaVerifier with a custom HTTP fetcher for cognito-local). Signup page
now handles Cognito's email-confirmation step.

DB: Supabase PostgREST → RDS Postgres via Drizzle ORM. ~191 query sites
across 14 backend files (~8000 lines) rewritten. Drizzle schema mirrors
the original 17 tables minus the auth.uid()-based RLS helpers - access is
already enforced in lib/access.ts via service-role queries (defense in
depth note in the original schema.sql:1052). Initial migration committed
under backend/drizzle/. A new public.users table mirrors Cognito identities
(replaces the Postgres on-signup trigger).

Storage: R2 → S3 envs (S3_BUCKET_NAME, S3_ENDPOINT_URL, AWS_*). Endpoint
and forcePathStyle are conditional - set for MinIO locally, unset for real
AWS so the SDK uses the ECS task-role credential chain.

LLM: Anthropic SDK → @aws-sdk/client-bedrock-runtime for Claude only.
OpenAI and Gemini still call their providers directly. Per-user Claude
keys are dropped (Bedrock uses IAM); a migration purges existing rows and
narrows the user_api_keys.provider check constraint.

Account deletion: routes/user.ts now calls AdminDeleteUserCommand on the
Cognito User Pool plus a cascading delete on public.users.

Frontend runtime: Cloudflare Workers / OpenNext → Next.js standalone in
Docker (output: "standalone" + `node server.js`). Removes @opennextjs/
cloudflare, wrangler, @openrouter/sdk, @supabase/*.

Backend runtime: nixpacks → node:20-bookworm-slim with libreoffice +
fontconfig baked in for DOC/DOCX → PDF conversion.

Infra artifacts:
- frontend/Dockerfile, backend/Dockerfile (multi-stage, healthchecked)
- docker-compose.yml: postgres, cognito-local (ghcr.io/amaingot/cognito-local),
  MinIO + minio-init for bucket bootstrap, smtp4dev, backend, frontend
- scripts/bootstrap-local.sh: pre-seeds cognito-local's clients.json so the
  fork's auto-generated client id doesn't clash with the env-pinned id,
  then runs Drizzle migrations
- .github/workflows/ci.yml: PR build + lint + db:migrate against a postgres
  service
- .github/workflows/build-and-publish.yml: multi-arch (amd64/arm64) push to
  ghcr.io/<owner>/mike-{frontend,backend} on main and v* tags

End-to-end verified locally:
- docker compose up brings postgres/auth/minio/smtp to healthy
- bootstrap-local.sh provisions pool + client + bucket + schema
- Cognito signup → confirm → InitiateAuth → backend JWKS verify → users
  row auto-created (with deterministic UUID derivation for cognito-local's
  non-UUID subs)
- POST /projects, GET /projects, POST /single-documents all return 200
  with the expected DB rows and MinIO object

Operator notes captured in README.md: required AWS resources (Cognito
pool, RDS, S3, SES, Bedrock model access, ECS task role permissions),
ghcr.io → ECR re-tag flow, Bedrock model-ID verification step before
first deploy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
e7593aa7 Fix frontend lint errors surfaced by new CI Alex Maingot 2026-05-14 ↗ GitHub
commit body
The Re-platform commit introduced .github/workflows/ci.yml which runs
`npm run lint` for the first time on this codebase. That surfaced 38
pre-existing errors in code inherited from upstream willchen96/mike,
which never ran ESLint in CI.

Breakdown of fixes:

- 16 react-hooks/set-state-in-effect (new in eslint-plugin-react-hooks 7
  / Next 16): converted to the React "adjusting state during render"
  pattern, useSyncExternalStore for localStorage-backed state, or
  deferred initial measurements via requestAnimationFrame/setTimeout.
- 2 react-hooks/refs in ChatView: dropped a no-op .current entry from a
  dep array that was already covered by an eslint-disable comment.
- 1 react-hooks/immutability in DocView: hoisted scrollToHighlightOnPage
  above its first useCallback caller.
- 1 react-hooks/static-components in WFColumnViewModal: switched the
  dynamic icon to React.createElement so we don't bind a component to a
  PascalCase local during render.
- 11 @typescript-eslint/no-explicit-any: removed redundant casts
  (MikeMessage already typed files/error/workflow), typed the
  caret-from-point document shape, used unknown + narrowing in catch.
- 5 react/no-unescaped-entities: escaped apostrophes/quotes in JSX text.
- 2 @typescript-eslint/no-require-imports: ignored src/scripts/** in
  eslint config - the one file there is a CJS build-time conversion
  script, not part of the app bundle.

next build still succeeds. Zero behavior changes intended - the
React Compiler-aware rules were all addressed by restructuring effects
into pure-render derivations rather than disabling them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-754.md from inside the repo you want the changes in.

⬇ Download capture-thread-754.md