Portfolio Manifest — Updated 2026-08-19

Terrence Daniels

Principal Frontend Engineer

A from-scratch rebuild of NgRx's core state-management libraries, module by module: real, MIT-licensed source ported where fidelity to a battle-tested implementation matters, six classes deliberately redesigned where the original violates its own interface — not a toy demo, and not a rewrite for its own sake either.

306commits
5,389Vitest tests
13/13modules ported
0lint errors
10CodeQL findings fixed
18×real perf fix

Why this project

The harder problem, on purpose

Writing a demo app from scratch means there's no existing architecture to evaluate, defend, or push back on — nothing to actually decide. This rebuild is the opposite exercise: recreate NgRx, Angular's dominant state-management ecosystem, module by module from the real source, and demonstrate the harder skill — knowing which parts of a mature codebase to port faithfully because they're already right, and which to challenge because they aren't, with the reasoning written down the way it would need to be defended in a real architecture review.

Angular NgRx RxJS TypeScript Nx Vitest ng-packagr GitHub Actions CodeQL

Port real source, redesign by choice

Composition over inheritance — six classes, three audit passes, complete 2026-08-06

The real NgRx Store, ActionsSubject, ReducerManager, State, ScannedActionsSubject, and EffectSources all extend RxJS's Observable/Subject types directly — a genuine Interface Segregation violation, not a style nitpick. Every consumer inherits the entire RxJS operator surface (pipe, lift, toPromise, ...) when each class's actual contract is far narrower. Store even has to override lift() in the real source purely to stop RxJS's own internal machinery from silently downgrading a Store back to a plain Observable mid-chain — direct evidence the fit is wrong, not a feature of it.

Why composition, not a workaround

Each class now holds its RxJS subject privately instead of extending it, exposing only the surface its actual contract needs. No override-the-base-class special cases left behind — the symptom that flagged the problem in the first place is gone, not patched over.

What it actually cost

Store losing the Observer interface is a real behavior change: ~40 call sites across 6 spec files rewritten, 2 tests deleted outright because the capability they tested no longer exists to test. Named in docs/architecture.md, not glossed over.

Security review, for real

CodeQL findings, fixed on a branch, landed through an actual Pull Request

10 CodeQL findings fixed in total across this repo's life — the two below are the original pair, real pre-existing vulnerabilities in ported Angular CLI source (Copyright Google Inc. still in the file header), found by CodeQL and not introduced by this repo, fixed here regardless and landed through PR #21 rather than a direct-to-main shortcut. The other 8 are the same two finding classes recurring as more modules were added — documented below rather than folded silently into the headline count.

01
ast-utils.ts
5× polynomial ReDoS — two unanchored regexes containing .* with no ^ anchor, forcing an O(n) retry from every character position on non-matching input, O(n²) total. Replaced with plain string methods (split/indexOf/lastIndexOf), immune by construction rather than just a safer regex.
high · security PR #21
02
package.ts
Prototype pollution — json[type][pkg] = version with unvalidated keys; a "__proto__" value would reassign the object's prototype instead of adding a normal property. Fixed with an explicit key guard.
high · security PR #21
03
effects, entity, operators — 3× package.ts
The same prototype-pollution pattern above, recurring: each of these 3 modules carried its own copy of schematics-core/utility/package.ts at the time it was added, inheriting the still-vulnerable code. Closed alongside the rewrite that finally satisfied CodeQL's own sanitizer recognition (see the note below) — all 4 duplicate copies fixed in the same commit, plus a real, separately-caught CI reliability bug (undeclared Nx task dependencies letting a build step race ahead of its own output).
high · security commit 623ed2e
04
data — http-url-generator.ts
A separate, later polynomial ReDoS — an alternation regex trimming leading/trailing slashes and whitespace in normalizeRoot, found once the data module was added. Replaced with an index-based manual scan, the same "immune by construction" approach as finding 01.
high · security PR #24

Disclosed, not hidden: the first prototype-pollution fix was functionally correct but used a Set.has() guard — CodeQL's own sanitizer recognition doesn't trace booleans returned from Set.has()/Array.includes() back to the guarded key, so re-scanning still flagged it as open. Rewritten to direct string-literal equality checks, the pattern CodeQL's own query actually recognizes, rather than arguing the tool was wrong.

Verifying it actually works

Real builds, real CI, stress-tested rather than assumed reliable

Every module port requires a real ng-packagr build, a real test run, and a real lint pass before being called done — then the same three gates again on GitHub Actions infrastructure this repo doesn't control. Two intermittent CI failures traced to undeclared Nx task dependencies weren't called fixed on the strength of one clean run; the fix was verified by deliberately wiping the cache and stress-testing at --parallel=4 until the race stopped reproducing.

5,389 tests, 0 lint errors

Across all 13 ported modules, real assertions against real behavior — not snapshot tests, not compilation-only checks passing for the wrong reason.

Live, self-updating dashboard

A full interactive test report plus a per-module composition chart, deployed to GitHub Pages on every push to main — checkable against the live repository, not a static screenshot.

Judgment calls

Where the interesting decisions actually happened

A live-deployed test report flagged roughly 100 tests as "slow." The cheap fix was obvious — raise the reporting threshold — and it was implemented wrong twice before it even took effect. Once genuinely applied, the number barely moved. That non-result was the actual signal: rather than call the config change "done," it pointed at a real bug — a test helper spinning up four full Angular schematic generators fresh before every single test instead of once per file. Fixed at the source: an 18×/4.5× real speedup, not a hidden threshold. Confident-looking config changes and an actually correct fix aren't always the same thing — worth telling apart, and worth writing down in todo.md when they diverge.