ci: add typecheck, lint, and format checks to PR workflow

⛔ closed · #152 · Open-Legal-Products/mike ← amaingot/mike-aws · opened 2mo ago by amaingot · closed 2mo ago · +47,966-50,873 across 188 files · ↗ on GitHub

From the PR description

Summary

  • Extend the existing ci.yml workflow so every PR to main runs explicit type-check, lint, and Prettier format checks on both frontend and backend. Each check is its own named step so the PR status shows exactly what fails.
  • Backend got a fresh ESLint setup (flat config, @eslint/js + typescript-eslint recommended) since it had none; both packages got a shared Prettier config.
  • Frontend lint is now --max-warnings 0 so warnings block CI.
  • Cleaned up everything the new checks flagged so the workflow lands green:
    • Backend (26 errors): removed unused vars/imports/functions, killed any types in tabular.ts, narrow eslint-disable for the intentional control-char regex in storage.ts.
    • Frontend (68 warnings): removed/_-prefixed unused vars, converted ternary-as-statement patterns to if/else, added justified eslint-disable-next-line react-hooks/exhaustive-deps where existing dep arrays were deliberately narrow.
  • The bulk of the diff is prettier --write formatting in its own commit so reviewers can ignore the noise.

Commits (in order)

  1. docs: add PR CI checks design spec
  2. ci: add explicit typecheck, lint, and format checks on PRs - read this one carefully; it's the actual setup
  3. chore: apply prettier formatting and fix lint/type errors - the noisy diff

Design doc: docs/superpowers/specs/2026-05-19-pr-ci-checks-design.md

Test plan

  • All four new CI steps pass on this PR: frontend format/lint/typecheck/build + backend format/lint/typecheck/build + drizzle migration
  • Locally verified: npm run format:check && npm run lint && npm run typecheck && npm run build exits 0 in both packages
  • Once green, consider wiring branch protection to require the Frontend checks and Backend checks status checks before merge

🤖 Generated with Claude Code

Our analysis

CI checks PR that swept in the AWS re-platform — read the full analysis →

Think the analysis missed something the PR description covers?

Commits in this PR (2)

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 PR into my fork

Download a Markdown prompt that tells Claude how to port every commit in this PR into your working tree. Run it via claude -p < capture-pull-152.md from inside the repo you want the changes in.

⬇ Download capture-pull-152.md