# Your Developer Growth Report

**Report Period**: April 10–12, 2026
**Last Updated**: April 12, 2026

---

## Work Summary

Over the past 48 hours you worked intensively across two projects: **pulse-analytics-api** (backend, ~14 sessions) and **pulse-dashboard** (React frontend, ~3 sessions). Your work spanned TypeScript/Express API development, Prisma ORM query tuning, raw SQL optimization, React component architecture, testing, and documentation. You shipped a significant analytics query-layer refactor (P95 latency from 3.2s down to 340ms) and prepared a PR with 24 new integration tests.

Your sessions show an iterative, depth-first problem-solving style — you'd fix one layer (e.g. Promise.all → allSettled) then immediately recognize the next gap (unwrapping settled results cleanly), which is a strong learning signal.

---

## Improvement Areas (Prioritized)

### 1. Advanced TypeScript Type Narrowing and Generics

**Why This Matters**: TypeScript is the backbone of both your projects. Mastering type narrowing, discriminated unions, and generic constraints eliminates an entire class of runtime bugs and makes your APIs self-documenting.

**What I Observed**: Three separate sessions touched type-safety issues:
- `string | undefined` not assignable to `string` — a classic narrowing gap
- `PaginatedResponse<any>` — leaking `any` through a generic function defeats the point of generics
- Type guard for `ApiResponse<T>` that "doesn't narrow properly" — the function lacked an explicit return type predicate (`response is ...`)

These came up across different days, suggesting this is a recurring friction point, not a one-off.

**Recommendation**: Study TypeScript's `is` type predicates, `asserts` type predicates, and the `satisfies` operator. Rewrite your `processResponse` function with a proper generic constraint (`<T extends Record<string, unknown>>`) instead of `any`. Practice writing discriminated union type guards with explicit return types.

**Time to Skill Up**: 3–4 focused hours

---

### 2. Async/Await Error Handling Architecture

**Why This Matters**: Your API handles parallel data fetching and Express routing — both are async-error-heavy. Getting this wrong means silent failures, hanging requests, and swallowed errors in production.

**What I Observed**: Four sessions formed a clear chain:
- `Promise.all` losing successful results on a single rejection
- `Promise.allSettled` producing verbose unwrapping boilerplate
- Express async handlers silently swallowing rejected promises
- Error middleware not differentiating 400/404/500

Each fix revealed the next gap, suggesting this area hasn't been studied holistically yet.

**Recommendation**: Build a small error-handling architecture: (1) a typed `AppError` class hierarchy with status codes, (2) an `asyncHandler` wrapper for Express routes, (3) a `settledResults()` utility that separates fulfilled/rejected with proper types. Study how Express 5 handles async errors natively.

**Time to Skill Up**: 4–5 hours

---

### 3. Database Query Performance (ORM vs. Raw SQL Trade-offs)

**Why This Matters**: Your analytics layer processes 10k+ events with joins across multiple tables. The difference between a naive query and an optimized one was nearly 10x in your own benchmarks (3.2s → 340ms).

**What I Observed**: Three sessions on query performance:
- Prisma `include` loading too much data eagerly
- N+1 queries surfacing when the dashboard loaded related teams
- Raw SQL producing duplicate rows from multiple JOINs, needing a rewrite

You've already made the pragmatic decision to use raw SQL for hot paths and Prisma for CRUD (per your PR). The next step is building systematic intuition for *when* each approach wins.

**Recommendation**: Learn to read Prisma's query logs (`prisma.$on('query')`) and EXPLAIN ANALYZE output. Study when `include` triggers separate queries vs. JOINs. Consider Prisma's `$queryRaw` with tagged templates or explore Kysely for type-safe raw SQL.

**Time to Skill Up**: 3–4 hours

---

### 4. React Rendering Mental Model

**Why This Matters**: Your dashboard re-rendered the entire chart grid on every keystroke, and a side effect inside `useMemo` triggered the "Cannot update while rendering" warning. These are symptoms of a shallow mental model of React's render cycle.

**What I Observed**:
- Search state changes causing full ChartGrid re-renders — state colocation issue
- `fetchMetrics().then(setMetrics)` inside `useMemo` — a side effect in a computation hook
- Needed guidance on error boundary patterns

The `useMemo` misuse is the most telling: putting an async fetch inside `useMemo` shows a gap in understanding when/why React calls these hooks.

**Recommendation**: Study the React render lifecycle: what triggers a render, when effects run vs. memos compute, and why `useMemo` must be pure. Move data fetching into `useEffect` or a data-fetching library (TanStack Query). Use React DevTools Profiler to visualize re-renders. Memo-ize `ChartGrid` with `React.memo` and isolate search state to its own context.

**Time to Skill Up**: 4–6 hours

---

## Strengths Observed

- **Testing discipline**: Proactively wrote unit, integration, and edge-case tests — including non-obvious cases like circular JSON in error objects
- **Performance ownership**: Benchmarked before/after (P95 3.2s → 340ms) and load-tested with realistic data (50k events)
- **Security awareness**: Checked for express CVEs before upgrading
- **Clear communication**: PR description had explicit breaking changes and quantified results

---

## Action Items

1. Write a proper type-guarded `isApiError<T>()` with an `is` predicate for your `ApiResponse<T>` union — apply it immediately to your codebase
2. Extract a reusable `asyncHandler` + `AppError` hierarchy for your Express routes — consolidate the ad-hoc error handling from this week
3. Add `prisma.$on('query')` logging in dev mode and run EXPLAIN ANALYZE on your top 3 slowest endpoints
4. Move the `fetchMetrics` call out of `useMemo` into `useEffect` in `MetricsProvider`, and wrap `ChartGrid` in `React.memo`

---

## Curated Learning Resources

### For: TypeScript Type Narrowing & Generics

1. **[TypeScript: Control flow analysis for destructured discriminated unions](https://news.ycombinator.com/item?id=29099331)** — HN Discussion
   Dives into how TypeScript's control flow analysis handles discriminated unions after destructuring — directly relevant to your `ApiResponse<T>` type guard work.

2. **[Zod: TypeScript-first schema validation with static type inference](https://news.ycombinator.com/item?id=41764163)** — HN Discussion
   Covers how Zod bridges runtime validation with compile-time types, a pattern that would eliminate your `string | undefined` issues at API boundaries.

### For: Async Error Handling

3. **[The gotcha of unhandled promise rejections](https://news.ycombinator.com/item?id=34347079)** — HN Discussion
   Breaks down exactly the Express async error swallowing pattern you hit — why rejected promises don't reach Express error middleware and how to fix it.

4. **[Express Error Handling Patterns](https://betterstack.com/community/guides/scaling-nodejs/error-handling-express/)** — Better Stack Guide
   Comprehensive guide to structuring Express error middleware with typed error hierarchies, async wrappers, and proper status code differentiation.

### For: Database Query Optimization

5. **[Finding and optimizing N+1 queries on a relational database](https://news.ycombinator.com/item?id=41486029)** — HN Discussion
   Systematic approach to detecting and fixing N+1 queries — the exact issue you hit with team loading in your dashboard.

6. **[We migrated to SQL. Our biggest learning? Don't use Prisma](https://news.ycombinator.com/item?id=37818391)** — HN Discussion
   A team's journey from Prisma to raw SQL for performance-critical paths. Mirrors your own refactor and offers lessons learned on the hybrid approach.

### For: React Rendering Performance

7. **[The Useless UseCallback](https://news.ycombinator.com/item?id=44715391)** — HN Discussion (2025)
   Recent discussion challenging common memoization assumptions. Good for building a clearer mental model of when React.memo / useMemo / useCallback actually help.

8. **[Understanding UseMemo and UseCallback](https://news.ycombinator.com/item?id=32652627)** — HN Discussion
   Practical breakdown of when these hooks matter, with examples of the "useless useMemo" anti-pattern — relevant to your MetricsProvider issue.
