Skip to content

fix: lazy-load dashboard modals, replace hardcoded colors with tokens#88

Merged
Samurai33 merged 3 commits into
mainfrom
fix/launch-audit-perf-tokens
Jul 12, 2026
Merged

fix: lazy-load dashboard modals, replace hardcoded colors with tokens#88
Samurai33 merged 3 commits into
mainfrom
fix/launch-audit-perf-tokens

Conversation

@Samurai33

Copy link
Copy Markdown
Owner

Summary

Test plan

  • pnpm lint — 0 errors, only pre-existing warnings
  • pnpm type-check — clean
  • pnpm test — 26/26 passing
  • pnpm build — succeeds, all routes compile
  • Verified /episodes and /episodes/[id] render correctly (SSR HTML + accessibility tree) with the new token classes

…#34, #43)

Dashboard.tsx statically imported ProjectModal/ExpertModal (react-hook-form +
zod forms) even though they're only needed once a modal opens, bloating the
dashboard chunk. Switch both to next/dynamic({ ssr: false }).

EpisodeRating.tsx and DashboardSelect.tsx overrode the card/popover/muted
CSS variables with hardcoded bg-gray-900/800, border-gray-700/600, and
text-gray-400/300/white utilities instead of the semantic tokens already
defined in app/globals.css, leaving those tokens dead for theme edits.

#15 (homepage fully client-rendered) was already fixed in ba5e6e7 - verified,
no change needed. #78 (eslint v10/typescript v7) stays blocked upstream.
…jectModal (#34)

28 components/ui/*.tsx (including the 763-line sidebar.tsx flagged in #34)
plus hooks/use-mobile.tsx and hooks/use-toast.ts were never imported anywhere
in the app - confirmed via cross-referenced grep across app/, components/,
contexts/, hooks/, lib/, services/, and tests, including checking whether any
used component imported one of these internally. Dead code never reaches a
bundle, so "splitting" it (the issue's literal suggestion) wouldn't have
changed anything; removing it does, and additionally drops 24 now-unused npm
dependencies (recharts, date-fns, cmdk, vaul, embla-carousel-react,
react-day-picker, react-resizable-panels, sonner, 15 @radix-ui/* packages),
shrinking the supply-chain/audit surface.

For the components that ARE used and genuinely oversized: extracted the
reusable ChipListField from ProjectModal.tsx (512 -> 409 lines) into its own
file, and split Dashboard.tsx's three tabs (projects/homepage-import/experts)
into ProjectsTabContent, HomepageEpisodesTabContent and ExpertsTabContent
(476 -> 243 lines), matching the issue's "split by field group" ask for the
files that actually ship in a bundle.

Verified with lint + type-check + test + build after every step.
…rror pages, login rate limit

Production-readiness audit findings, independent of the open GitHub issues:

- app/layout.tsx OpenGraph metadata claimed url: "https://cyberjustica.brasil.gov.br" -
  a .gov.br domain this project does not own and never deployed to (README is
  explicit this is not a government platform). Replaced with the real Vercel
  deployment from README, added metadataBase, and centralized SITE_URL in
  lib/constants.ts so layout.tsx/robots.ts/sitemap.ts share one source of truth.

- next.config.mjs had no security headers at all. Added CSP, X-Content-Type-Options,
  X-Frame-Options, Referrer-Policy and Permissions-Policy via the official headers()
  API. Used a static (non-nonce) CSP deliberately: a nonce-based policy forces every
  page to render dynamically per Next's own CSP guide, which would have broken the
  static prerendering /episodes and /episodes/[id] already rely on.

- No robots.ts/sitemap.ts - standard Next.js metadata routes, absent entirely for a
  public content site. Added both, sitemap covers every episode from data/episodes.ts.

- No app/error.tsx or app/not-found.tsx - Next.js App Router error-handling
  convention, previously covered only by the client-side ErrorBoundary component
  (which doesn't catch server-render errors the same way). Added both, styled to
  match the existing cyberpunk theme.

- Dashboard login had no server-side throttling - the "3 attempts" lockout in
  DashboardAuthModal is plain useState, trivially bypassed by refreshing or calling
  the server action directly. Added a best-effort in-memory rate limiter (5
  attempts/60s per IP) to app/actions/auth.ts, documented as non-distributed
  (resets on cold start, not shared across serverless instances) since no KV/Redis
  store is provisioned. Added a regression test.

Checked and left alone: images.unoptimized:true in next.config.mjs looks like a
bug but isn't - expert.avatar (dashboard form) accepts an arbitrary URL, and
Next's image optimizer requires a fixed remotePatterns allowlist. Also confirmed
eslint v10 (#78) is still genuinely broken upstream by reproducing the failure
directly, not just reading the issue.

Verified with lint + type-check + test (27/27) + build, plus a manual curl
against `next start` confirming all 5 headers, robots.txt and sitemap.xml render
correctly in the actual production output.
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.

Components layered on Dialog/Card use hardcoded colors instead of design tokens

1 participant