Paul Sumido Portfolio

A playground where I can test different styles and functionality.

Log in

What I Built

Authentication, design systems, live data, full-stack API integration, and real-user performance monitoring — all in one project.

🔐

Auth & Security

Auth0 integration with CSP headers, proxy middleware, and protected routes.

📊

Web Vitals Dashboard

Real-user Core Web Vitals collected via sendBeacon, aggregated as P75 in Postgres, and displayed on a protected dashboard.

🎨

Design System

Token-driven palette, theme toggling, and reusable components.

🏀

NBA Stats

Live player stats via API proxy with batch loading and error handling.

🃏

Pokémon TCG

Card browser with infinite scroll, URL-synced filters, and per-set grids built on the TCGdex SDK.

📅

Personal Calendar

Four-view calendar with multi-day events, time-grid overlap layout, and Pokémon card attachments.

GraphQL Pokédex

Pokémon browser using the PokeAPI Hasura endpoint — typed queries, field selection, plain fetch over Apollo.

Auth & Security

  • Auth0 SDK — session management with server-side token handling
  • CSP Headers — strict Content-Security-Policy via middleware
  • Proxy Middleware — API calls proxied server-side to hide secrets
  • Route Protection — unauthenticated users redirected from private pages
// middleware.ts
export async function middleware(req) {
  const session = await auth0.getSession();

  if (!session && isProtected(req)) {
    return redirect("/auth/login");
  }

  // attach CSP + nonce headers
  return addSecurityHeaders(req);
}

Design System

A token-driven palette with semantic color aliases, consistent spacing, and theme toggling.

P400
P500
P600
S400
S500
S600
N
Err
Ok
Warn
PrimarySecondaryAccentDestructive
sm
md
lg
xl
2xl
full

NBA Stats

Live player statistics proxied through the API layer with batch loading and error recovery.

PlayerTeamPTSREBAST
Luka DoncicLAL28.48.38.1
Jayson TatumBOS27.08.54.6
Shai GilgeousOKC31.25.56.0
Nikola JokicDEN26.312.49.0

Live API Proxy

Server-side proxy hides API keys from the client.

Batch Loading

Multiple players fetched in parallel with loading states.

Error Handling

Granular error recovery per player, not per page.

Pokémon TCG Browser

Full card browser with infinite scroll, URL-synced filters, per-set grids, and deep card detail — built on the TCGdex SDK.

FireWaterGrassLightningPsychic
Charizard
Pikachu
Mewtwo
Blastoise
Gengar
Eevee

Infinite Scroll

IntersectionObserver sentinel loads next pages as you scroll — reconnects after each fetch so wide viewports never stall.

URL-Synced State

Search, type filter, and page number live in the URL. Shareable, bookmarkable, and back/forward navigable.

Server / Client Split

Set metadata fetched server-side via TCGdex SDK. Paginated card grids are client components with Suspense boundaries.

Personal Calendar

Day, week, month, and year views with multi-day events, an overlapping-event layout engine, and Pokémon card attachments — built to track what we pull playing Pokémon Pocket together.

February 2026
DayWeekMonthYear
Su
Mo
Tu
We
Th
Fr
Sa
26
27
28
1
Pocket night
2
Pocket night
3
4
5
6
Trade meet
7
Trade meet
Pulled Mewtwo ✦
8
Trade meet
9
10
11

4 Calendar Views

Day and week views use an absolute-positioned time grid — events span their real duration and sit side by side when they overlap.

Pokémon Card Tracking

Attach cards pulled from Pocket to any event. Search the full TCGdex catalog and log what you got, when you got it.

Multi-day Events

Events spanning multiple days show on every day they cover, with continuation bars in month view and all-day row promotion in week/day view.

GraphQL Pokédex

Browse 1,000+ Pokémon via a Hasura GraphQL endpoint — typed queries, field selection, and a live query inspector. Plain fetch, no Apollo.

AllFireWaterGrassElectricPsychic
#001Bulbasaur
#004Charmander
#007Squirtle
#025Pikachu
#039Jigglypuff
#054Psyduck

GraphQL Queries

Field selection means the card only fetches id, name, types, and two stats — not the full 40-field REST response.

No Apollo

Plain fetch with a 10-line wrapper. Apollo earns its cost for normalized caches and subscriptions; for a browser it's just weight.

Live Query Inspector

A collapsible panel shows the actual GraphQL query and variables as you search and filter — updates in real time.

Web Vitals Dashboard

Real-user Core Web Vitals collected from every page load. P75 scores aggregated in Postgres and displayed on a protected dashboard — field data, not lab simulations.

Web Vitals
LCP
1.8s
FCP
0.9s
INP
145ms
CLS
0.041
TTFB
320ms
By page
PageLCPP75
/protected/vitals1.8s
75th
/calendar2.1s
75th
/tcg/browse2.9s
75th

Real-user Collection

The web-vitals package fires each metric from real browsers over real connections. sendBeacon guarantees delivery even when the user navigates away before the metric fires.

P75 in Postgres

PERCENTILE_CONT(0.75) aggregates the 75th percentile natively in SQL — no extra tooling. P75 is the same threshold Google uses for search ranking.

End-to-end Ownership

BFF proxy keeps auth tokens server-side. Data lives in our own DB so the dashboard can be embedded anywhere, not just a third-party UI.

Ready to explore?

Log in and see everything in action.