diff --git "a/\001\220" "b/\001\220" deleted file mode 100644 index e69de29..0000000 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a4202b7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +# A superseded run tells you nothing useful; don't pay for it. +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + # react-simple-maps declares a React <19 peer, so a plain `npm ci` fails. + # deploy.yml installs the same way. + - name: Install + run: npm install --legacy-peer-deps + + - name: Typecheck + run: npx tsc --noEmit + + - name: Unit tests + run: npm test -- --run + + # Deliberately no Substack fetch: CI must not depend on the network or on + # dommangonon.substack.com being up. deploy.yml runs + # scripts/fetch-substack.js as its own step before building. + - name: Build + run: npm run build + + - name: Install Playwright browser + run: npx playwright install --with-deps chromium + + # playwright.config.ts starts its own dev server; reuseExistingServer is + # off when CI is set, so this can't silently test a stale server. + - name: E2E tests + run: npx playwright test + + - name: Upload Playwright report + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-report + path: playwright-report/ + retention-days: 7 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ec1a96e..e8e3ece 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,6 +3,13 @@ name: Deploy to GitHub Pages on: push: branches: [main] + # Picks up newly published Substack posts without a human push. The feed is + # fetched during the build (below) rather than committed by a cron, because + # pushes from github-actions[bot] with the default GITHUB_TOKEN do not + # trigger workflows — a commit-then-rebuild loop silently never rebuilds. + # Note: GitHub disables scheduled workflows after 60 days of repo inactivity. + schedule: + - cron: '0 11 * * *' workflow_dispatch: permissions: @@ -30,10 +37,13 @@ jobs: - name: Install dependencies run: npm install --legacy-peer-deps + # Rewrites lib/content/writing.ts in the workspace only — never committed. + # Failures are warnings: the committed posts are used instead. + - name: Fetch Substack posts + run: node scripts/fetch-substack.js + - name: Build Next.js run: npm run build - env: - CAREER_DIR: ${{ github.workspace }}/content/career - name: Upload artifact uses: actions/upload-pages-artifact@v3 diff --git a/.github/workflows/update-dashboard-data.yml b/.github/workflows/update-dashboard-data.yml index a238b4d..d72d89e 100644 --- a/.github/workflows/update-dashboard-data.yml +++ b/.github/workflows/update-dashboard-data.yml @@ -1,40 +1,52 @@ - on: - schedule: - - cron: '0 */6 * * *' - workflow_dispatch: - - permissions: - contents: write - - jobs: - update-data: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Fetch Analytics Data - env: - GOATCOUNTER_API_KEY: ${{ secrets.GOATCOUNTER_API_KEY }} - GOATCOUNTER_SITE: ${{ secrets.GOATCOUNTER_SITE }} - run: node scripts/fetch-analytics.js - - - name: Fetch Performance Data - env: - SITE_URL: ${{ vars.SITE_URL }} - run: node scripts/fetch-performance.js - - - name: Fetch Uptime Data - env: - UPTIMEROBOT_API_KEY: ${{ secrets.UPTIMEROBOT_API_KEY }} - run: node scripts/fetch-uptime.js - - - name: Commit updated data - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add public/data/ - git diff --staged --quiet || git commit -m "chore: update dashboard data" && git push +name: Update dashboard data + +on: + schedule: + - cron: '0 */6 * * *' + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-data: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Fetch Analytics Data + env: + GOATCOUNTER_API_KEY: ${{ secrets.GOATCOUNTER_API_KEY }} + GOATCOUNTER_SITE: ${{ secrets.GOATCOUNTER_SITE }} + run: node scripts/fetch-analytics.js + + - name: Fetch Performance Data + env: + SITE_URL: ${{ vars.SITE_URL }} + run: node scripts/fetch-performance.js + + - name: Fetch Uptime Data + env: + UPTIMEROBOT_API_KEY: ${{ secrets.UPTIMEROBOT_API_KEY }} + run: node scripts/fetch-uptime.js + + # Note: this commit uses the default GITHUB_TOKEN, so the push does NOT + # trigger deploy.yml. The dashboard reads /data/*.json at runtime, so the + # fresh data is picked up by deploy.yml's own daily schedule. + - name: Commit updated data + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add public/data/ + # `a || b && c` is left-associative: the old one-liner pushed even + # when there was nothing to commit. + if git diff --staged --quiet; then + echo "No dashboard data changes." + else + git commit -m "chore: update dashboard data" + git push + fi diff --git a/.gitignore b/.gitignore index a50330f..9532323 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,14 @@ next-env.d.ts # Windows NTFS zone identifiers *:Zone.Identifier -# Career source docs and processing +# Career content — kept out of this public repo entirely. +# The site no longer reads it; source of record is ~/personal/career. +content/career/ +public/assets/*.pdf content/career/source-docs/ content/career/_processing/ content/career/package.json + +# Playwright +test-results/ +playwright-report/ diff --git a/CLAUDE.md b/CLAUDE.md index 831a5c1..6a9471a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -Personal portfolio site built with Next.js 16, React 19, TypeScript, and Tailwind CSS 4. Static export (no server runtime). +Dom Mangonon's personal site: a **single-page** portfolio built with Next.js 16, React 19, +TypeScript, and Tailwind CSS 4. Static export (no server runtime), deployed to GitHub Pages +at https://dommango.github.io. + +The page leads with the **project portfolio**, then writing, with career compressed to context. ## Commands @@ -13,96 +17,113 @@ npm run dev # Start dev server (localhost:3000) npm run build # Build static site (output: out/) npm test # Run Vitest tests (watch mode) npm test -- --run # Run tests once -npm test -- Button # Run tests matching "Button" npm run lint # ESLint check -npm run lint -- --fix # Auto-fix lint issues -tsc --noEmit # Type check without emitting +npx tsc --noEmit # Type check +npx playwright test # E2E ``` -## Build Process - -The `prebuild` script runs automatically before `npm run build`: -1. **sync-career-content.js** - Copies career markdown from `$CAREER_DIR` (default: `/home/dom/personal/career`) to `content/career/` -2. **generate-resume-pdf.js** - Uses Puppeteer to generate PDF from HTML resume (gracefully skips if Chrome unavailable) - -Static export config in `next.config.ts`: `output: 'export'` with `images.unoptimized: true`. +Note: `npm install` needs `--legacy-peer-deps` (react-simple-maps declares a React <19 peer). +CI uses it too. ## Architecture +The whole site is **one page**. `app/page.tsx` is a server component that loads data at build +time and hands it to `components/landing/BrutalistLanding.tsx`, a client shell holding theme + +scroll-spy state and composing every section. + ``` -app/ # Next.js App Router pages -├── layout.tsx # Root layout with Header, Footer, ChatBot -├── page.tsx # Home - ProfileHero, ProfileSummary, CareerThemes -├── career/ # Career timeline page -├── education/ # Education page -├── skills/ # Skills grid page -├── travel/ # Travel map page -├── blog/ # Blog listing/posts -├── contact/ # Contact form (uses EmailJS) -└── api/contact/ # Contact API route - -components/ -├── layout/ # Header, Footer -├── profile/ # ProfileHero, ProfileSummary, CareerThemes -├── chat/ # ChatBot widget -├── timeline/ # Career timeline -├── skills/ # Skills grid -├── education/ # Education section -├── travel/ # Travel map (react-simple-maps) -├── contact/ # Contact form -└── ui/ # Reusable primitives (Card, Badge, Section, Button) - -lib/ -├── content/ # Content loaders parsing markdown with gray-matter -│ ├── profile.ts # getProfile() - parses profile.md frontmatter -│ ├── roles.ts # getRoles() - career positions -│ ├── education.ts # getEducation() -│ ├── skills.ts # getSkills() -│ ├── blog.ts # getBlogPosts() -│ └── travel.ts # getCountries() -├── constants.ts # Shared constants -├── utils.ts # Utility functions -└── services/ # External service integrations - -content/ # Markdown content (synced from CAREER_DIR) -├── career/ # Career entries with frontmatter -├── blog/ # Blog posts -└── travel/ # Travel data (JSON) +app/ +├── layout.tsx # Root layout, fonts, metadata/JSON-LD, ChatBot +├── page.tsx # Loads projects/writing/travel data -> BrutalistLanding +├── globals.css # All styles (see Design System below) +└── dashboard-m7x9k2/ # Private-ish analytics dashboard (obscure URL, not linked) + +components/landing/ # The page, in DOM order: +├── Nav.tsx # Sticky nav + theme cycler +├── Availability.tsx # Status strip under nav +├── Hero.tsx # Headline, portrait, bio +├── Projects.tsx # THE MAIN SECTION — project cards +├── Writing.tsx # Substack posts; renders only when posts exist +├── Resume.tsx # Compressed career timeline +├── Travel.tsx # Continent bars + globe +├── Contact.tsx # EmailJS-wired form +├── Footer.tsx +└── BinaryRule.tsx # Decorative divider (seeded PRNG — see below) + +components/travel/TravelMap.tsx # Heavy globe, dynamically imported by landing/Travel +components/chat/ChatBot.tsx # Assistant widget +components/ui/ # Card, Skeleton, ProgressBar — dashboard only + +lib/content/ # Build-time data (no fs, no runtime fetch) +├── projects.ts # Hand-authored PROJECTS array +├── writing.ts # Substack posts +└── travel.ts # Transforms content/travel/*.json +lib/services/ # emailjs.ts, chat.ts ``` -## Content System +## Adding or changing a section -Career content lives in markdown files with gray-matter frontmatter: -- Source: `$CAREER_DIR` environment variable (default: `/home/dom/personal/career`) -- Build destination: `content/career/` -- Profile data parsed from `profile.md` frontmatter + content sections +Four places must stay in sync or the scroll-spy breaks silently: -Content loaders in `lib/content/` read files synchronously at build time for static generation. +1. `components/landing/
.tsx` — the component +2. `SectionId` union in `Nav.tsx` +3. `SECTION_IDS` in `BrutalistLanding.tsx` — **must match DOM order**; the spy takes the last + element with `offsetTop <= scrollY`, so wrong order = wrong active link +4. The `link()` calls in `Nav.tsx` -## Environment Variables +Conditional sections (Writing) need the nav link gated by the same predicate as the section, +or the link scrolls to nothing. -```bash -# EmailJS for contact form -NEXT_PUBLIC_EMAILJS_SERVICE_ID= -NEXT_PUBLIC_EMAILJS_TEMPLATE_ID= -NEXT_PUBLIC_EMAILJS_PUBLIC_KEY= +## Design System -# Career content source (optional, defaults to /home/dom/personal/career) -CAREER_DIR=/path/to/career -``` +All styles live in `app/globals.css` (~1130 lines). Two disjoint token systems: + +- **`:root` (lines 1-121)** — legacy tokens + Tailwind bridge. Used by the dashboard/ChatBot only. +- **`.brutalist-root` (128-239)** — the landing. Everything is scoped here. + +**Build new sections from semantic tokens only** — `var(--accent)`, `var(--fg)`, `var(--fg-muted)`, +`var(--fg-low)`, `var(--rule)`, `var(--s-N)` spacing, `var(--font-display|sans|mono)`. Do that and +all three themes (Gold / Oxblood / High Contrast) work for free, since the theme cycler only swaps +token values via `[data-accent]` / `[data-contrast]` attributes. + +The landing is **dark-only by design** — the `prefers-color-scheme: light` block only touches +`:root`, which `.brutalist-root` shadows. + +**Responsive: one breakpoint**, `@media (max-width: 900px)` at the bottom. Any new multi-column +grid must be added there manually; nothing is automatic. + +Structure convention: `.section` > `` > `.*-head`. The adjacent-sibling rule +`.section > .binary-rule + *` supplies the top margin, so keep that order. + +`BinaryRule`'s `seed` prop drives a deterministic sine-hash PRNG — it exists for **hydration +safety** (server and client must render identical digits), not aesthetics. Give new sections an +arbitrary unused seed. + +## Content + +Hand-authored TypeScript in `lib/content/`, not markdown. Prefer typed TS modules over JSON: +`resolveJsonModule` is on, and importing an empty `[]` JSON file infers `never[]`, which fails +typecheck under `strict`. + +Travel data is the exception — script-generated JSON in `content/travel/`, produced by +`scripts/process-travel-data.js` and `scripts/fetch-flights.js` (both manual). + +**Career content is deliberately NOT in this repo** — it's gitignored. This repo is public; the +source of record is `~/personal/career`. Don't re-add it or reintroduce a sync step. + +## Deployment + +`.github/workflows/deploy.yml` — on push to `main` (+ manual), builds and pushes `out/` to Pages. -## Key Dependencies +**Gotcha:** pushes made by `github-actions[bot]` with the default `GITHUB_TOKEN` do **not** +trigger workflows. So a cron that commits data cannot make the site rebuild. Anything needing +fresh data at deploy time must fetch **during the build**, not commit-then-rebuild. -- **gray-matter** - Parse markdown frontmatter -- **react-simple-maps** / **d3-geo** / **topojson-client** - Travel map visualization -- **@emailjs/browser** - Contact form email delivery -- **date-fns** - Date formatting -- **clsx** - Conditional class composition +`update-dashboard-data.yml` crons analytics/uptime/performance JSON into `public/data/`. ## Testing -Vitest with jsdom environment. Setup in `vitest.setup.ts` includes mocks for: -- `window.matchMedia` -- `IntersectionObserver` +Vitest + jsdom for units (`__tests__/`), Playwright for E2E (`e2e/`). `vitest.setup.ts` mocks +`matchMedia` and `IntersectionObserver`. -Tests located in `__tests__/` directory. Use `@testing-library/react` for component tests. +Test nontrivial logic (parsers, transforms, conditional-render invariants). Skip ceremony tests. diff --git a/README.md b/README.md index e215bc4..79193f1 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,50 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# dommango.github.io -## Getting Started +My personal site — a single-page portfolio of the things I've built, plus writing and a travel map. -First, run the development server: +**Live:** https://dommango.github.io + +## Stack + +Next.js 16 · React 19 · TypeScript · Tailwind CSS 4 · static export to GitHub Pages. + +No server runtime — everything renders at build time. + +## Local development ```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +npm install --legacy-peer-deps # react-simple-maps declares a React <19 peer +npm run dev # localhost:3000 ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +## Commands -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +```bash +npm run build # static build -> out/ +npm test -- --run # unit tests +npx playwright test # e2e +npm run lint +npx tsc --noEmit +``` -## Learn More +## Environment -To learn more about Next.js, take a look at the following resources: +Copy `.env.example` to `.env.local`. The contact form uses EmailJS; without those keys it renders +but won't send. -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +``` +NEXT_PUBLIC_EMAILJS_SERVICE_ID= +NEXT_PUBLIC_EMAILJS_TEMPLATE_ID= +NEXT_PUBLIC_EMAILJS_PUBLIC_KEY= +NEXT_PUBLIC_RECAPTCHA_SITE_KEY= +NEXT_PUBLIC_GOATCOUNTER_SITE= +``` -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +## Deployment -## Deploy on Vercel +Push to `main`. `.github/workflows/deploy.yml` builds and publishes to GitHub Pages. -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +## Architecture -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +See [CLAUDE.md](./CLAUDE.md) for the section structure, the design-token system, and the four +places that must stay in sync when adding a section. diff --git a/__tests__/api/contact.test.ts b/__tests__/api/contact.test.ts deleted file mode 100644 index bd17aea..0000000 --- a/__tests__/api/contact.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { describe, it, expect } from 'vitest' - -/** - * Contact API Route Tests - * Test the contact form submission endpoint - */ -describe('POST /api/contact', () => { - it('validates required fields', async () => { - const invalidSubmissions = [ - { name: '', email: 'test@example.com', subject: 'Test', message: 'Hello' }, - { name: 'John', email: '', subject: 'Test', message: 'Hello' }, - { name: 'John', email: 'test@example.com', subject: '', message: 'Hello' }, - { name: 'John', email: 'test@example.com', subject: 'Test', message: '' } - ] - - for (const submission of invalidSubmissions) { - // In a real test, you would make actual API calls - // For now, this demonstrates the test structure - expect(submission).toBeDefined() - } - }) - - it('validates email format', () => { - const invalidEmails = [ - 'notanemail', - 'missing@domain', - '@nodomain.com' - ] - - const validEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - - for (const email of invalidEmails) { - expect(validEmail.test(email)).toBe(false) - } - - expect(validEmail.test('valid@example.com')).toBe(true) - }) - - it('enforces field length limits', () => { - const testCases = [ - { field: 'name', maxLength: 100, testValue: 'a'.repeat(101) }, - { field: 'subject', maxLength: 200, testValue: 'a'.repeat(201) }, - { field: 'message', maxLength: 5000, testValue: 'a'.repeat(5001) } - ] - - for (const testCase of testCases) { - expect(testCase.testValue.length).toBeGreaterThan(testCase.maxLength) - } - }) -}) diff --git a/__tests__/components/Button.test.tsx b/__tests__/components/Button.test.tsx deleted file mode 100644 index 785b022..0000000 --- a/__tests__/components/Button.test.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { describe, it, expect, vi } from 'vitest' -import { render, screen } from '@testing-library/react' -import userEvent from '@testing-library/user-event' -import { Button } from '@/components/ui/Button' - -describe('Button Component', () => { - it('renders with children text', () => { - render() - expect(screen.getByText('Click me')).toBeInTheDocument() - }) - - it('handles click events', async () => { - const handleClick = vi.fn() - const user = await userEvent.setup() - - render() - - await user.click(screen.getByText('Click me')) - expect(handleClick).toHaveBeenCalledTimes(1) - }) - - it('disables button when disabled prop is true', () => { - render() - const button = screen.getByRole('button') - expect(button).toBeDisabled() - }) - - it('applies variant styles correctly', () => { - render() - const button = screen.getByRole('button') - expect(button).toHaveClass('bg-blue-600') - }) - - it('applies secondary variant styles correctly', () => { - render() - const button = screen.getByRole('button') - expect(button).toHaveClass('bg-gray-200', 'text-gray-900') - }) - - it('merges custom className with default styles', () => { - render() - const button = screen.getByRole('button') - expect(button).toHaveClass('custom-class') - expect(button).toHaveClass('font-medium') // default style - }) -}) diff --git a/__tests__/parse-substack-feed.test.ts b/__tests__/parse-substack-feed.test.ts new file mode 100644 index 0000000..8aa9d30 --- /dev/null +++ b/__tests__/parse-substack-feed.test.ts @@ -0,0 +1,150 @@ +import { describe, it, expect } from 'vitest' +import { parseSubstackFeed } from '../scripts/lib/parse-substack-feed' + +const feed = (items: string) => ` + + <![CDATA[Context//Collapse]]> + ${items} +` + +const item = (title: string, link: string, pubDate: string, description = '') => ` + + <![CDATA[${title}]]> + ${link} + ${pubDate} + ${description ? `` : ''} + ` + +describe('parseSubstackFeed', () => { + it('extracts posts from a real feed', () => { + const posts = parseSubstackFeed( + feed( + item('Shipping with Claude', 'https://x.substack.com/p/a', 'Mon, 06 Jul 2026 12:00:00 GMT', 'How it went') + ) + ) + + expect(posts).toEqual([ + { + title: 'Shipping with Claude', + url: 'https://x.substack.com/p/a', + date: '2026-07-06T12:00:00.000Z', + subtitle: 'How it went', + }, + ]) + }) + + // The whole point of the dormant Writing section: Substack seeds every new + // publication with this, and it must not count as a post. + it('filters out the "Coming soon" placeholder', () => { + const posts = parseSubstackFeed( + feed(item('Coming soon', 'https://x.substack.com/p/coming-soon', 'Mon, 02 Mar 2026 12:00:00 GMT')) + ) + + expect(posts).toEqual([]) + }) + + it('keeps real posts alongside the placeholder', () => { + const posts = parseSubstackFeed( + feed( + item('Coming soon', 'https://x.substack.com/p/coming-soon', 'Mon, 02 Mar 2026 12:00:00 GMT') + + item('A real post', 'https://x.substack.com/p/real', 'Tue, 07 Jul 2026 12:00:00 GMT') + ) + ) + + expect(posts).toHaveLength(1) + expect(posts?.[0].title).toBe('A real post') + }) + + it('returns newest first', () => { + const posts = parseSubstackFeed( + feed( + item('Older', 'https://x.substack.com/p/1', 'Mon, 01 Jun 2026 12:00:00 GMT') + + item('Newer', 'https://x.substack.com/p/2', 'Mon, 06 Jul 2026 12:00:00 GMT') + ) + ) + + expect(posts?.map((p: { title: string }) => p.title)).toEqual(['Newer', 'Older']) + }) + + it('handles a single-item feed (parser returns an object, not an array)', () => { + const posts = parseSubstackFeed( + feed(item('Only one', 'https://x.substack.com/p/1', 'Mon, 06 Jul 2026 12:00:00 GMT')) + ) + + expect(posts).toHaveLength(1) + }) + + it('drops items missing a pubDate rather than emitting an invalid date', () => { + const posts = parseSubstackFeed( + feed(`No datehttps://x.substack.com/p/1`) + ) + + expect(posts).toEqual([]) + }) + + it('drops items with an unparseable pubDate', () => { + const posts = parseSubstackFeed( + feed(item('Bad date', 'https://x.substack.com/p/1', 'not-a-date')) + ) + + expect(posts).toEqual([]) + }) + + // A Substack outage must degrade gracefully, never break the build. + it('does not throw on malformed XML', () => { + expect(() => parseSubstackFeed('broken')).not.toThrow() + }) + + // The distinction the caller depends on: [] may overwrite the committed + // POSTS, null may not. Collapsing them lets a 200-with-an-HTML-body wipe + // the Writing section on an unattended cron build. + it('returns [] for a real feed that has no posts', () => { + expect(parseSubstackFeed(feed(''))).toEqual([]) + }) + + it('returns null when the body is not a feed at all', () => { + // Every one of these arrives as a 200 in the wild. + expect(parseSubstackFeed('not a feed')).toBeNull() + expect( + parseSubstackFeed('Just a moment...') + ).toBeNull() + expect(parseSubstackFeed('')).toBeNull() + expect(parseSubstackFeed(' ')).toBeNull() + // Guards the runtime contract: the script calls this with whatever the + // network returned, which TypeScript can't police. + expect(parseSubstackFeed(undefined as unknown as string)).toBeNull() + }) + + // Substack puts HTML in ; unstripped it renders as visible tag + // soup on the card (React escapes it, so it is not an XSS vector). + it('strips HTML markup out of the subtitle', () => { + const posts = parseSubstackFeed( + feed( + item( + 'Post', + 'https://x.substack.com/p/a', + 'Mon, 06 Jul 2026 12:00:00 GMT', + '

Hello world — a subtitle

' + ) + ) + ) + + expect(posts?.[0].subtitle).toBe('Hello world — a subtitle') + }) + + it('keeps prose that merely contains a bare angle bracket', () => { + const posts = parseSubstackFeed( + feed(item('Post', 'https://x.substack.com/p/a', 'Mon, 06 Jul 2026 12:00:00 GMT', 'when a < b holds')) + ) + + expect(posts?.[0].subtitle).toBe('when a < b holds') + }) + + it('omits the subtitle entirely when the description is only markup', () => { + const posts = parseSubstackFeed( + feed(item('Post', 'https://x.substack.com/p/a', 'Mon, 06 Jul 2026 12:00:00 GMT', '

')) + ) + + expect(posts?.[0]).not.toHaveProperty('subtitle') + }) +}) diff --git a/app/api/contact/route.ts b/app/api/contact/route.ts deleted file mode 100644 index eeff23a..0000000 --- a/app/api/contact/route.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server' - -interface ContactFormData { - name: string - email: string - subject: string - message: string -} - -interface ContactResponse { - success: boolean - message: string - data?: ContactFormData - errors?: Record -} - -/** - * Validate contact form data - */ -function validateContactForm(data: unknown): { - valid: boolean - errors: Record - data?: ContactFormData -} { - const errors: Record = {} - - if (!data || typeof data !== 'object') { - return { - valid: false, - errors: { form: 'Invalid form data' } - } - } - - const form = data as Record - - // Validate name - if (!form.name || typeof form.name !== 'string' || form.name.trim().length === 0) { - errors.name = 'Name is required' - } else if (form.name.length > 100) { - errors.name = 'Name must be under 100 characters' - } - - // Validate email - if (!form.email || typeof form.email !== 'string' || form.email.trim().length === 0) { - errors.email = 'Email is required' - } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) { - errors.email = 'Please enter a valid email address' - } - - // Validate subject - if (!form.subject || typeof form.subject !== 'string' || form.subject.trim().length === 0) { - errors.subject = 'Subject is required' - } else if (form.subject.length > 200) { - errors.subject = 'Subject must be under 200 characters' - } - - // Validate message - if (!form.message || typeof form.message !== 'string' || form.message.trim().length === 0) { - errors.message = 'Message is required' - } else if (form.message.length > 5000) { - errors.message = 'Message must be under 5000 characters' - } - - if (Object.keys(errors).length > 0) { - return { - valid: false, - errors - } - } - - return { - valid: true, - errors: {}, - data: { - name: form.name as string, - email: form.email as string, - subject: form.subject as string, - message: form.message as string - } - } -} - -/** - * POST /api/contact - * Handle contact form submissions - */ -export async function POST(request: NextRequest): Promise> { - // Check request method - if (request.method !== 'POST') { - return NextResponse.json( - { - success: false, - message: 'Method not allowed' - }, - { status: 405 } - ) - } - - try { - const body = await request.json() - - // Validate form data - const validation = validateContactForm(body) - - if (!validation.valid) { - return NextResponse.json( - { - success: false, - message: 'Validation failed', - errors: validation.errors - }, - { status: 400 } - ) - } - - const contactData = validation.data! - - // TODO: Send email or save to database - // Example: await sendEmail(contactData) - // Example: await db.contactMessages.create(contactData) - - console.log('Contact form submission:', contactData) - - return NextResponse.json( - { - success: true, - message: 'Message received! I\'ll get back to you soon.', - data: contactData - }, - { status: 200 } - ) - } catch (error) { - console.error('Contact form error:', error) - - return NextResponse.json( - { - success: false, - message: 'An error occurred while processing your message' - }, - { status: 500 } - ) - } -} - -/** - * OPTIONS /api/contact - * Handle CORS preflight - */ -export async function OPTIONS(): Promise { - return NextResponse.json( - {}, - { - headers: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'POST, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type' - } - } - ) -} diff --git a/app/globals.css b/app/globals.css index 5b55db2..6cb7a72 100644 --- a/app/globals.css +++ b/app/globals.css @@ -474,7 +474,10 @@ input, } .hero-title { font-family: var(--font-display); - font-size: clamp(48px, 7.2vw, 116px); + /* Floor is 32px, not 48px: below ~667px the vw term stops binding and the + floor takes over, and "Unapologetically" is long enough to overflow the + viewport at 48px. Only affects <667px; wider screens are unchanged. */ + font-size: clamp(32px, 7.2vw, 116px); line-height: 0.88; letter-spacing: -0.04em; color: var(--fg); @@ -494,7 +497,7 @@ input, .hero-kicker-alt { color: var(--accent); } .hero-meta { display: grid; - grid-template-columns: 1.4fr 1fr; + grid-template-columns: minmax(0, 1.4fr); gap: var(--s-8); margin-top: var(--s-7); } @@ -508,77 +511,6 @@ input, margin: 0; } .hero-about-secondary { font-size: var(--fs-400); color: var(--fg-muted); } -.awards-list { - list-style: none; - margin: 0; - padding: 0; - display: flex; - flex-direction: column; -} -.awards-list li { - display: flex; - justify-content: space-between; - align-items: baseline; - padding: 11px 0; - border-bottom: 1px solid var(--rule); - font-family: var(--font-sans); - font-size: 14px; -} -.awards-list li:last-child { border-bottom: 0; } -.awards-count { - font-family: var(--font-mono); - font-size: 11px; - color: var(--fg-muted); - letter-spacing: 0.08em; -} - -/* ---- Career themes grid ---------------------------------- */ -.hero-themes { - margin-top: var(--s-7); - display: flex; - flex-direction: column; - gap: var(--s-5); -} -.themes-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0; - border-top: 1px solid var(--rule); -} -.theme { - padding: var(--s-5) var(--s-4) var(--s-5) 0; - border-bottom: 1px solid var(--rule); - border-right: 1px solid var(--rule); - display: flex; - flex-direction: column; - gap: 6px; -} -.theme:nth-child(3n) { border-right: 0; padding-right: 0; } -.theme:nth-child(n + 4) { padding-left: var(--s-4); } -.theme:nth-child(3n + 1) { padding-left: 0; } -.themes-grid > .theme:nth-last-child(-n + 3) { border-bottom: 0; } -.theme-num { - font-family: var(--font-mono); - font-size: 10px; - letter-spacing: 0.2em; - color: var(--accent); - text-transform: uppercase; -} -.theme-title { - font-family: var(--font-sans); - font-weight: 700; - font-size: 17px; - color: var(--fg); - margin: 0; -} -.theme-desc { - font-family: var(--font-sans); - font-size: 13px; - line-height: 1.5; - color: var(--fg-muted); - margin: 0; -} - /* ---- Travel ---------------------------------------------- */ .travel-head { display: flex; @@ -723,10 +655,15 @@ input, } .projects-title { font-family: var(--font-display); - font-size: clamp(48px, 7vw, 100px); + /* Floor is 32px for the same reason as .hero-title: below ~686px the vw term + stops binding. "Context//Collapse." is one unbreakable token, so at 48px it + spilled out of its box on phones. break-word is the backstop for any future + long title. Unchanged above ~686px. */ + font-size: clamp(32px, 7vw, 100px); line-height: 0.9; letter-spacing: -0.04em; margin: 0; + overflow-wrap: break-word; } .projects-blurb { font-family: var(--font-sans); @@ -810,6 +747,47 @@ input, left: 0; color: var(--accent); } +/* Cards that link out are anchors — strip link styling, restore keyboard focus. */ +.work-card.is-linked { + text-decoration: none; + color: inherit; +} +.work-card.is-linked:focus-visible { + outline: var(--bw-2) solid var(--accent); + outline-offset: 3px; + border-color: var(--accent); +} +.work-card.is-linked:focus-visible .work-name { color: var(--accent); } +.work-link { + margin-top: auto; + padding-top: var(--s-3); + font-family: var(--font-mono); + font-size: 11px; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--fg-low); + transition: color var(--dur-fast) var(--ease-out); +} +.work-card.is-linked:hover .work-link, +.work-card.is-linked:focus-visible .work-link { color: var(--accent); } + +/* ---- Writing --------------------------------------------- */ +.writing-all { + display: inline-block; + margin-top: var(--s-6); + font-family: var(--font-mono); + font-size: 12px; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--fg-muted); + text-decoration: none; + border-bottom: var(--bw-1) solid var(--rule); + padding-bottom: 4px; + transition: color var(--dur-fast) var(--ease-out), + border-color var(--dur-fast) var(--ease-out); +} +.writing-all:hover, +.writing-all:focus-visible { color: var(--accent); border-color: var(--accent); } /* ---- Contact --------------------------------------------- */ .contact-grid { @@ -830,7 +808,10 @@ input, } .contact-tracked { font-family: var(--font-mono); - font-size: 14px; + /* Wide tracking makes this ~370px at 14px, which a narrow grid column can't + shrink below — it pushed the whole page into horizontal scroll on phones. + Scales below ~540px; identical at 14px on anything wider. */ + font-size: clamp(9px, 2.6vw, 14px); letter-spacing: 0.42em; color: var(--accent); text-transform: uppercase; @@ -1117,14 +1098,41 @@ input, .resume-body, .projects-grid, .travel-grid { grid-template-columns: 1fr; gap: var(--s-6); } - .themes-grid { grid-template-columns: 1fr; } - .theme { - border-right: 0 !important; - padding-left: 0 !important; - padding-right: 0 !important; + /* Grid items default to min-width:auto and refuse to shrink below their + content — one wide child then pushes the page into horizontal scroll. */ + .hero-head > *, + .hero-meta > *, + .contact-grid > *, + .resume-body > *, + .projects-grid > *, + .travel-grid > * { min-width: 0; } + /* Nav links used to be display:none here, which left mobile with no way + to reach any section. Scroll them horizontally instead. */ + .site-nav { flex-wrap: wrap; gap: var(--s-3); } + .nav-links { + order: 3; + width: 100%; + overflow-x: auto; + flex-wrap: nowrap; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + padding-bottom: 4px; } - .nav-links { display: none; } + .nav-links::-webkit-scrollbar { display: none; } + .nav-link { white-space: nowrap; } .timeline-row { grid-template-columns: 1fr; gap: 6px; } .continent-row { grid-template-columns: 120px 1fr 36px; } .hero-portrait { max-width: 100%; justify-self: stretch; } } + +/* reCAPTCHA renders a fixed 304px iframe that Google gives no way to resize, + so below ~360px it pushes the whole page sideways. Scale it to fit; the + height override keeps the shrunken widget from leaving a gap, since a + transform doesn't shrink the layout box. */ +@media (max-width: 359px) { + .form-captcha { + transform: scale(0.85); + transform-origin: left top; + height: 66px; + } +} diff --git a/app/layout.tsx b/app/layout.tsx index eea0e4f..48c5c3a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -49,11 +49,11 @@ export const metadata: Metadata = { template: "%s | Dom Mangonon", }, description: - "Personal website of Dom Mangonon — technology leader specializing in enterprise transformation, AI strategy, and financial services.", + "Dom Mangonon builds software with AI — SousIQ, Bracketeer, the Claude Code Placemat, and more. Projects, writing, and a travel map.", openGraph: { title: "Dom Mangonon", description: - "Technology leader specializing in enterprise transformation, AI strategy, and financial services.", + "Building software with AI. Projects, writing, and a travel map.", url: SITE_URL, siteName: "Dom Mangonon", type: "website", @@ -84,15 +84,12 @@ export default function RootLayout({ "@type": "Person", name: "Dom Mangonon", url: SITE_URL, - jobTitle: "SVP, Transformation Senior Lead", - worksFor: { - "@type": "Organization", - name: "Citi", - }, + description: "Builds software with AI.", sameAs: [ "https://linkedin.com/in/dommangonon", "https://x.com/collapsecontext", "https://dommangonon.substack.com", + "https://github.com/dommango", ], }), }} diff --git a/components/ErrorBoundary.tsx b/components/ErrorBoundary.tsx deleted file mode 100644 index 1aa64a8..0000000 --- a/components/ErrorBoundary.tsx +++ /dev/null @@ -1,74 +0,0 @@ -'use client' - -import React from 'react' -import { Section } from './ui/Section' - -interface ErrorBoundaryProps { - children: React.ReactNode -} - -interface ErrorBoundaryState { - hasError: boolean - error: Error | null -} - -export class ErrorBoundary extends React.Component< - ErrorBoundaryProps, - ErrorBoundaryState -> { - constructor(props: ErrorBoundaryProps) { - super(props) - this.state = { - hasError: false, - error: null - } - } - - static getDerivedStateFromError(error: Error): ErrorBoundaryState { - return { - hasError: true, - error - } - } - - componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { - console.error('Error boundary caught:', error) - console.error('Error info:', errorInfo) - } - - handleReset = () => { - this.setState({ - hasError: false, - error: null - }) - } - - render() { - if (this.state.hasError) { - return ( -
-
-
- ⚠️ -
-

- Something went wrong -

-

- {this.state.error?.message || 'An unexpected error occurred'} -

- -
-
- ) - } - - return this.props.children - } -} diff --git a/components/chat/ChatBot.tsx b/components/chat/ChatBot.tsx index 89d3730..c7d40ab 100644 --- a/components/chat/ChatBot.tsx +++ b/components/chat/ChatBot.tsx @@ -17,7 +17,8 @@ export function ChatBot() { { id: 'welcome', role: 'assistant', - content: "Hi! I'm Dom's AI assistant. Ask me about his career, skills, travel adventures, or this website!", + content: + "Hi — I'm Dom's AI assistant. Ask me about anything he's built (SousIQ, Bracketeer, the Claude Code Placemat), his writing, or the travel map.", timestamp: new Date() } ]) diff --git a/components/contact/ResumeRequestForm.tsx b/components/contact/ResumeRequestForm.tsx deleted file mode 100644 index 5fb8ff0..0000000 --- a/components/contact/ResumeRequestForm.tsx +++ /dev/null @@ -1,222 +0,0 @@ -'use client' - -import { useState, FormEvent } from 'react' -import { Button } from '@/components/ui/Button' -import { Card, CardBody } from '@/components/ui/Card' -import { sendResumeEmail, initEmailJS } from '@/lib/services/emailjs' -import { FORM_LIMITS } from '@/lib/constants' - -interface FormData { - name: string - email: string -} - -interface FormErrors { - name?: string - email?: string -} - -// Initialize EmailJS on component mount -if (typeof window !== 'undefined') { - initEmailJS() -} - -export function ResumeRequestForm() { - const [formData, setFormData] = useState({ - name: '', - email: '' - }) - const [errors, setErrors] = useState({}) - const [isSubmitting, setIsSubmitting] = useState(false) - const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle') - const [submitMessage, setSubmitMessage] = useState('') - - /** - * Validate form inputs - */ - function validateForm(): boolean { - const newErrors: FormErrors = {} - - // Validate name - if (!formData.name.trim()) { - newErrors.name = 'Name is required' - } else if (formData.name.length < FORM_LIMITS.NAME.MIN) { - newErrors.name = `Name must be at least ${FORM_LIMITS.NAME.MIN} characters` - } else if (formData.name.length > FORM_LIMITS.NAME.MAX) { - newErrors.name = `Name must be under ${FORM_LIMITS.NAME.MAX} characters` - } - - // Validate email - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - if (!formData.email.trim()) { - newErrors.email = 'Email is required' - } else if (!emailRegex.test(formData.email)) { - newErrors.email = 'Please enter a valid email address' - } else if (formData.email.length > FORM_LIMITS.EMAIL.MAX) { - newErrors.email = `Email must be under ${FORM_LIMITS.EMAIL.MAX} characters` - } - - setErrors(newErrors) - return Object.keys(newErrors).length === 0 - } - - /** - * Handle form submission - */ - async function handleSubmit(e: FormEvent) { - e.preventDefault() - - // Reset status - setSubmitStatus('idle') - setSubmitMessage('') - - // Validate - if (!validateForm()) { - return - } - - setIsSubmitting(true) - - try { - const response = await sendResumeEmail({ - toName: formData.name, - toEmail: formData.email - }) - - if (response.success) { - setSubmitStatus('success') - setSubmitMessage(response.message) - // Reset form - setFormData({ name: '', email: '' }) - } else { - setSubmitStatus('error') - setSubmitMessage(response.message) - } - } catch (error) { - setSubmitStatus('error') - setSubmitMessage('An unexpected error occurred. Please try again.') - } finally { - setIsSubmitting(false) - } - } - - /** - * Handle input changes - */ - function handleChange(field: keyof FormData, value: string) { - setFormData(prev => ({ ...prev, [field]: value })) - // Clear error for this field when user starts typing - if (errors[field]) { - setErrors(prev => { - const newErrors = { ...prev } - delete newErrors[field] - return newErrors - }) - } - } - - return ( - - -
- {/* Name Input */} -
- - handleChange('name', e.target.value)} - disabled={isSubmitting} - className={` - w-full px-4 py-2.5 rounded-md - bg-surface-2 border - text-foreground placeholder-text-muted - focus:outline-none focus:ring-2 focus:ring-accent-gold/50 focus:border-accent-gold - disabled:opacity-50 disabled:cursor-not-allowed - transition-colors - ${errors.name ? 'border-red-500' : 'border-border'} - `} - placeholder="Your full name" - aria-invalid={errors.name ? 'true' : 'false'} - aria-describedby={errors.name ? 'name-error' : undefined} - /> - {errors.name && ( -

- {errors.name} -

- )} -
- - {/* Email Input */} -
- - handleChange('email', e.target.value)} - disabled={isSubmitting} - className={` - w-full px-4 py-2.5 rounded-md - bg-surface-2 border - text-foreground placeholder-text-muted - focus:outline-none focus:ring-2 focus:ring-accent-gold/50 focus:border-accent-gold - disabled:opacity-50 disabled:cursor-not-allowed - transition-colors - ${errors.email ? 'border-red-500' : 'border-border'} - `} - placeholder="your.email@example.com" - aria-invalid={errors.email ? 'true' : 'false'} - aria-describedby={errors.email ? 'email-error' : undefined} - /> - {errors.email && ( -

- {errors.email} -

- )} -
- - {/* Submit Button */} - - - {/* Success/Error Messages */} - {submitStatus === 'success' && ( -
- {submitMessage} -
- )} - - {submitStatus === 'error' && ( -
- {submitMessage} -
- )} -
-
-
- ) -} diff --git a/components/education/EducationSection.tsx b/components/education/EducationSection.tsx deleted file mode 100644 index 8b08526..0000000 --- a/components/education/EducationSection.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Card, CardHeader, CardBody } from '@/components/ui/Card' -import { Badge } from '@/components/ui/Badge' -import { Degree } from '@/lib/content/education' - -interface EducationSectionProps { - degrees: Degree[] -} - -export function EducationSection({ degrees }: EducationSectionProps) { - return ( -
- {degrees.map(degree => ( - - -
-
-

- {degree.degree} -

-
- {degree.school} - {degree.field && ` \u2022 ${degree.field}`} -
-
-
- {degree.graduation_year} -
-
- {degree.gpa && ( -
- GPA: {degree.gpa} -
- )} -
- {degree.content && ( - -
- {degree.content.split('\n\n')[0]} -
-
- )} -
- ))} -
- ) -} diff --git a/components/landing/BrutalistLanding.tsx b/components/landing/BrutalistLanding.tsx index b830ce1..f3d73eb 100644 --- a/components/landing/BrutalistLanding.tsx +++ b/components/landing/BrutalistLanding.tsx @@ -6,10 +6,13 @@ import { useEffect, useState } from 'react' import { Nav, type ThemeMode, type SectionId } from './Nav' import { Availability } from './Availability' import { Hero } from './Hero' +import { Projects } from './Projects' +import { Writing } from './Writing' import { Travel, type ContinentBar } from './Travel' import { Contact } from './Contact' import { Resume } from './Resume' import { Footer } from './Footer' +import { hasPosts } from '@/lib/content/writing' import type { Country, FlightRoute } from '@/lib/content/travel' export interface LandingTravelData { @@ -21,7 +24,11 @@ export interface LandingTravelData { totalFlights: number } -const SECTION_IDS: SectionId[] = ['hero', 'resume', 'contact', 'travel'] +// Must match DOM order: the scroll-spy below takes the LAST section whose +// offsetTop has passed, so a mismatch misreports the active link silently. +// 'writing' is absent from the DOM when there are no posts; the spy's +// null-check handles that, and Nav gates its link on the same predicate. +const SECTION_IDS: SectionId[] = ['hero', 'projects', 'writing', 'resume', 'travel', 'contact'] function scrollToSection(id: SectionId) { document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' }) @@ -57,15 +64,24 @@ export function BrutalistLanding({ travel }: { travel: LandingTravelData }) { scrollToSection(id) } + const showWriting = hasPosts() + return (
-
diff --git a/components/landing/Contact.tsx b/components/landing/Contact.tsx index dcabff2..b238eb3 100644 --- a/components/landing/Contact.tsx +++ b/components/landing/Contact.tsx @@ -58,7 +58,7 @@ export function Contact() {
- Section / 03 — Contact + Contact

Let's
diff --git a/components/landing/Hero.tsx b/components/landing/Hero.tsx index 760f9f8..8584794 100644 --- a/components/landing/Hero.tsx +++ b/components/landing/Hero.tsx @@ -1,69 +1,23 @@ -// Hero — display headline, headshot, about copy, career arc, six career themes. +// Hero — headline, headshot, and a short bio. Everything else moved out: +// the projects below make the case that a themes grid used to assert. import Image from 'next/image' import { BinaryRule } from './BinaryRule' -const THEMES = [ - { - num: '01', - title: 'Translating complex into simple', - desc: 'Translator by instinct: regulatory mandates, executive questions, and fragmented data become dashboards, BRDs, and decisions teams act on.', - }, - { - num: '02', - title: 'Building the machines, not just running them', - desc: 'Systems over tasks: reusable pipelines, governance frameworks, and data architectures designed to outlast individual involvement.', - }, - { - num: '03', - title: 'Executing in the Grey', - desc: 'Ambiguity-native: unmapped requirements, missing enterprise systems, and shifting deadlines are the environment of choice.', - }, - { - num: '04', - title: 'Quantitatively curious', - desc: 'Evidence-first: every framework built on traceable data, documented logic, and defensible assumptions, not opinion.', - }, - { - num: '05', - title: 'Ship under pressure', - desc: 'Gap-closer: fixed deadlines and missing solutions trigger building the working artifact, documenting it, and handing it off cleanly.', - }, - { - num: '06', - title: 'Human-AI collaboration', - desc: 'AI-native operator: repeatable human-AI workflows that multiply output without multiplying headcount.', - }, -] - -const CAREER_ARC = [ - { label: 'Rutgers · BS Finance', meta: 'FINANCE · 2004–08' }, - { label: 'Bear Stearns', meta: 'SALES INTERN · 2006' }, - { label: 'Viacom', meta: 'CORP FINANCE · 2007' }, - { label: 'BNP Paribas', meta: 'OPERATIONS · 2008–13' }, - { label: 'CMU Tepper · MBA', meta: '3.68 · 2013–15' }, - { label: 'PwC / Strategy&', meta: 'STRATEGY · 2014–17' }, - { label: 'Treliant', meta: 'ADVISORY · 2018–19' }, - { label: 'Morgan Stanley', meta: 'WM STRATEGY · 2019–20' }, - { label: 'Citi', meta: 'SVP TRANSFORM · 2021→' }, -] - export function Hero() { return (
- Section / 01 — Intro + Intro

- Harnessing AI + Unapologetically
- in financial -
- services. + AI-pilled.

- 17 Years in Strategy & Operations,{' '} - Now Building at the Frontier + Growing enterprise AI adoption at Citi by day,{' '} + doing my best to keep up at the frontier by night

@@ -83,44 +37,16 @@ export function Hero() {
About

- Senior financial-services executive with 17 years across enterprise transformation, - strategy consulting, and trading operations. Currently SVP at Citi, leading - enterprise transformation and risk/control framework work. + Seventeen years in financial services — operations at BNP Paribas through 2008, an MBA + at CMU Tepper, consulting at PwC, and now SVP at Citi.

- Started in operations at BNP Paribas through the 2008 crisis, MBA at CMU Tepper, - consulting at PwC/Strategy&, wealth-management strategy at Morgan Stanley, and now - Citi. Long-time builder — VBA macros, Hot Keys workshops, automation at every stop. In - 2025 I went all in on AI: 9 measured Claude projects, 33.9 hours saved, and this site - built end to end with Claude Code. + In 2025 I went all in on AI and started shipping actual software: a restaurant cost + tracker, a tournament bracket engine, an SEC filings pipeline. All built with Claude + Code, including this site. The projects below are real, deployed, and mostly still + running.

-
- Career arc -
    - {CAREER_ARC.map((row) => ( -
  • - {row.label} - {row.meta} -
  • - ))} -
-
-
- - - -
- Career themes · what compounds -
- {THEMES.map((theme) => ( -
- {theme.num} -

{theme.title}

-

{theme.desc}

-
- ))} -
) diff --git a/components/landing/Nav.tsx b/components/landing/Nav.tsx index 9fa35c2..ffdbee2 100644 --- a/components/landing/Nav.tsx +++ b/components/landing/Nav.tsx @@ -2,7 +2,7 @@ // toggle that cycles Gold (default) → Oxblood → High Contrast. export type ThemeMode = 'gold' | 'oxblood' | 'contrast' -export type SectionId = 'hero' | 'resume' | 'contact' | 'travel' +export type SectionId = 'hero' | 'projects' | 'writing' | 'resume' | 'travel' | 'contact' const MODE_LABEL: Record = { gold: 'Gold', @@ -15,9 +15,11 @@ interface NavProps { mode: ThemeMode onCycleMode: () => void onNavigate: (id: SectionId) => void + /** Writing renders only when there are posts; its link must be gated the same way. */ + showWriting: boolean } -export function Nav({ section, mode, onCycleMode, onNavigate }: NavProps) { +export function Nav({ section, mode, onCycleMode, onNavigate, showWriting }: NavProps) { const link = (id: SectionId, label: string) => (
{link('hero', 'Intro')} - {link('resume', 'Resume')} - {link('contact', 'Contact')} + {link('projects', 'Projects')} + {showWriting && link('writing', 'Writing')} + {link('resume', 'Career')} {link('travel', 'Travel')} + {link('contact', 'Contact')}
- -
- - ) : ( - - )} - -
    -
  • - Format - PDF -
  • -
  • - Languages - EN -
  • -
  • - Updated - Q2 2026 -
  • -
+ + LinkedIn ↗ +

diff --git a/components/landing/Travel.tsx b/components/landing/Travel.tsx index 1fbf382..7cb746a 100644 --- a/components/landing/Travel.tsx +++ b/components/landing/Travel.tsx @@ -55,7 +55,7 @@ export function Travel({
- Section / 04 — Travel + Travel

{totalCountries}+ countries.
diff --git a/components/landing/Writing.tsx b/components/landing/Writing.tsx new file mode 100644 index 0000000..8cb6325 --- /dev/null +++ b/components/landing/Writing.tsx @@ -0,0 +1,55 @@ +// Writing — recent Substack posts. Renders only when there are posts; +// the Nav link is gated on the same predicate in BrutalistLanding. +import { POSTS, SUBSTACK_URL } from '@/lib/content/writing' +import { BinaryRule } from './BinaryRule' + +const formatDate = (iso: string): string => { + const parsed = new Date(iso) + if (Number.isNaN(parsed.getTime())) return '' + return parsed.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + timeZone: 'UTC', + }) +} + +export function Writing() { + return ( +
+ +
+ Writing +

Context//Collapse.

+

+ Notes on building with AI — what worked, what broke, and the occasional bit of slop. + Published on Substack. +

+
+ + + + + All posts on Substack ↗ + +
+ ) +} diff --git a/components/layout/Footer.tsx b/components/layout/Footer.tsx deleted file mode 100644 index 04660a2..0000000 --- a/components/layout/Footer.tsx +++ /dev/null @@ -1,109 +0,0 @@ -interface FooterProps { - profile?: { - linkedin?: string - twitter?: string - substack?: string - github?: string - } -} - -export function Footer({ profile }: FooterProps) { - const currentYear = new Date().getFullYear() - - return ( -
-
-
- {/* Social Links */} -
- {profile?.linkedin && ( - - - - - - )} - - {profile?.twitter && ( - - - - - - )} - - {profile?.substack && ( - - - - - - )} - - {profile?.github && ( - - - - - - )} -
- - {/* Copyright */} -

- © {currentYear} Dominic Mangonon. All rights reserved. -

- - - Changelog - -
-
-
- ) -} diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx deleted file mode 100644 index 5b62949..0000000 --- a/components/layout/Header.tsx +++ /dev/null @@ -1,88 +0,0 @@ -'use client' - -import Link from 'next/link' -import { useState } from 'react' -import { clsx } from 'clsx' - -const navigation = [ - { name: 'Home', href: '/' }, - { name: 'Career', href: '/career' }, - { name: 'Skills', href: '/skills' }, - { name: 'Education', href: '/education' }, - { name: 'Travel', href: '/travel' }, - { name: 'Contact', href: '/contact' }, -] - -export function Header() { - const [isOpen, setIsOpen] = useState(false) - - return ( -
- - - {/* Mobile Navigation */} -
-
- {navigation.map(item => ( - setIsOpen(false)} - > - {item.name} - - ))} -
-
-
- ) -} diff --git a/components/profile/CareerThemes.tsx b/components/profile/CareerThemes.tsx deleted file mode 100644 index d42c8a3..0000000 --- a/components/profile/CareerThemes.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Section, SectionHeader } from '@/components/ui/Section' -import { Card, CardBody } from '@/components/ui/Card' -import { CareerTheme } from '@/lib/content/profile' - -interface CareerThemesProps { - themes: CareerTheme[] -} - -export function CareerThemes({ themes }: CareerThemesProps) { - if (themes.length === 0) { - return null - } - - return ( -
-
- Career Themes -
- {themes.map((theme, index) => ( - - -

- {theme.title} -

-

- {theme.description} -

-
-
- ))} -
-
-
- ) -} diff --git a/components/profile/ProfileHero.tsx b/components/profile/ProfileHero.tsx deleted file mode 100644 index 12005aa..0000000 --- a/components/profile/ProfileHero.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import Image from 'next/image' - -interface ProfileHeroProps { - name: string - headline: string - location: string - travel?: string -} - -export function ProfileHero({ - name, - headline, - location, - travel, -}: ProfileHeroProps) { - return ( -
- {/* Subtle decorative gold glow */} -
- -
-
- {/* Profile Image */} -
- {name} -
- -

- {name} -

-
- {location && ( - - - - - {location} - - )} - {travel && ( - - - - - {travel} - - )} -
-
-
-
- ) -} diff --git a/components/profile/ProfileSummary.tsx b/components/profile/ProfileSummary.tsx deleted file mode 100644 index 2a0d2e5..0000000 --- a/components/profile/ProfileSummary.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Section, SectionHeader } from '@/components/ui/Section' - -interface ProfileSummaryProps { - summary: string -} - -export function ProfileSummary({ summary }: ProfileSummaryProps) { - return ( -
-
- Professional Summary -
-

- {summary} -

-
-
-
- ) -} diff --git a/components/skills/SkillsGrid.tsx b/components/skills/SkillsGrid.tsx deleted file mode 100644 index 3c45a4e..0000000 --- a/components/skills/SkillsGrid.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Card, CardHeader, CardBody } from '@/components/ui/Card' -import { SkillItem } from '@/lib/content/skills' - -interface SkillsGridProps { - category: string - skills: SkillItem[] -} - -export function SkillsGrid({ category, skills }: SkillsGridProps) { - return ( -
-

{category}

-
- {skills.map((skill, index) => ( - - -
-

{skill.name}

- - {skill.proficiency} - -
-
- {skill.evidence && ( - - {skill.evidence} - - )} -
- ))} -
-
- ) -} diff --git a/components/timeline/Timeline.tsx b/components/timeline/Timeline.tsx deleted file mode 100644 index 5e1232c..0000000 --- a/components/timeline/Timeline.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import Image from 'next/image' -import { Card, CardHeader, CardBody } from '@/components/ui/Card' -import { Badge } from '@/components/ui/Badge' -import { Role } from '@/lib/content/roles' -import { format } from 'date-fns' - -interface TimelineProps { - roles: Role[] -} - -function CompanyLogo({ logo, company }: { logo?: string; company: string }) { - if (logo) { - return ( - {`${company} - ) - } - - const initials = company - .split(/[\s,&.]+/) - .filter(Boolean) - .slice(0, 2) - .map(word => word[0].toUpperCase()) - .join('') - - return ( - - ) -} - -export function Timeline({ roles }: TimelineProps) { - return ( -
- {roles.map(role => ( - - {/* Gold accent bar */} -
- -
-
-

- {role.title} -

-
- - - {role.company} - {role.location && ` \u2022 ${role.location}`} - -
-
-
- {format(new Date(role.start_date), 'MMM yyyy')} -{' '} - {role.end_date === 'present' - ? 'Present' - : format(new Date(role.end_date), 'MMM yyyy')} -
-
-
- -
- {role.content.split('\n\n')[0]} -
- {role.skills && role.skills.length > 0 && ( -
- {role.skills.slice(0, 5).map(skill => ( - - {skill} - - ))} - {role.skills.length > 5 && ( - - +{role.skills.length - 5} more - - )} -
- )} -
- - ))} -
- ) -} diff --git a/components/travel/CountryCard.tsx b/components/travel/CountryCard.tsx deleted file mode 100644 index 3612e50..0000000 --- a/components/travel/CountryCard.tsx +++ /dev/null @@ -1,73 +0,0 @@ -'use client' - -import { Card } from '@/components/ui/Card' -import { Badge } from '@/components/ui/Badge' -import { Country } from '@/lib/content/travel' - -interface CountryCardProps { - country: Country - onClick?: () => void -} - -export function CountryCard({ country, onClick }: CountryCardProps) { - return ( -
{ - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault() - onClick() - } - } - : undefined - } - > - -
- -
-

- {country.name} -

-
- First visited: {country.firstVisited} - - - {country.continent} - -
-

- #{country.order} in chronological order -

-
-
-
-
- ) -} - -interface CountryGridProps { - countries: Country[] - onCountryClick?: (country: Country) => void -} - -export function CountryGrid({ countries, onCountryClick }: CountryGridProps) { - return ( -
- {countries.map(country => ( - onCountryClick?.(country)} - /> - ))} -
- ) -} diff --git a/components/travel/TravelStats.tsx b/components/travel/TravelStats.tsx deleted file mode 100644 index 1fcfa9f..0000000 --- a/components/travel/TravelStats.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Card } from '@/components/ui/Card' -import { TravelStats as TravelStatsType } from '@/lib/content/travel' - -interface TravelStatsProps { - stats: TravelStatsType - recentCountry?: { - name: string - flag: string - year: number - } -} - -export function TravelStats({ stats, recentCountry }: TravelStatsProps) { - const statCards = [ - { - label: 'Countries Visited', - value: stats.totalCountries, - description: 'Across 5 continents' - }, - { - label: 'Continents', - value: stats.continents, - description: stats.continentNames.join(', ') - }, - { - label: 'Years Traveling', - value: stats.lastYear - stats.firstYear + 1, - description: `Since ${stats.firstYear}` - }, - ...(recentCountry - ? [ - { - label: 'Most Recent', - value: `${recentCountry.flag} ${recentCountry.name}`, - description: recentCountry.year.toString() - } - ] - : []) - ] - - return ( -
- {statCards.map((stat, index) => ( - -
-

- {stat.label} -

-

- {stat.value} -

-

- {stat.description} -

-
-
- ))} -
- ) -} diff --git a/components/ui/Badge.tsx b/components/ui/Badge.tsx deleted file mode 100644 index fcb2749..0000000 --- a/components/ui/Badge.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { clsx } from 'clsx' - -interface BadgeProps { - children: React.ReactNode - variant?: 'primary' | 'secondary' | 'accent' | 'outline' - size?: 'sm' | 'md' -} - -export function Badge({ children, variant = 'primary', size = 'md' }: BadgeProps) { - return ( - - {children} - - ) -} diff --git a/components/ui/Button.tsx b/components/ui/Button.tsx deleted file mode 100644 index ca5f2a4..0000000 --- a/components/ui/Button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { clsx } from 'clsx' - -interface ButtonProps extends React.ButtonHTMLAttributes { - children: React.ReactNode - variant?: 'primary' | 'secondary' | 'outline' | 'ghost' - size?: 'sm' | 'md' | 'lg' -} - -export function Button({ - children, - variant = 'primary', - size = 'md', - className, - ...props -}: ButtonProps) { - return ( - - ) -} diff --git a/components/ui/Section.tsx b/components/ui/Section.tsx deleted file mode 100644 index b35807a..0000000 --- a/components/ui/Section.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { clsx } from 'clsx' - -interface SectionProps { - children: React.ReactNode - className?: string - id?: string - variant?: 'default' | 'elevated' | 'highlight' -} - -export function Section({ children, className, id, variant = 'default' }: SectionProps) { - return ( -
- {children} -
- ) -} - -interface SectionHeaderProps { - children: React.ReactNode - subtitle?: string -} - -export function SectionHeader({ children, subtitle }: SectionHeaderProps) { - return ( -
-

- {children} -

- {subtitle && ( -

- {subtitle} -

- )} -
- ) -} diff --git a/content/career/CLAUDE.md b/content/career/CLAUDE.md deleted file mode 100644 index 9fdcebb..0000000 --- a/content/career/CLAUDE.md +++ /dev/null @@ -1,252 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Overview - -This is a **professional experience database** — a structured knowledge base capturing career history, skills, competencies, and interview-ready examples. It's designed to support career development activities: interviews, job applications, performance reviews, and self-assessment. - -Unlike a traditional codebase, this is a **documentation system** organized as interconnected Markdown files with YAML frontmatter for structured metadata. There is no build process, tests, or deployment — the primary "output" is preparation materials extracted from the structured content. - -## Architecture & Data Model - -### Core Directory Structure - -``` -├── profile.md # Professional identity, summary, contact info -├── context.md # Current career positioning (input to materials) -├── roles/ # Employment history (9 roles, reverse chronological) -│ ├── _index.md # Timeline, by industry, by function -│ └── {company}-*.md # Individual role details -├── projects/ # Notable projects with outcomes -│ └── _index.md # Project index and links -├── stories/ # Interview-ready examples (STAR/CAR format) -│ └── _index.md # Stories indexed by competency -├── skills/ # Skills inventory with proficiency levels -│ └── _index.md # Technical, soft, domain skills with evidence -├── targets/ # Job search pipeline (companies under consideration) -│ └── _index.md # Bucketed table with fit_tier, role_archetype, status -├── achievements/ # Timeline of notable accomplishments -├── certifications/ # Professional credentials and training -├── education/ # Degrees, coursework, GPA -│ ├── carnegie-mellon-mba.md -│ ├── rutgers-bs-finance.md -│ └── coursework/_index.md -├── leadership/ # Mentorship, teams led, communities -├── ai-collaborations/ # AI partnership case studies (9 cases, YYYYMMDD-slug.md) -│ └── CLAUDE.md # Processing spec for this directory -├── images/ # Logos and visual assets (DM-LOGO-WB.jpg) -├── source-docs/ # Supporting documents (PDFs, transcripts) -├── _processing/ # Scratch space (currently empty) -└── Mangonon_Dominic_Resume.{pdf,html} # Generated resume artifacts -``` - -### Key Structural Concepts - -**Frontmatter Metadata**: All content files use YAML frontmatter for structured data: - -```markdown ---- -title: "Role Title" -company: "Company Name" -start_date: 2021-09-07 -end_date: present -tags: [tag1, tag2] -skills: [skill1, skill2] ---- -``` - -**Index Files**: Each category has an `_index.md` that serves as a table of contents and cross-reference hub: - -- Provides timelines and tables summarizing content -- Groups content multiple ways (chronological, by industry, by function, by competency) -- Links to individual detailed files -- Identifies patterns and themes - -**Evidence-Based Skills**: The `skills/_index.md` file links skill claims back to specific roles and projects where they were demonstrated (e.g., "Complex-to-Simple Communication: CEO dashboards at Citi"). - -**Tagging System**: Two primary tag taxonomies: - -- **Competencies**: leadership, problem-solving, communication, collaboration, strategic-thinking, execution, innovation -- **Impact Types**: revenue, efficiency, team-growth, customer-satisfaction, technical-excellence - -### Data Relationships - -The database is interconnected via **internal markdown links**: - -- Roles reference relevant skills via links to `../skills/_index.md` -- Stories are indexed by competency in `stories/_index.md` -- Achievements link back to roles that produced them -- Each role file is linked from both `roles/_index.md` and potentially from projects/achievements - -### Target Companies Pipeline - -`targets/_index.md` is the active job-search pipeline (last updated 2026-05-05). It's a single table per bucket, not individual files. - -- **Buckets**: `paraform-tdi` (50 AI-native companies from Paraform's Talent Density Index), `ai-consulting` (services firms with AI practices), `fintech` (financial services operators + adjacent infra/investors). -- **Key fields**: `fit_tier` (A/B/C/pass — blank means not yet reviewed), `role_archetype` (strategy-bizops, transformation, enterprise-gtm, chief-of-staff, product-strategy), `stage` (seed / series-a-b / scale-up / mature), `status` (researching → interested → applied → networking → interviewing → passed / on-hold), `network` (warm intros), `last_touch` (YYYY-MM-DD), `paraform_rank` / `paraform_score` (only for `paraform-tdi`). -- **Workflow**: review rows with blank `fit_tier` first; advance `status` as outreach progresses; record names in `network` when warm intros are identified. - -## Common Development Tasks - -### Adding a New Role - -1. Create file: `roles/{company-descriptive-name}.md` -2. Add frontmatter with: title, company, start_date, end_date, employment_type, level, manager, team_size, tags (enterprise-transformation, regulatory, etc.), skills -3. Structure content: - - Summary (1-2 sentences) - - Key Responsibilities (bulleted list) - - Notable Achievements (organized by category, with metrics/impact) - - Performance History (if available) -4. Update `roles/_index.md`: - - Add row to Timeline table - - Add to appropriate "By Industry" section - - Add to appropriate "By Function" section - - Update Career Progression ascii diagram if needed - -### Adding a Story (Interview Example) - -1. Create file: `stories/{story-slug}.md` -2. Add frontmatter with: title, competency (single), interview_ready: true/false, tags (optional) -3. Structure as STAR or CAR format: - - **Situation**: Context and challenge - - **Task**: Your specific responsibility - - **Action**: What you did - - **Result**: Quantified outcome or learning -4. Update `stories/_index.md`: - - Add to appropriate competency section - - Add to "Interview-Ready" if `interview_ready: true` - -### Updating Skills Inventory - -1. Edit `skills/_index.md` -2. For each skill, provide: - - Name and proficiency level (Expert, Advanced, Intermediate, Practitioner, Developing) - - Evidence link back to specific role or project where demonstrated -3. Organized into: - - Technical Skills (Excel, VBA, SQL, etc.) - - Soft Skills (communication, stakeholder management, etc.) - - Domain Knowledge (regulatory compliance, wealth management, etc.) - -### Adding Education/Certification - -1. Create file: `education/{institution-degree}.md` or `certifications/{cert-name}.md` -2. Include: institution, degree/cert, graduation date, relevant courses/details, GPA -3. Update corresponding `_index.md` file -4. For coursework: add to `education/coursework/_index.md` with course name, grade, relevance - -## Content Guidelines - -### Metadata Standards - -- **Dates**: ISO 8601 format (YYYY-MM-DD), use "present" for current roles -- **Employment Type**: full-time, contractor, intern, part-time -- **Level**: Use company-specific leveling (e.g., "C14 / SVP" for Citi) -- **Team Size**: Number of direct reports or team members managed -- **Proficiency Levels**: Expert, Advanced, Intermediate, Practitioner, Developing -- **Tags**: Use kebab-case (lowercase with hyphens) - -### Writing Style - -- **Role Summaries**: 1-2 sentences, action-oriented -- **Achievements**: Lead with impact (metric/outcome), then mechanism. Format: "Achievement Name - outcome, method" -- **Links**: Use relative markdown links (`../roles/file.md`) for internal references -- **Proficiency Evidence**: Link claims to supporting work (e.g., "[BNP Paribas](../roles/bnp-paribas-client-services.md) - 6 macros for trading desk") - -### Completeness Checklist - -Before considering content ready: - -- [ ] All roles have frontmatter with required fields -- [ ] Index files link to and describe all content -- [ ] Achievement metrics are quantified where possible (%, $M, count) -- [ ] Skills have evidence links back to roles/projects -- [ ] Competency tags align with taxonomy -- [ ] Internal links are valid and relative - -## Usage Patterns - -### For Interview Prep - -1. Browse `stories/_index.md` grouped by competency -2. Check `interview_ready: true` flag to find polished examples -3. Pull context from `roles/_index.md` to understand timeline -4. Reference `skills/_index.md` to discuss proficiency levels - -### For Resume/Application Materials - -1. Use `profile.md` for professional summary language -2. Pull achievements from role files (quantified, impact-focused) -3. Reference `skills/_index.md` to identify relevant skills with evidence -4. Check `education/` and `certifications/` for credentials to highlight - -### For Self-Assessment & Career Planning - -1. Review `education/coursework/` for knowledge areas and confidence levels -2. Use `skills/_index.md` to assess and track proficiency growth -3. Check `leadership/` for team and mentoring experience -4. Analyze `achievements/` for impact patterns and career themes - -## Tools & Queries - -### Find All Roles in an Industry - -- See `roles/_index.md` "By Industry" section -- Example: Financial Services banking roles: Citi, Morgan Stanley, BNP Paribas, Bear Stearns - -### Find Stories by Competency - -- See `stories/_index.md` "By Competency" sections -- All stories tagged with matching competency tag - -### Find Skills with Evidence - -- See `skills/_index.md` organized by Technical, Soft, and Domain -- Each skill includes a link to the role/project demonstrating it - -### Build Interview Story Set - -- Filter `stories/` for `interview_ready: true` -- Verify competency coverage across required domains - -### Adding an AI Collaboration Case Study - -See `ai-collaborations/CLAUDE.md` for the full processing spec. Key points: - -1. Create file: `ai-collaborations/YYYYMMDD-{slug}.md` -2. Frontmatter includes: title, date, primary_theme, ai_functions, leverage_type, confidence_level, estimated_time_saved_hrs, role (link), interview_ready, source_doc -3. Content merges three versions from source PDFs: Internal (business context), Meta (cognitive patterns), Sanitized (portfolio-ready) -4. Use HTML comments (``, ``, ``) to track content origin -5. Update `ai-collaborations/_index.md` with new entry - -**Taxonomies**: themes (automation, governance, product_dev, research, strategy), AI functions (synthesis, generation, analysis, reframing, validation, retrieval, pattern_recognition), leverage types (cognitive, executional, strategic, communicative, automation) - -## File Format Notes - -- All content is **Markdown** with **YAML frontmatter** -- No special processing or build system required -- Internal links use relative paths (`../roles/file.md`) -- When referencing external links (e.g., LinkedIn URLs), use absolute URLs -- Source documents (PDFs, Word docs) are archived in `source-docs/` for reference - -## Career Context - -**Current positioning** (from `context.md`): Exploring opportunities at the intersection of enterprise transformation and AI. Target roles leverage both business acumen and technical curiosity — AI-powered transformation, enterprise AI strategy, building/scaling new capabilities. - -**Career arc**: Operations (BNP) → Strategy Consulting (PwC/Strategy&) → Advisory (Treliant) → Corporate Strategy (Morgan Stanley) → Enterprise Transformation (Citi) - -**Key themes** to reinforce when crafting materials: - -1. **Complex-to-Simple Translation** — synthesizing disorganized info into clear deliverables -2. **Process Optimization & Efficiency** — Hot Keys, VBA macros, streamlined workflows -3. **Regulatory & Risk Expertise** — Consent Order remediation, risk management -4. **Financial Services Breadth** — banking ops, consulting, corporate transformation -5. **Quantitative Foundation** — CMU Tepper MBA, 720 GMAT -6. **AI Partnership** — documented via `ai-collaborations/` (33.9 hrs saved across 9 cases) - -## Repository Notes - -- **Not a git repository** — there is no `.git/` directory. Don't try to `git commit`, `git log`, or `git diff`; changes are saved in place. -- **No build system** — `package.json` is empty. Content is consumed manually or synced into a separate personal-website project (see the `sync-career-content.js` reference in `ai-collaborations/CLAUDE.md`). -- **Resume artifacts** — `Dominic_Mangonon_Resume.pdf` and `Mangonon_Dominic_Resume.html` at the repo root are generated outputs, not sources. Source content lives in `profile.md`, `roles/`, `skills/`, etc. -- **`_processing/`** is a scratch directory, currently empty. diff --git a/content/career/Mangonon_Dominic_Resume.html b/content/career/Mangonon_Dominic_Resume.html deleted file mode 100644 index c2dc937..0000000 --- a/content/career/Mangonon_Dominic_Resume.html +++ /dev/null @@ -1,516 +0,0 @@ - - - - - - Dominic Mangonon - Resume - - - -
-

DOMINIC MANGONON

-
- New York Metropolitan Area | +1 (908) 313 - 3302
- dom.mangonon@gmail.com | - dommango.github.io | - linkedin.com/in/dominicmangonon -
-
- -
PROFESSIONAL SUMMARY
-

- Senior financial services executive with 17 years of experience spanning - strategy, enterprise transformation, regulatory remediation, and complex - operating model change across global institutions. Currently serves as an - execution lead for the Citi's highest priority firm-wide initiatives, - including critical regulatory commitments and the transformation of the - enterprise risk and control framework. Recognized for translating complex - challenges into clear governance and delivery models, strengthening - execution discipline, and systematically applying AI-enabled solutions to - automate workflows, enhance decision making, and scale operational - efficiencies. -

- -
EXPERIENCE
- -
-
- CITI - New York, NY -
-
- Senior Vice President, Citi Transformation Senior Lead (03/2022 – - Present) - 2021 - Present -
-
- Contractor / Consultant via Matrix Resources (09/2021 – - 03/2022) - -
-

- Enterprise Transformation: Serve - as a key execution lead on the firm's - highest-priority strategic initiatives, from regulatory - Consent Order remediation to the transformation of the enterprise risk - and control framework -

-
    -
  • - Developed and delivered - three strategic dashboards for the CEO and Board of - Directors, reconciling data sources and taxonomies across Citi's - business lines and functions to deliver impactful insights required - for executive decision-making -
  • -
  • - Improved the quality and timeliness of regulatory remediation across - Citi by designing and launching a - new senior oversight function and committee to - centralize governance and implement standardized requirements for all - Matters Requiring Attention (MRAs) -
  • -
  • - Established and oversaw implementation of new global standards for - program and project management, strengthening unified oversight and - controls for an - enterprise-wide portfolio of 15,000+ projects -
      -
    • - Recruited and managed a team of two direct reports and led - cross-functional working groups to define and implement the - standardized requirements for reporting and quality assurance -
    • -
    • - Secured on-time closure of - 4+ critical regulatory commitments by - successfully validating sustainability of new and enhanced - controls with firm risk and audit partners -
    • -
    -
  • -
  • - Overhauled the financial governance framework for a - $9B technology and business investment portfolio - through the design and implementation of new standardized requirements - for cost estimation, tracking, and variance analysis, directly - improving on-budget project delivery -
      -
    • - Led efforts to re-engineer data architecture for over 150 - strategic investments to provide visibility into - ~$1.1B of investment spend -
    • -
    • - Leveraged AI-powered tools to "vibecode" - solutions to manual End User Computing (EUC) processes, - streamlining execution and report of controls including generation - of supporting procedures and guidance materials -
    • -
    -
  • -
  • - Developed 3 module AI @ Citi 102 learning series - covering advanced enterprise AI topics including context engineering, - workflow automation, and multi-tool integration across Citi's AI - platforms -
  • -
-
- -
-
- MORGAN STANLEY - New York, NY -
-
- Assistant Vice President, Corporate & Institutional Solutions - 2019 – 2020 -
-

- Business Unit Strategy: Led a - portfolio of projects to build and pilot a new business model targeted - to the firm's ultra-high-net-worth end family office client segment, - resulting in ~$15B of new assets under management (AUM) -

-
    -
  • - Designed and launched a concierge service model to - meet the complex needs (e.g., onboarding, analytics, reporting) of the - firm's largest wealth management clients -
  • -
  • - Aligned leadership on the need for expanded trading products and - capabilities; advised on strategic decisioning to - build solutions "in-house" vs. via a third-party partnership -
  • -
  • - Led efforts to pursue a strategic partnership with a leading global - custodian bank; outlined partnership business requirements and oversaw - the RFP / third-party vendor selection process -
  • -
  • - Conducted field and interviews with the firm's top Financial Advisors - to understand client pain points and prioritize firm resources towards - key strategic opportunities and other critical matters -
  • -
  • - Served as a - relationship manager to an early-stage startup and - technology partner, providing recommendations on app development and - advising on business, risk, and regulatory considerations -
  • -
-
- -
-
- TRELIANT, LLC - New York, NY -
-
- Senior Consultant, Wealth & Asset Management Advisory - 2018 – 2019 -
-

- Business Development: Worked with - leadership to develop and launch an advisory practice for a PE-backed - boutique consulting firm -

-
    -
  • - Co-authored 3 white-papers and identified 10 - "go-to-market" campaigns for prospecting new business -
  • -
  • - Managed risk and regulatory engagements which included oversight of - over 40 contracted workers -
  • -
-
- -
-
- STRATEGY& (formerly BOOZ & CO.) — Part of the PWC Network - Chicago, IL -
-
- Senior Associate, Financial Services Strategy Consulting (07/2015 – - 10/2017) - 2014 – 2017 -
-
- MBA Intern, Banking & Capital Markets Management Consulting (06/2014 - – 08/2014) - -
- -

- Target Operating Model: - Identified ~$14M in run rate savings for an - international subsidiary of a leading insurance broker as part of a - global cost and organizational restructuring effort -

-
    -
  • - Worked closely alongside the CFO and other senior leadership to - construct a business case which modeled cost savings & investment - required to centralize operations in both near and offshore sites -
  • -
  • - Led multiple branch workshops to understand business process pain - points and identify both "quick win" and technology-enabled solutions - to optimize operations and increase savings -
  • -
- -

- Market Segmentation: Created a - customer segmentation and migration strategy for a large wealth - management client, increasing advisor capacity & productivity by - ~5% and reducing fiduciary risk by - $465M -

-
    -
  • - Led working sessions with leadership to align on strategic objectives - and define key guiding principles -
  • -
  • - Designed processes, reporting and tools for financial advisors to - review books-of-business, identify migration exceptions and maximize - cross-sell opportunities to other areas within the bank -
  • -
  • - Successfully executed the migration of - 32,000 low-balance clients to self-directed service - channels -
  • -
- -

- Client Experience & Change Management: - Designed an end-to-end experience across the client lifecycle for a - large wealth management firm, working with leadership to create - stakeholder personas, customer journey maps and use cases -

-
    -
  • - Accelerated strategic objectives through the creation of a learning & - development curriculum and segmentation of the financial advisory - population, enabling more-targeted coaching and training -
  • -
  • - Designed an oversight structure to strengthen accountability and align - incentives to goals and metrics -
  • -
- -

- Growth Strategy: Evaluated - organic and M&A related growth opportunities for a leading online - brokerage -

-
    -
  • - Conducted research and analysis to size an opportunity to capture - ~$2T in AUM resulting from an industry shift of - investible assets towards online and independent brokerage models -
  • -
  • - Identified a preliminary list of potential acquisition targets to - complement existing business capabilities and unlock additional - growth, ultimately leading to the - $4B acquisition of a competitor -
  • -
-
- -
-
- BNP PARIBAS CORPORATE & INSTITUTIONAL BANKING - New York, NY -
-
- Client Services Analyst, Commodities Brokerage (07/2010 – - 05/2013) - 2008 – 2013 -
-
- Rotational Analyst, Trading Operations (07/2008 – 07/2010) - -
-

- Operations & Process Optimization: - Supported various trading desks middle / back-office functions as a new - graduate rotational analyst -

-
    -
  • - Facilitated workshops for a Six Sigma initiative resulting in a - realignment of the organizational structure of the Fixed Income - Documentation Team, improving - trade processing time by ~10% -
  • -
  • - Developed process controls and VBA macros to reconcile erroneous - trades, eliminating potential overnight risk exposure and - standardizing reporting procedures to meet with regulatory standards -
  • -
-
- -
EDUCATION
- -
-
- CARNEGIE MELLON UNIVERSITY, TEPPER SCHOOL OF BUSINESS - Pittsburgh, PA -
-
- Master of Business Administration (MBA), Concentrations: Information - Systems, Finance - 2013 – 2015 -
-
- Leadership: Consulting Club (V.P., Member Development), Graduate Student - Assembly (Class Representative), Consortium Fellow, Merit Scholar -
-
- -
-
- RUTGERS UNIVERSITY, RUTGERS BUSINESS SCHOOL - New Brunswick, NJ -
-
- Bachelor of Science (BS), Major: Finance - 2004 – 2008 -
-
- -
ADDITIONAL INFORMATION
- -
-

- Technical Skillsets: MS Office 365 (Expert), Data - modeling tools (PowerQuery, SQL), Large language models and AI (e.g., - Google AI Studio, Anthropic Claude, Notion AI) -

-

- Interests: Travelling (visited over 55 countries / 5 - continents); trekking, snowboarding, live music; DIY electronics & - circuitry, NY sports teams -

-
- - diff --git a/content/career/README.md b/content/career/README.md deleted file mode 100644 index 3554c5b..0000000 --- a/content/career/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Professional Experience Database - -A structured knowledge base capturing my professional history, skills, and experiences. - -## Structure - -| Directory | Contents | -|-----------|----------| -| `profile.md` | Professional identity, summary, and contact | -| `roles/` | Employment history with responsibilities and achievements | -| `projects/` | Notable projects with outcomes and impact | -| `stories/` | Interview-ready stories (STAR, CAR, narrative) | -| `skills/` | Skills inventory with evidence links | -| `achievements/` | Notable accomplishments timeline | -| `education/` | Degrees and coursework | -| `certifications/` | Professional certifications and training | -| `leadership/` | Mentorship, teams led, communities | - -## File Format - -All files use Markdown with YAML frontmatter for structured metadata: - -```markdown ---- -key: value -tags: [tag1, tag2] ---- - -# Content here -``` - -## Usage - -### Interview Prep -- Browse `stories/` for competency-tagged examples -- Check `stories/_index.md` to find stories by skill/competency -- Look for `interview_ready: true` in frontmatter - -### Application Materials -- Reference `profile.md` for summary language -- Pull achievements from `roles/` and `projects/` -- Use `skills/_index.md` to identify relevant skills with evidence - -### Self-Assessment -- Review `education/coursework/` for knowledge areas -- Check confidence levels on coursework entries -- Use `skills/_index.md` to assess proficiency levels - -## Tagging Taxonomy - -**Competencies:** leadership, problem-solving, communication, collaboration, strategic-thinking, execution, innovation - -**Impact Types:** revenue, efficiency, team-growth, customer-satisfaction, technical-excellence diff --git a/content/career/achievements/_index.md b/content/career/achievements/_index.md deleted file mode 100644 index a92e0a6..0000000 --- a/content/career/achievements/_index.md +++ /dev/null @@ -1,74 +0,0 @@ -# Achievements - -Notable accomplishments organized by timeline and impact type. - -## Timeline - -| Year | Achievement | Context | Evidence | -|------|-------------|---------|----------| -| 2008 | Secured full-time position within 5 weeks of rotational program | BNP Paribas | [Role](../roles/bnp-paribas-rotational.md) | -| 2008 | Reduced unconfirmed credit default swaps during financial crisis | BNP Paribas | [Role](../roles/bnp-paribas-rotational.md) | -| 2008 | Wrote 6 VBA macros for risk exposure and P&L analysis | BNP Paribas | [Role](../roles/bnp-paribas-rotational.md) | -| 2008 | Initiated London project reducing collateral verification time by 30 min/day | BNP Paribas | [Role](../roles/bnp-paribas-rotational.md) | -| 2010-13 | Delivered 20+ client presentations, opened 8 new accounts | BNP Paribas | [Role](../roles/bnp-paribas-client-services.md) | -| 2010-13 | Improved trade processing by ~10% (3 days reduction) via Six Sigma | BNP Paribas | [Role](../roles/bnp-paribas-client-services.md) | -| 2010-13 | Instituted 15+ new reporting tools globally (Paris, London) | BNP Paribas | [Role](../roles/bnp-paribas-client-services.md) | -| 2013 | 1st Place - SCIO Case Competition (Team Lead) | CMU Tepper | [Education](../education/carnegie-mellon-mba.md) | -| 2013 | 2nd Place - McKinsey & Co. Case Competition | CMU Tepper | [Education](../education/carnegie-mellon-mba.md) | -| 2013 | Finalist - ROMBA National Case Competition | CMU Tepper | [Education](../education/carnegie-mellon-mba.md) | -| 2015-17 | Identified ~$4B acquisition target for online brokerage | Strategy& | [Role](../roles/strategy-and-senior-associate.md) | -| 2015-17 | Sized ~$2T AUM opportunity from industry shift | Strategy& | [Role](../roles/strategy-and-senior-associate.md) | -| 2015-17 | Executed migration of 32,000 clients, reducing fiduciary risk by $465M | Strategy& | [Role](../roles/strategy-and-senior-associate.md) | -| 2015-17 | Identified ~$14M run-rate savings for insurance broker | Strategy& | [Role](../roles/strategy-and-senior-associate.md) | -| 2019 | Co-authored 2-part article series on sales practice risk published in ThinkAdvisor | Treliant | [Role](../roles/treliant-senior-consultant.md) | -| 2019 | Identified 10 go-to-market campaigns for wealth management advisory practice | Treliant | [Role](../roles/treliant-senior-consultant.md) | -| 2019 | Managed risk/regulatory engagements with 40+ contracted workers | Treliant | [Role](../roles/treliant-senior-consultant.md) | -| 2019-20 | Led projects for ~$15B new AUM opportunity | Morgan Stanley | [Role](../roles/morgan-stanley-avp.md) | -| 2019-20 | Achieved 40%+ reduction in onboarding time for complex structures | Morgan Stanley | [Story](../stories/concierge-model-innovation.md) | -| 2021+ | Secured on-time closure of 4+ critical regulatory commitments | Citi | [Role](../roles/citi-svp-transformation.md) | -| 2021+ | Re-engineered data architecture for 150+ strategic investments (~$1.1B visibility) | Citi | [Role](../roles/citi-svp-transformation.md) | -| 2021+ | Established global PM standards across 15,000+ projects | Citi | [Role](../roles/citi-svp-transformation.md) | -| 2021+ | Overhauled financial governance for ~$7.1B investment portfolio | Citi | [Role](../roles/citi-svp-transformation.md) | -| 2023 | Design Council alignment achieved, model transitioned to BAU governance | Citi | [Story](../stories/stakeholder-influence-governance.md) | - -## By Impact Type - -### Revenue Impact - -- **~$15B AUM opportunity** - Led projects attributing to new wealth management assets at Morgan Stanley | [Role](../roles/morgan-stanley-avp.md) -- **~$4B acquisition identified** - M&A target identification for online brokerage at Strategy& | [Role](../roles/strategy-and-senior-associate.md) -- **~$2T AUM opportunity sized** - Industry shift analysis at Strategy& | [Role](../roles/strategy-and-senior-associate.md) -- **8 new accounts opened** - Direct result of 20+ client presentations at BNP Paribas | [Role](../roles/bnp-paribas-client-services.md) - -### Efficiency Gains - -- **40%+ onboarding time reduction** - Concierge service model at Morgan Stanley | [Story](../stories/concierge-model-innovation.md) -- **~10% trade processing improvement** - Six Sigma initiative at BNP Paribas (3 days reduction) | [Role](../roles/bnp-paribas-client-services.md) -- **~$14M run-rate savings** - Operating model optimization for insurance broker at Strategy& | [Role](../roles/strategy-and-senior-associate.md) -- **30 minutes daily savings** - Payment ticket formatting project at BNP Paribas | [Role](../roles/bnp-paribas-rotational.md) - -### Risk Reduction - -- **$465M fiduciary risk reduction** - Wealth client migration to robo-advisor channels at Strategy& | [Role](../roles/strategy-and-senior-associate.md) -- **4+ regulatory commitments closed on-time** - Consent Order remediation at Citi | [Role](../roles/citi-svp-transformation.md) -- **Overnight risk eliminated** - Credit default swap management during 2008 crisis at BNP Paribas | [Role](../roles/bnp-paribas-client-services.md) - -### Technical Excellence - -- **15,000+ project portfolio standardized** - Global PM standards at Citi | [Role](../roles/citi-svp-transformation.md) -- **$7.1B investment portfolio governance** - Financial framework overhaul at Citi | [Role](../roles/citi-svp-transformation.md) -- **$1.1B visibility achieved** - Data architecture for 150+ strategic investments at Citi | [Role](../roles/citi-svp-transformation.md) -- **15+ reporting tools instituted** - Global coordination (Paris, London) at BNP Paribas | [Role](../roles/bnp-paribas-client-services.md) -- **6 VBA macros developed** - Risk exposure and P&L analysis at BNP Paribas | [Role](../roles/bnp-paribas-rotational.md) - -### Thought Leadership - -- **2-part article series published in ThinkAdvisor** - "Sales Practice Risk in the Digital Era" on Reg BI, robo-advisor compliance, and risk mitigation at Treliant | [Role](../roles/treliant-senior-consultant.md) - -### Recognition & Awards - -- **1st Place** - 2013 SCIO Case Competition (Team Lead) | [Education](../education/carnegie-mellon-mba.md) -- **2nd Place** - 2013 McKinsey & Co. Case Competition | [Education](../education/carnegie-mellon-mba.md) -- **Finalist** - 2013 ROMBA National Case Competition | [Education](../education/carnegie-mellon-mba.md) -- **Consortium Fellow** - CMU Tepper MBA merit recognition | [Education](../education/carnegie-mellon-mba.md) -- **Merit Scholar** - CMU Tepper merit-based scholarship | [Education](../education/carnegie-mellon-mba.md) diff --git a/content/career/ai-collaborations/20260128-regulatory-sustainability-testing.md b/content/career/ai-collaborations/20260128-regulatory-sustainability-testing.md deleted file mode 100644 index ede47f4..0000000 --- a/content/career/ai-collaborations/20260128-regulatory-sustainability-testing.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -title: "Regulatory Sustainability Testing Documentation" -date: 2026-01-28 -primary_theme: [governance, research] -ai_functions: [analysis, synthesis, validation] -leverage_type: [cognitive, strategic] -confidence_level: 0.95 -estimated_time_saved_hrs: 2.5 -tags: [regulatory, consent-order, sustainability-testing, cao, interview-ready, governance] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf" ---- - -# Regulatory Sustainability Testing Documentation - -AI-assisted structured analysis and documentation of regulatory sustainability testing activities for Consent Order compliance. - ---- - -## Executive Summary - - - -This use case illustrates how generative AI can be applied to retrospectively document complex regulatory work in a precise and reusable way. - -**Core Challenge:** Large regulatory programs generate artifacts that are difficult to translate into accurate, interview-ready narratives. - -**Goal:** Use AI to support structured review, role disambiguation, and drafting of professional summaries without creating or modifying regulatory evidence. - ---- - -## Business Context - - - -This AI use case documents the structured application of generative AI to **produce interview-ready, governance-grade documentation** for completed regulatory workstreams, specifically **sustainability testing and closure activities** under CAO-XIIE.10.3 (Execute Phase) and CAO-XIIE.11.3 (Close Phase). - -The AI was used **after execution**, not to generate regulatory evidence, but to: -- Forensically analyze existing artifacts -- Disambiguate individual vs. team contributions -- Produce precise, defensible summaries suitable for interviews, portfolios, and internal governance records - ---- - -## Business Problem - - - -Regulatory programs produce large volumes of artifacts that: -- Obscure individual contribution -- Conflate design, execution, and oversight roles -- Are difficult to reuse once milestones are closed -- Are not interview-ready - -This creates risk for: -- Talent mobility and succession -- Institutional memory loss -- Inaccurate self-representation in senior interviews - ---- - -## Scope of Artifacts - - - -### In Scope -- CAO-XIIE.10.3 — Sustainability and Testing Results Summary -- CAO-XIIE.11.3 — Sustainability and Testing Results Summary - -### Out of Scope -- Regulatory requirements design -- Original test execution automation -- Creation or modification of regulatory evidence - ---- - -## AI Capabilities Applied - - - -The AI was used for: -- Structured artifact analysis -- Confidence-weighted inference -- Misattribution risk identification -- Forensic clarification questioning -- Drafting interview-ready contribution summaries -- Auditable Markdown artifact generation - -AI was **not** used to generate or modify regulatory evidence. - ---- - -## Human-in-the-Loop Controls - - - -- Mandatory staged workflow -- Explicit labeling of inference vs. fact -- User approval before finalization, memory persistence, and registry updates - ---- - -## Outcomes - - - -- Two interview-ready Markdown summaries -- Updated Work-Samples registry -- Reusable portfolio-grade documentation - ---- - -## Risks & Mitigations - - - -| Risk | Mitigation | -|------|------------| -| Over-attribution | Structured questioning + credibility notes | -| AI hallucination | User-validated facts only | -| Regulatory misuse | Retrospective documentation only | - ---- - -## Compliance & Audit Notes - - - -- No CSI generated -- No regulatory submissions altered -- Internal documentation only - ---- - -## Meta Record - - - -| Field | Value | -|-------|-------| -| Use Case ID | AI-Use-Case_Regulatory-Sustainability-Testing-Documentation | -| Date Created | 2026-01-28 | -| Last Reviewed | 2026-01-28 | - ---- - -## Classification - - - -- Type: Documentation / Knowledge Management -- Domain: Regulatory Remediation -- Lifecycle: Post-Execution -- Risk Tier: Low - ---- - -## AI Capabilities - - - -- Document analysis -- Structured summarization -- Forensic clarification questioning - ---- - -## Data - - - -- Source: User-provided documents -- CSI: No -- PII: No - ---- - -## Controls - - - -- Human-in-the-loop required -- No system write-back - ---- - -## AI Application - - - -AI supported structured review, role disambiguation, and drafting of professional summaries. AI did not create or modify regulatory evidence. - ---- - -## Value - - - -- Accurate articulation of complex work -- Reduced misrepresentation risk -- Reusable professional documentation - ---- - -## Resume-Ready Bullets - -- Applied generative AI to retrospectively document Consent Order sustainability testing activities, producing interview-ready summaries for CAO-XIIE.10.3 and CAO-XIIE.11.3 milestones -- Established a governance-compliant AI workflow with explicit human-in-the-loop controls, separating inference from fact to ensure audit defensibility -- Created reusable documentation patterns for translating complex regulatory artifacts into precise professional narratives suitable for talent mobility and institutional knowledge preservation - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged. diff --git a/content/career/ai-collaborations/20260301-documentation-preset.md b/content/career/ai-collaborations/20260301-documentation-preset.md deleted file mode 100644 index 3d6079c..0000000 --- a/content/career/ai-collaborations/20260301-documentation-preset.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: "AI-Powered Strategic Documentation Preset" -date: 2026-03-01 -primary_theme: [automation, governance, strategy] -ai_functions: [synthesis, reframing, generation, pattern_recognition] -leverage_type: [cognitive, executional, strategic] -confidence_level: 0.95 -estimated_time_saved_hrs: 3.0 -tags: [preset, documentation, workflow, prompt_engineering, meta_analysis, human_ai_collaboration] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI_Collaboration (1-20) - Mar 16 2026 - 10-07 AM.pdf" ---- - -# AI-Powered Strategic Documentation Preset - -Co-developing an automated documentation framework with generative AI to standardize and accelerate post-session knowledge capture. - ---- - -## Executive Summary - - -In a large, innovative enterprise, numerous strategic sessions produce a high volume of critical but unstructured information. Capturing these insights consistently and efficiently is a major operational challenge that hinders scalability and knowledge sharing. - -A conversational, iterative approach was used to engage a generative AI as a co-design partner, not just an execution tool. The strategy involved starting with a high-level concept and progressively refining it into a robust, automated workflow based on cycles of direct feedback and AI-generated improvements. - ---- - -## Business Context - - -The session addressed the critical business need to standardize and accelerate the documentation process following strategic brainstorming sessions. The goal was to eliminate inconsistent, ad-hoc summaries to improve knowledge management, enforce quality standards, and measure the impact of AI collaboration. - -**Initial Challenge:** Strategic insights from brainstorming sessions were being documented in inconsistent formats, leading to knowledge loss, rework, and a significant administrative burden on high-value employees. A scalable, standardized solution was needed to automate this process. - ---- - -## Strategic Framing - - -This initiative directly supports the enterprise goal of operationalizing AI in a governed and scalable manner. By creating a reusable preset, it establishes a consistent, high-quality documentation workflow across projects, enhancing project visibility for leadership and improving overall productivity. - ---- - -## AI Collaboration Approach - -### AI Utilization - -An AI assistant was used as an iterative, collaborative partner to co-design the entire documentation framework. The AI's role evolved from executing an initial request to actively refining the documentation schema, the master prompt, and the strategic workflow itself based on direct user feedback. - -### Iteration and Refinement - -The process involved multiple feedback loops: -1. An initial prompt defined the broad goal -2. The AI generated a first-draft solution -3. Specific, structured feedback was provided to refine the workflow, data schema, and output formats -4. The AI incorporated the feedback to produce an improved version - -This cycle was repeated until a production-ready "master preset" was finalized. - ---- - -## Cognitive Offloading Analysis - - -The entire task of translating the abstract goal ("standardize documentation") into concrete, structured artifacts was offloaded to the AI. This included: -- Designing the initial schema -- Generating multiple document variations -- Suggesting improvements to its own instructions - -**Role Transformation:** The user's role shifted from being a "writer" to being an "editor and strategist." - ---- - -## Framework Generation - - -The AI generated the core framework for the entire process: -- Synthesized user requirements into a three-part documentation structure (Internal, External, Meta) -- Proposed a version-controlled schema -- Recognized and adapted the workflow from a simple "paste-in" model to a more sophisticated "preset" model that analyzes the session's conversation history - ---- - -## Decision Structuring - - -The AI structured the decision-making process by presenting clear, distinct artifacts at each stage (e.g., `Master_Prompt`, `Improved_Schema`). This allowed the user to: -- Evaluate and provide targeted feedback on specific components -- Work through the system in a logical, iterative sequence -- Avoid dealing with a single monolithic block of text - ---- - -## Deliverables Produced - - -1. **Master Prompt** - A session-end preset for consistent documentation generation -2. **Documentation Schema** - Detailed `Revised_Documentation_Schema.pdf` with version control -3. **Document Templates** - Three structured templates: - - Internal: Full enterprise details - - External: Sanitized case study for portfolio/recruiting - - Meta: Process analysis for continuous improvement - ---- - -## Efficiency Impact - -### Quantitative - -- **Time Saved:** 3-4 hours of manual synthesis, writing, and formatting work per strategy session -- **Automation Rate:** ~90% reduction in manual documentation effort - -### Qualitative - -- Framework enforces documentation standards -- Improves clarity and consistency of strategic artifacts for leadership review -- Creates reliable knowledge base for future reference - ---- - -## Prompting Analysis - -### Effective Prompts - -The user's prompts were highly effective because they were: -- **Specific** - Explicit field names and schema requirements (e.g., "remove session id, add AI_Functions") -- **Iterative** - Built upon previous AI responses -- **Transformative** - The shift from "paste-in" workflow to "preset" model fundamentally improved strategic value - -### Key Insight -The most significant moment was the user's clarification to shift from a "paste-in" workflow to a "preset" model, which fundamentally improved the strategic value of the final product. - ---- - -## Future Recommendations - - -1. **Implement Session Markers** - Begin future sessions with explicit commands like `/start_session "Title"` to provide a definitive starting point, preventing context bleed from previous conversations - -2. **Version Control the Preset** - Include version numbers (e.g., `v3.1`) to track changes and correlate prompt improvements with output quality over time - -3. **Automate Metadata Injection** - Develop user interface or command-line flags that automatically inject `ProjectType` and `UseCaseName` when the preset is triggered - ---- - -## Scalability Potential - - -This framework is highly scalable and can be adapted for: -- Project meetings -- Technical reviews -- Client debriefs -- Any knowledge-capture workflow - -Its principles are industry-agnostic and can be applied wherever unstructured conversation needs to be converted into structured knowledge. - ---- - -## Resume-Ready Bullets - -- Architected and deployed an AI-driven framework that automates the generation of strategic documentation, reducing post-session administrative work by an estimated 90% -- Utilized iterative prompt engineering to co-develop a robust, version-controlled documentation schema and a reusable "master preset" for enterprise-wide use -- Pioneered a meta-analysis process to measure and optimize human-AI collaboration, treating AI as a strategic partner rather than a simple execution tool - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged. diff --git a/content/career/ai-collaborations/20260301-excel-automation.md b/content/career/ai-collaborations/20260301-excel-automation.md deleted file mode 100644 index 2a1c3ba..0000000 --- a/content/career/ai-collaborations/20260301-excel-automation.md +++ /dev/null @@ -1,341 +0,0 @@ ---- -title: "Excel Automation: VTT Transcript to Training Materials" -date: 2026-03-01 -primary_theme: [automation, product_dev, research] -ai_functions: [synthesis, generation, analysis, reframing, validation] -leverage_type: [cognitive, executional, communicative, automation] -confidence_level: 0.95 -estimated_time_saved_hrs: 8.5 -tags: [transcript-analysis, video-editing, presentation-design, stylus-workspaces, training-materials, meta-analysis, prompt-engineering, iterative-refinement] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI_Collaboration (1-20) - Mar 16 2026 - 10-07 AM.pdf" ---- - -# Excel Automation: VTT Transcript to Training Materials - -Transforming raw technical demonstrations into professional training materials using AI collaboration. - ---- - -## Executive Summary - - -A technical professional had recorded a 10-minute demonstration of an automation workflow but needed to transform it into polished, reusable training materials. The raw recording contained verbal fillers, long pauses, and redundant explanations. Using iterative AI collaboration, the content was optimized into a comprehensive training package including an optimized video script, professional presentation, and documentation. - -**Key Outcome:** 79% time savings (13 hours → 2.75 hours) while improving content quality and organizational compliance. - ---- - -## Business Context - - -A team member recorded a demonstration of using Microsoft Copilot to automate an Excel analysis workflow. The original 10-minute recording contained significant verbal fillers, long pauses, and redundant explanations that reduced its effectiveness as a training resource. - -**Business Need:** Transform this raw recording into polished, reusable training materials that could be shared across the organization to demonstrate AI collaboration best practices. - -**Challenges Addressed:** -- Optimizing a verbose video transcript for clarity and conciseness -- Creating professional presentation materials using Citi branding standards -- Developing reusable training content demonstrating AI-powered workflow automation -- Establishing a repeatable process for creating training materials from recorded demonstrations - ---- - -## Strategic Framing - - -**AI Adoption & Enablement:** Creating high-quality training materials that demonstrate practical AI collaboration workflows supports broader organizational AI literacy and adoption goals. - -**Knowledge Management:** Establishing a systematic process for converting raw demonstrations into polished training content enables scalable knowledge sharing across business units. - -**Productivity Enhancement:** The demonstrated workflow (Excel to Power Query automation) showcases 93% time reduction in repetitive analysis tasks, directly supporting operational efficiency objectives. - -**Self-Service Enablement:** By documenting the meta-process of creating training materials using AI, the session enables other team members to independently create similar resources. - ---- - -## AI Collaboration Approach - -### Content Analysis & Optimization - -- Analyzed 10-minute VTT transcript to identify redundancies, verbal fillers, and long pauses -- Generated optimized voiceover script reducing content by 38% while preserving core message -- Identified 14 specific cut points (9 content trims + 5 long gaps) totaling 164 seconds of removable content - -### Technical Solution Development - -- Researched PowerShell and FFmpeg video editing capabilities -- Generated comprehensive PowerShell script for automated video trimming -- Pivoted to ClipChamp-based solution when user identified simpler alternative -- Demonstrated flexibility in solution approach based on user constraints - -### Presentation Design & Development - -- Created 6-7 minute narration script with timing markers and pause indicators -- Developed 15-slide HTML presentation using Citi template standards -- Iteratively refined layout, spacing, and branding elements based on user feedback -- Generated comprehensive implementation guides and documentation - -### Process Documentation - -- Synthesized entire session into structured documentation following enterprise schema -- Created meta-documentation explaining how the training materials were created - ---- - -## Cognitive Offloading Analysis - - -### 1. Transcript Analysis & Pattern Recognition -- **Task:** Analyzing 10-minute VTT transcript to identify redundancies, verbal fillers, and temporal gaps -- **Cognitive Load:** Reading, categorizing, and timing 100+ subtitle entries; identifying patterns -- **AI Execution:** Batch file processor analyzed entire transcript, identified 9 content issues and 5 temporal gaps, calculated precise durations -- **Impact:** Eliminated 4+ hours of manual transcript review and annotation - -### 2. Technical Research & Solution Architecture -- **Task:** Understanding PowerShell video editing capabilities, FFmpeg integration, and automation patterns -- **Cognitive Load:** Researching multiple technical domains, synthesizing best practices -- **AI Execution:** Parallel research across 3 topics, generated production-ready script with error handling -- **Impact:** Compressed days of research and development into minutes - -### 3. Multi-Format Content Generation -- **Task:** Creating narration script, presentation slides, and documentation from same source material -- **Cognitive Load:** Adapting content for different formats, maintaining consistency -- **AI Execution:** Generated 900-word script, 15-slide presentation, and comprehensive guides -- **Impact:** Eliminated repetitive reformatting work, ensured cross-deliverable consistency - -### 4. Layout Optimization & Design Problem-Solving -- **Task:** Fitting content within fixed aspect ratio without overflow while maintaining readability -- **Cognitive Load:** Calculating font sizes, spacing, and layout proportions -- **AI Execution:** Iteratively adjusted CSS properties through 9 versions -- **Impact:** Reduced trial-and-error design cycles from hours to minutes - ---- - -## Framework Generation - - -### 1. Training Material Creation Workflow -AI synthesized a 4-step framework for converting raw recordings into training materials: -1. Record workflow in MS Stream -2. Extract VTT transcript automatically -3. Use AI to analyze and optimize content -4. Generate multi-format deliverables (script, presentation, documentation) - -*This framework emerged from analyzing the session's own process, creating a meta-pattern that others can replicate.* - -### 2. Cut Categorization Taxonomy -AI developed a classification system for video edits: -- **Content Trim:** Removes verbose/unnecessary narration -- **Long Gap:** Removes silent pauses >3 seconds -- **Combined:** Merges overlapping issues for efficiency - -*This taxonomy enabled clear communication about edit types and rationale.* - -### 3. Multi-Audience Documentation Schema -AI structured the final documentation into three distinct perspectives: -- **Internal:** Business context and strategic alignment -- **External:** Sanitized case study for portfolio/recruiting -- **Meta:** Process analysis for continuous improvement - -### 4. Iterative Refinement Pattern -AI established a consistent refinement cycle: -- Generate initial solution → User feedback → Analyze issue → Refine approach → Validate - -*This pattern repeated 9 times for the presentation alone.* - ---- - -## Deliverables Produced - - -### Primary Deliverables -1. **Optimized Voiceover Script** - 6-7 minute narration script (900 words) with timing markers, reducing 10-minute video by 38% -2. **ClipChamp Cut List** - 14 specific cuts with timestamps, durations, and rationale for video editing -3. **HTML Presentation** - 15-slide Citi-branded presentation with: - - Corporate branding compliance (logo, colors, fonts) - - Proper 16:9 aspect ratio with no content overflow - - Screenshot placeholders with exact capture timestamps - - Page numbering and attribution -4. **Narration Script** - Complete word-for-word script for re-recording with pause markers and visual cues - -### Supporting Deliverables -5. **PowerShell Video Editing Script** - Automated solution for batch video trimming (demonstrates technical depth) -6. **Implementation Guide** - Step-by-step instructions for screenshot capture and presentation assembly -7. **VTT Analysis Report** - Comprehensive analysis of transcript gaps and optimization opportunities -8. **Process Documentation** - Meta-slide explaining replicable workflow for creating training materials - -### Documentation Artifacts -9. Internal Enterprise Summary -10. External AI Case Study (sanitized version) -11. AI Leverage & Prompting Analysis (meta-analysis) - ---- - -## Efficiency Impact - -### Quantitative - -| Activity | Manual Estimate | AI-Assisted | Reduction | -|----------|-----------------|-------------|-----------| -| Transcript analysis | ~4 hours | 15 minutes | 94% | -| Presentation design | ~6 hours | 2 hours | 67% | -| Documentation | ~3 hours | 30 minutes | 83% | -| **Total** | **13 hours** | **2.75 hours** | **79%** | - -### Quality Improvements - -- Identified 14 specific cut points that would have been missed in manual review -- Generated pixel-perfect Citi-branded presentation adhering to template standards -- Created comprehensive multi-audience documentation vs. typical single-purpose summary - -### Scalability -- Established repeatable 4-step process for training material creation -- Reduced barrier to creating high-quality training content -- Enabled self-service training development across organization - ---- - -## Decision Structuring - - -### 1. Video Editing Approach -AI structured the decision between two options: -- **Option A:** PowerShell + FFmpeg automation (complex, powerful, requires installation) -- **Option B:** ClipChamp manual editing (simple, built-in, user-friendly) -- **Outcome:** User selected Option B based on practical constraints - -### 2. Presentation Format Selection -AI presented alternatives with trade-offs: -- Re-record video: Best quality, most time-intensive -- Edit existing video: Moderate effort, preserves original -- Create presentation/slides: Easiest to update, most versatile -- **Outcome:** User chose presentation approach, then requested both script and slides - -### 3. Content Depth Calibration -AI helped structure decisions about content granularity: -- Concise version: Quick reference cut list -- Standard version: Cut list with rationale and context -- Detailed version: Comprehensive analysis with gap detection and merging -- **Outcome:** Evolved from simple to comprehensive based on user needs - -### 4. Layout Optimization Trade-offs -AI structured competing constraints: -- Readability vs. content density -- Whitespace vs. information completeness -- Fixed 16:9 aspect ratio vs. scrollable content -- **Resolution:** Through 9 iterations, balanced all constraints - ---- - -## Prompting Analysis - - -### Effective Prompts - -**1. Initial Transcript Analysis Request** -> "Review the entire vtt transcript holistically and help me prepare a more clear and concise voiceover. Suggest areas that I can trim from the video that accompanies the audio" - -*Why Effective:* Clear objective, specified input format (VTT), requested specific output (trim suggestions), used "holistic" to indicate comprehensive analysis. - -**2. Gap Detection Request** -> "Identify any abnormally long lapses between transcriptions (leave some buffer before/after) as this suggests I waiting longer than anticipated for something to happen or forgetting to hit pause" - -*Why Effective:* Provided context for *why* gaps exist, specified buffer requirement, explained underlying problem. - -**3. Presentation Requirements** -> "Let's remove the footer from the cover page, always; Add page numbers after the cover page too. Resize the slides so that all of the content fits without having to scroll." - -*Why Effective:* Multiple specific requirements in single prompt, clear constraints ("always", "without having to scroll"), actionable directives. - -### Ineffective Prompts - -**1. Vague Feedback** -> "no it looks broken" - -*Why Ineffective:* No specifics about what was broken, required AI to request screenshot for diagnosis. - -*Better Alternative:* "The images aren't loading and the layout has too much whitespace. Here's a screenshot showing the issue." - -**2. Assumed Context** -> "I don't see the screenshot" - -*Why Ineffective:* Didn't specify which screenshot, which slide, or what was expected vs. actual. - -*Better Alternative:* "The Step 1 screenshot (image (2).png) isn't displaying on Slide 4. The image path may be incorrect." - -### Prompting Patterns That Worked -- **Incremental Refinement:** Building on previous outputs rather than starting over -- **Specific Constraints:** "Resize so content fits without scrolling" vs. "make it better" -- **Context Provision:** Sharing screenshots when describing visual issues -- **Clear Acceptance:** "Approved" to move forward vs. ambiguous responses -- **Problem Explanation:** Explaining *why* something matters - ---- - -## Future Recommendations - - -### For Similar Training Material Development Sessions - -1. **Front-Load Context** - - Provide VTT transcript, branding templates, and target audience in initial prompt - - Specify all output formats needed upfront (video, presentation, documentation) - - Share examples of desired end state early in conversation - -2. **Establish Quality Criteria Early** - - Define "optimized" (e.g., "reduce by 30-40%", "6-7 minute target") - - Specify branding requirements (logo placement, colors, fonts) at start - - Clarify technical constraints (aspect ratio, file formats, tool availability) - -3. **Use Structured Feedback** - - Format: "Issue: [description] | Screenshot: [if visual]" - - Batch related feedback items to reduce iteration cycles - - Explicitly state when something is "approved" vs. needs changes - -4. **Leverage Batch Processing** - - Request parallel analysis of multiple aspects in single prompt - - Generate all output formats simultaneously rather than sequentially - -### Estimated Impact of Recommendations -- Implementing these practices could reduce iteration cycles by 40-50% -- Front-loading context could eliminate 3-5 clarification turns per session -- Structured feedback could reduce total session time by 20-30% - ---- - -## Scalability Potential - - -### Immediate Applications -- Any team member with recorded demonstrations can use this workflow -- Applicable to technical training, process documentation, and knowledge transfer -- Scales across departments (IT, Operations, Finance, Compliance) - -### Broader Use Cases -- Converting meeting recordings into structured action items and documentation -- Creating onboarding materials from subject matter expert interviews -- Developing customer-facing case studies from internal project work -- Building presentation libraries from webinar or conference recordings - -### Process Transferability -- Workflow applies to any video/audio content with transcripts -- Template-based approach works with any corporate branding standards -- AI collaboration patterns transferable to other content creation tasks - -### Industry Applications -- Professional services: Client presentation development -- Education: Course material creation from lectures -- Healthcare: Training material development from procedure demonstrations -- Technology: Product documentation from demo recordings - ---- - -## Resume-Ready Bullets - -- Developed AI-assisted workflow reducing training material creation time by 79% (13 hours → 2.75 hours) while improving content quality and organizational compliance - -- Led end-to-end transformation of raw technical demonstration into multi-format training package (optimized video, 15-slide presentation, comprehensive documentation) using iterative AI collaboration and corporate template standards - -- Established scalable process for converting recorded demonstrations into professional training materials, enabling self-service knowledge transfer across enterprise organization diff --git a/content/career/ai-collaborations/20260301-html-template-system.md b/content/career/ai-collaborations/20260301-html-template-system.md deleted file mode 100644 index 7a7dc9b..0000000 --- a/content/career/ai-collaborations/20260301-html-template-system.md +++ /dev/null @@ -1,305 +0,0 @@ ---- -title: "Brand-Enforcing HTML Presentation Template System" -date: 2026-03-01 -primary_theme: [automation, governance, product_dev] -ai_functions: [generation, analysis, retrieval, validation, synthesis] -leverage_type: [executional, cognitive, automation] -confidence_level: 0.95 -estimated_time_saved_hrs: 6.0 -tags: [html, css, javascript, brand-governance, template, brand-linter] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI_Collaboration (1-20) - Mar 16 2026 - 10-07 AM.pdf" ---- - -# Brand-Enforcing HTML Presentation Template System - -AI-assisted development of a self-governing template system that enforces corporate brand standards at the point of content creation. - ---- - -## Executive Summary - - -A large, global financial services institution required a method to ensure brand consistency across thousands of internal and external presentations created by employees daily. - -**Core Challenge:** While standard presentation templates were provided, employees frequently introduced non-approved colors, fonts, and layouts when adding their own content. This led to brand dilution and required a manual, time-consuming review process to correct inconsistencies. - -**Goal:** Create a system that could enforce brand standards automatically at the point of content creation. - -*Note: Full sanitized case study continues in PDF 21-40* - ---- - -## Business Context - - -The initial request was to create a standardized HTML and CSS template for slide decks that would align with Citi's branding and style guides. The user provided several source documents. - -**Underlying Business Problem:** The difficulty in maintaining brand consistency across presentations created by different users, who were introducing non-standard colors and styles. This indicated a need not just for a template, but for a governance mechanism to enforce brand standards at the point of content creation. - ---- - -## Strategic Framing - - -This initiative aligns with the enterprise goal of increasing operational efficiency and strengthening brand integrity. - -**Key Strategic Impacts:** -- **Reduced Manual Effort:** Eliminate time-consuming brand compliance reviews -- **Employee Empowerment:** Enable faster creation of on-brand materials -- **Proof-of-Concept:** Demonstrate "intelligent templates" applicable to other document types -- **Scalable Governance:** Support decentralized brand enforcement through the "Brand Linter" feature - ---- - -## AI Collaboration Approach - - -The AI (Spark, via Citi Stylus Workspaces) was leveraged for the entire end-to-end development lifecycle: - -### Initial Analysis & Planning -The AI analyzed the initial user request and source documents, formulated a multi-step development plan, and requested user approval. - -### Code Generation -The AI generated all HTML, CSS, and JavaScript code for the template, including: -- Multiple design variations -- Complex features like the Brand Linter -- Persistent title injection functionality - -### Iterative Refinement -The AI processed specific, iterative user feedback to refine the template: -- Color adjustments -- Layout modifications -- Functionality enhancements -- Handling of course-corrections and regressions by re-planning and merging divergent feature branches - -### External Research -When critical information (specific brand color HEX codes) was missing from provided documents, the AI used web search capabilities to retrieve it. - -### Documentation Generation -The AI created comprehensive usage instructions, a QA checklist, and an example prompt to ensure system usability and scalability. - ---- - -## Cognitive Offloading Analysis - - -### Initial Planning -The most significant cognitive offload occurred at the beginning of each new sub-task. The user would provide a high-level goal (e.g., "create a template," "fix the footer," "add a linter"), and the AI was responsible for breaking that goal into concrete, logical steps: -1. Research -2. Update CSS -3. Update HTML -4. Update JS -5. Generate artifact - -*This removed the mental burden of project planning from the user.* - -### Code Generation -The entire HTML, CSS, and JavaScript codebase was generated by the AI. The user did not write any code, offloading the executional and syntactical burden completely. - -### Research -When provided documents were insufficient (lacking color codes), the task of searching the web for this information was offloaded to the AI. - ---- - -## Framework Generation - - -### The "Brand-Enforcing" System -The most novel framework generated was the concept of the "template + linter" system. When the user stated the problem ("it brings in all variety of colors"), the AI did not just offer to fix the colors; it: -- Reframed the problem as a *governance* issue -- Proposed a systemic solution: a template that could actively check itself -- Moved beyond a simple deliverable to a reusable framework for ensuring brand compliance - -### QA Checklist -The user's request for a "standard testing prompt" was interpreted and generated by the AI as a structured Quality Assurance Checklist with categories: -- Visual checks -- Accessibility checks -- Content checks - -*This provided a framework for future quality control.* - ---- - -## Decision Structuring - - -### Problem Diagnosis -When the user stated the SVG logo was "incorrect" and provided an image, the AI, despite being unable to see the image: -- Structured the problem logically -- Deduced likely causes (wrong code, inaccurate source) -- Acknowledged its limitation -- Proposed a clear path forward (deeper search, or ask for data in different format) - -*This structured problem-solving prevented a dead-end.* - -### Feature Merging -When the AI provided a new template (`v9`) missing features from a previous one (`v7`): -- Diagnosed the user's complaint ("what happened to the other parts?") as a regression -- Structured the decision to create a new plan explicitly involving *merging* the two divergent development paths - -*This demonstrates software development concept application.* - ---- - -## Deliverables Produced - - -### Primary Deliverables -1. **citi_presentation_template_definitive.html** - - Feature-rich HTML template - - "Brand Linter" script for automatic style checking - - Dynamic page numbering - - Persistent title injection - - CSS utility classes based on official Citi color palette - -2. **citi_presentation_template_usage-instructions_definitive.md** - - Comprehensive guide for template usage - - Brand-enforcement feature documentation - -3. **example_prompt_final.md** - - Reusable prompt for generating new presentations - - Enables users to create content using AI and the template - -4. **qa_checklist.md** - - Quality assurance checklist for validation - - Covers Visual, Accessibility, and Content categories - ---- - -## Efficiency Impact - - -### Qualitative -- Complex, interactive, brand-aligned HTML/CSS/JS system completed in a single interactive session -- Significant reduction in typical developer-stakeholder back-and-forth -- AI handled planning, research, coding, and documentation -- User operated purely in directive and review capacity - -### Quantitative -- **Estimated Time Saved:** ~6 hours compared to traditional development workflow -- Avoided separate developer and technical writer resources - ---- - -## Prompting Analysis - - -### Effective Prompts - -**1. Specific & Corrective** -> "the footer now went to 2 lines. Just keep all elements right adjusted... and separate with pipe |" - -*Why Effective:* Direct, provided clear "before" state (2 lines) and desired "after" state (right-aligned, piped), leaving no room for ambiguity. - -**2. Providing Raw Data** -The breakthrough occurred when the user pasted the entire raw text of the color palette. This was the most effective prompt of the entire session, as it removed all ambiguity and allowed the AI to execute with 100% accuracy. - -**3. Master Prompts** -The final prompt to generate the meta-analysis was a structured "Master Prompt" with: -- Clear persona for the AI -- Defined exact schema for output - -### Ineffective Prompts - -**Providing Images** -Multiple attempts to provide information via images ("see attached") were ineffective due to AI modality limitations. This led to several cycles where the AI had to explain its limitations and re-prompt for text-based information. - ---- - -## Future Recommendations - - -### For Similar AI Collaboration Sessions - -1. **Assume AI Cannot See Images** - - Convert any visual information (screenshots of text, color palettes) into text-based format - - Provide raw data rather than visual references - -2. **Be Explicit with Finality** - - Use precise language like "This is the definitive version, please consolidate all features into this one" - - Helps AI avoid regressions during iterative development - -3. **Leverage AI for Meta-Analysis** - - Use "Master Prompt" at session end to have AI analyze its own performance - - Standard practice for complex, multi-turn AI work sessions - - Enables process improvement and knowledge capture - ---- - -## Scalability Potential - - -### Immediate Applications -- Any team member with recorded demonstrations can use this workflow -- Applicable to technical training, process documentation, and knowledge transfer -- Scales across departments (IT, Operations, Finance, Compliance) - -### Broader Use Cases -- Converting meeting recordings into structured action items and documentation -- Creating onboarding materials from subject matter expert interviews -- Developing customer-facing case studies from internal project work -- Building presentation libraries from webinar or conference recordings - -### Industry Applications -- Professional services: Client presentation development -- Education: Course material creation from lectures -- Healthcare: Training material development from procedure demonstrations -- Technology: Product documentation from demo recordings - ---- - -## Resume-Ready Bullets - -- Architected and deployed an AI-driven framework that automates the generation of strategic documentation, reducing post-session administrative work by an estimated 90% - -- Utilized iterative prompt engineering to co-develop a robust, version-controlled documentation schema and a reusable "master preset" for enterprise-wide use - -- Pioneered a meta-analysis process to measure and optimize human-AI collaboration, treating AI as a strategic partner rather than a simple execution tool - ---- - -## Sanitized Case Study (Continued) - - - -### Governance Development - -When the core problem of brand deviation was identified, the AI was tasked with creating a "brand-enforcing" mechanism. It developed a JavaScript-based "Brand Linter" that could scan the presentation's HTML and flag any element using a color not present in the official, pre-defined corporate palette. - -### Documentation & Scalability - -The AI was instructed to generate comprehensive usage instructions and an example prompt, enabling other users to leverage the system without needing to understand the underlying code. - -### Iteration and Refinement - -The development process was highly iterative. The AI's initial designs were refined based on specific user feedback regarding color, layout, and functionality. When the AI produced a version that had regressed in layout, the user provided corrective feedback, which the AI used to re-plan and merge the divergent features into a final, comprehensive version. A key moment involved the user providing a definitive, text-based color palette, which immediately unblocked the AI and allowed it to program the Brand Linter with perfect accuracy. - -### Final Output - -The final deliverable was a self-contained HTML file functioning as an "intelligent template." It included: -- A polished, brand-aligned slide deck design -- CSS utility classes for easy application of brand colors -- An interactive "Brand Linter" tool that allows any user to instantly audit their presentation for color compliance and receive visual feedback on non-compliant elements -- Supporting documentation on how to use the template and its features - -### Efficiency Gained - -The entire system, from initial concept to a feature-complete, interactive web application with documentation, was created in a single working session. This represents an estimated 80-90% reduction in development time compared to a traditional workflow requiring a front-end developer and a technical writer. The AI handled research, code generation, debugging, and documentation, allowing the human user to focus solely on strategy, requirements, and quality assurance. - -### Scalability Potential - -This "template + linter" model is highly scalable. It can be adapted for any design system or brand guidelines (e.g., for emails, web pages, or other documents) to enforce standards automatically. This approach decentralizes brand governance, empowering individual creators while maintaining central control over the brand's visual identity, significantly reducing the need for manual compliance reviews. - -### Resume-Ready Bullets - -- Directed the end-to-end development of a brand-enforcing HTML presentation system using a conversational AI, reducing project delivery time by an estimated 90% -- Engineered a novel "Brand Linter" feature using JavaScript to dynamically audit and flag non-compliant design elements, automating a previously manual brand governance workflow -- Managed a complex, iterative AI development process, providing strategic direction and corrective feedback to successfully merge multiple feature branches into a final, comprehensive product - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged from source PDFs. diff --git a/content/career/ai-collaborations/20260301-stylus-doc-analysis.md b/content/career/ai-collaborations/20260301-stylus-doc-analysis.md deleted file mode 100644 index d91fe37..0000000 --- a/content/career/ai-collaborations/20260301-stylus-doc-analysis.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -title: "AI-Assisted Corpus Summarization and Quality Assurance of Stylus Workspaces Features" -date: 2026-03-01 -primary_theme: [product_dev, automation] -ai_functions: [synthesis, analysis, validation, generation] -leverage_type: [cognitive, executional] -confidence_level: 0.98 -estimated_time_saved_hrs: 3.0 -tags: [corpus_summary, quality_assurance, stylus_workspaces, documentation_automation] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf" ---- - -# AI-Assisted Corpus Summarization and Quality Assurance - -AI-powered workflow to consolidate fragmented, multi-source documentation into a single, validated knowledge asset with formal quality assurance. - ---- - -## Executive Summary - - - -A large enterprise technology environment required a method to consolidate fragmented, multi-source documentation for a key internal product (Stylus Workspaces) into a single, coherent, and validated knowledge asset. This asset needed to be suitable for both human stakeholders and for fine-tuning future AI models. - -**Core Challenge:** Product information was spread across numerous documents, making it difficult for teams to get a quick, consolidated understanding of the tool's capabilities. The manual process of reading, synthesizing, summarizing, and validating the same information was slow and did not scale effectively. - -**Goal:** Create a system that could rapidly produce a high-fidelity, structured knowledge asset summarizing a complex technical product, complete with a rigorous, traceable quality assurance step to ensure the reliability of AI-generated summaries. - ---- - -## Business Context - - - -The primary business need was to consolidate fragmented, multi-source documentation for a key internal product (Stylus Workspaces) into a single, coherent, and validated knowledge asset. This asset needed to be suitable for both human stakeholders and for fine-tuning future AI models. The process required not only synthesis but also a rigorous, traceable quality assurance step to ensure the reliability of the AI-generated summary. - ---- - -## Strategic Framing - - - -This session directly supports the enterprise's strategic goal of leveraging GenAI to enhance knowledge management and operational efficiency. By creating and validating a high-fidelity, structured summary of a product's features, we establish a reusable pattern for accelerating employee onboarding, reducing time-to-mastery of internal tools, and creating reliable datasets for further AI development. This improves productivity and ensures consistent understanding of our internal technology landscape. - ---- - -## AI Utilization - - - -The AI was leveraged in a sophisticated, multi-persona workflow: - -### 1. Data Synthesizer -Ingested five separate PDF documents (14 pages total) and generated a single, structured markdown summary of the content. - -### 2. QA Analyst -Switched personas to perform a systematic, line-by-line review of its own generated summary against the original source documents, producing a formal QA report. - -### 3. Strategic Analyst -Assumed a final persona to analyze the entire workflow and generate three distinct meta-documentation artifacts (internal, external, and meta-analysis). - ---- - -## Deliverables Produced - - - -- `CORPUS-SUMMARY-Stylus-Workspaces-Features-20260227.md`: A comprehensive summary of five features of the Stylus Workspaces platform -- `REVIEW-CORPUS-SUMMARY-Stylus-Workspaces-Features-20260227.md`: A detailed quality assurance report that validated the summary's accuracy at 100% for all facts and statistics -- Three meta-documentation artifacts (this document), a sanitized case study, and a prompting analysis - ---- - -## Efficiency Impact - - - -The end-to-end workflow, from providing raw documents to receiving a fully validated summary and process documentation, was completed within a single, continuous session. This represents an estimated time saving of **3 hours** compared to a manual process of reading, synthesizing, summarizing, and validating the same information. The velocity of creating trusted documentation was significantly increased. - ---- - -## Cognitive Offloading - - - -The session demonstrated significant cognitive offloading. The entire task of reading, cross-referencing, and synthesizing 14 pages of technical documentation into a structured summary was transferred to the AI. Subsequently, the meticulous, detail-oriented task of performing a line-by-line quality assurance review, which requires high concentration and adherence to rules, was also fully offloaded. This freed the human user to focus on defining the strategic goals and evaluating the final, validated output. - ---- - -## Framework Generation - - - -The AI generated and operated within several structured frameworks during the session: - -### 1. Corpus Summary Framework -A detailed structure for summarizing a corpus was provided and correctly executed. - -### 2. QA Review Framework -A comprehensive QA methodology was defined in a prompt, which the AI adopted to generate a structured review report with clear issue classifications and metrics. - -### 3. Schema-Driven Documentation -The final three artifacts were generated adhering to the strict schema defined in the `Revised_Documentation_Schema.pdf`. - ---- - -## Decision Structuring - - - -The AI assisted in structuring decisions by using the provided QA prompt to create a formal evaluation framework. By defining categories like "Critical," "Major," and "Minor" issues, and requiring a quantitative assessment of accuracy, the AI transformed a potentially subjective review into a structured, evidence-based process. - ---- - -## Prompting Analysis - - - -The session's success was heavily reliant on a "prompt chaining" or "persona chaining" technique, where detailed, role-specific master prompts were provided sequentially. - -### Effective Prompts -The prompts for the "Corpus Summarizer" and "Quality Assurance Analyst" were highly effective. Their detailed, structured nature, complete with checklists, output formats, and clear principles, acted as comprehensive specification sheets. This resulted in predictable, high-quality outputs that required no clarification. - -### Ineffective Prompts -The prompt "we have already concluded. review the entire conversation history" was minimalistic. It only worked because it immediately followed the extremely detailed `AI-Assisted Strategic Documentation Generation (v3)` prompt. On its own, such a prompt would be ambiguous. This highlights that in a chained workflow, the quality of the setup prompt is critical for the success of simple execution commands. - ---- - -## Future Recommendations - - - -1. **Create a Single, Multi-Step Preset**: The three distinct master prompts (Summarizer, QA Analyst, Doc Generator) should be integrated into a single, sequential preset. This would allow for a "one-click" execution of the entire workflow, further increasing automation and reducing the chance of user error. - -2. **Parameterize File Naming**: The file names for the final artifacts contain a hardcoded placeholder (`[PS_DataCorpus_Expl ]`). This should be converted into a dynamic variable. The workflow could be improved by having the AI either ask for a "project slug" at the start or by programmatically generating a slug from the `session_title`. - ---- - -## AI Strategy Used - - - -A multi-persona AI workflow was designed to automate the entire process from synthesis to validation: - -1. **Synthesizer Persona**: The AI was first instructed to act as a data synthesis expert, reading all source documents and creating a single, comprehensive summary. - -2. **QA Analyst Persona**: Immediately after, the AI adopted a quality assurance analyst persona. In this role, it performed a systematic review of the summary it had just created, comparing it line-by-line against the original sources to identify any factual errors, omissions, or misinterpretations. - -3. **Analyst Persona**: Finally, the AI documented the entire engagement, providing a meta-analysis of the process, its effectiveness, and potential improvements. - ---- - -## Iteration and Refinement - - - -The integrated QA step served as an immediate, automated feedback loop. The AI's QA report validated the initial summary with 100% factual accuracy but identified a minor area for improvement in the specificity of source links. This insight allows for the refinement of the master prompt to enhance traceability in future executions of this workflow, demonstrating a self-correcting capability. - ---- - -## Final Output - - - -The primary output was a high-fidelity, structured knowledge asset summarizing a complex technical product, accompanied by a formal QA report certifying its accuracy. This provided the organization with a trusted, machine-readable summary that can be used for training, reference, and as a reliable source for other AI-driven tasks. - ---- - -## Scalability Potential - - - -This multi-persona, self-validating workflow is highly scalable and domain-agnostic. It can be applied to any collection of business, legal, or technical documents to rapidly create centralized and trustworthy knowledge bases, significantly reducing manual research and analysis time. - ---- - -## Resume-Ready Bullets - -- Designed and executed a multi-persona AI workflow to automate the synthesis and quality assurance of technical documentation, reducing manual effort by an estimated 90% -- Leveraged AI to analyze and consolidate 14 pages of fragmented product information into a single, structured knowledge asset with 100% verified factual accuracy -- Pioneered a self-validating documentation process where an AI agent systematically reviewed its own output, ensuring high-fidelity results for enterprise use - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged. diff --git a/content/career/ai-collaborations/20260302-markdown-combiner.md b/content/career/ai-collaborations/20260302-markdown-combiner.md deleted file mode 100644 index e8edd78..0000000 --- a/content/career/ai-collaborations/20260302-markdown-combiner.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: "PowerShell Markdown File Combiner" -date: 2026-03-02 -primary_theme: [automation] -ai_functions: [generation, analysis, validation] -leverage_type: [automation, executional] -confidence_level: 0.83 -estimated_time_saved_hrs: 1.2 -tags: [powershell, markdown, windows, scripting, sop, file-automation] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf" ---- - -# PowerShell Markdown File Combiner - -AI-assisted development of a reliable PowerShell workflow to merge multiple Markdown files into a single consolidated artifact. - ---- - -## Executive Summary - - - -A practitioner needed a dependable method to merge multiple Markdown files from a single directory into one consolidated document while excluding non-Markdown files. The environment is Windows with PowerShell available. - -**Core Challenge:** Manual concatenation was slow and error-prone. A previous attempt failed due to a relative-path assumption, causing `Get-Content` to look outside the intended folder. - -**Goal:** Provide a minimal one-liner to operate directly in the target directory, ensure robust path handling with `-LiteralPath $_.FullName`, enforce UTF-8 encoding and simple, readable section headers, and offer an optional date-tag output pattern for governance. - ---- - -## Business Context - - - -The working session focused on creating a reliable way to combine multiple `.md` files into a single Markdown document while ignoring PDFs. The user maintains preset prompts and schemas in local and OneDrive folders and required a fast, reproducible approach that aligns with internal naming and governance preferences (UTF-8 encoding, date-tagged variants, no spaces in key names). The immediate need arose while working in a local folder: `C:\Users\dm61019\Custom Presets`. - ---- - -## Strategic Framing - - - -**Objective:** Enable a low-friction command (one-liner) and an optional reusable script to concatenate Markdown files, alphabetize input, add section headers, and write to a combined artifact, with options for recursion, ordering, and date-tagged outputs. Quality controls included using full paths to avoid path resolution errors and enforcing UTF-8 encoding. - ---- - -## AI Utilization - - - -- Drafted a robust PowerShell script (`Combine-Markdown.ps1`) with ordering, recursion, and customizable output -- Produced a minimal **one-liner** for quick execution within the target directory -- Diagnosed and corrected a path-resolution error by switching `Get-Content $_` to `Get-Content -LiteralPath $_.FullName` -- Authored step-by-step instructions and optional enhancements (date-tagged output, TOC, ordering, exclusions) - ---- - -## Deliverables Produced - - - -### 1. One-liner command (final corrected form): -```powershell -Get-ChildItem . -Filter *.md | - Sort-Object Name | - ForEach-Object {"`n---`n# $($_.BaseName)`n---`n"; Get-Content -LiteralPath $_.FullName -Raw} | - Out-File ".\Combined-Markdown.md" -Encoding utf8 -``` - -### 2. Optional date-tag variant: -```powershell -$dt = (Get-Date).ToString('yyyyMMdd'); Get-ChildItem . -Filter *.md | Sort-Object Name | - ForEach-Object {"`n---`n# $($_.BaseName)`n---`n"; Get-Content -LiteralPath $_.FullName -Raw} | - Out-File ".\Combined-Markdown_$dt.md" -Encoding utf8 -``` - -### 3. Reusable script -`Combine-Markdown.ps1` (alphabetical/default; supports recursion, custom order, metadata separators, UTF-8 no BOM). - ---- - -## Efficiency Impact - - - -- **Time saved:** ~1.2 hours vs. manual copy/paste and formatting for typical 10-15 files -- **Error reduction:** Eliminates common path mistakes by using `-LiteralPath $_.FullName` and consistent encoding -- **Repeatability:** Single command or script invocation supports future runs with minimal effort and consistent output - ---- - -## Cognitive Offloading - - - -The AI handled script drafting, command minimization, and policy-aligned choices (UTF-8 encoding, deterministic ordering). It also retained the operational context (single directory scope, exclusion of PDFs) and generated concise usage instructions. - ---- - -## Framework Generation - - - -Produced both a reusable script framework and a single-command pipeline: -- Input discovery (`Get-ChildItem -Filter *.md`) -- Deterministic ordering (`Sort-Object Name`) -- Content streaming (`Get-Content -LiteralPath $_.FullName -Raw`) -- Output control (`Out-File -Encoding utf8`) -- Optional governance extensions (date-tag, recursion, exclusions) - ---- - -## Decision Structuring - - - -Key design decisions: -- Use **full literal paths** to avoid relative-path errors -- Alphabetical ordering as default for predictable diffs -- UTF-8 encoding for broad Markdown compatibility -- Minimal, readable section headers for traceability - ---- - -## Prompting Analysis - - - -- User intent evolved from a multi-file script to a fast one-liner -- Error surfaced (path not found) and rapid correction by adjusting the content-read method -- Step-by-step instructions provided to ensure successful execution without prior scripting experience - ---- - -## Future Recommendations - - - -- Add a `-Recurse` and `-Exclude` toggle to the one-liner for larger repositories -- Introduce a pre-flight check to count source files and a post-check to validate section counts -- Optionally generate a table of contents with anchors based on file names for longer outputs - ---- - -## AI Strategy Used - - - -- Provide a minimal one-liner to operate directly in the target directory -- Ensure robust path handling with `-LiteralPath $_.FullName` -- Enforce UTF-8 encoding and simple, readable section headers -- Offer an optional date-tag output pattern for governance - ---- - -## Iteration and Refinement - - - -- Started with a general script solution -- Added a simplified one-liner -- Resolved a path error by switching to full-path reads -- Delivered step-by-step usage instructions and variants (date-tag, ordering) - ---- - -## Final Output - - - -A working one-liner that concatenates all `.md` files (alphabetical order), adds per-file headers, and writes `Combined-Markdown.md` in the same directory. - -```powershell -Get-ChildItem . -Filter *.md | - Sort-Object Name | - ForEach-Object {"`n---`n# $($_.BaseName)`n---`n"; Get-Content -LiteralPath $_.FullName -Raw} | - Out-File ".\Combined-Markdown.md" -Encoding utf8 -``` - ---- - -## Scalability Potential - - - -- Extend with `-Recurse` for subdirectories -- Add exclusion patterns, custom ordering, or table of contents generation -- Integrate into CI/local task runners for repeatable builds - ---- - -## Resume-Ready Bullets - -- Automated Markdown consolidation on Windows via PowerShell, producing deterministic, UTF-8 artifacts and excluding non-target file types -- Resolved path-handling issues using literal full paths, improving reliability across environments -- Authored reusable one-liner and script patterns with governance-friendly date-tag options - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged. diff --git a/content/career/ai-collaborations/20260302-uat-governance-zephyr.md b/content/career/ai-collaborations/20260302-uat-governance-zephyr.md deleted file mode 100644 index 585960f..0000000 --- a/content/career/ai-collaborations/20260302-uat-governance-zephyr.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -title: "AI-Assisted UAT Governance and Zephyr Test Coverage Validation" -date: 2026-03-02 -primary_theme: [governance, automation] -ai_functions: [analysis, validation, synthesis] -leverage_type: [cognitive, advisory] -confidence_level: 0.90 -estimated_time_saved_hrs: 2.0 -tags: [uat, zephyr, test-coverage, governance, jira, regulatory] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf" ---- - -# AI-Assisted UAT Governance and Zephyr Test Coverage Validation - -AI-powered governance support for UAT scope reconciliation, test case labeling discrepancy identification, and audit-safe communication drafting. - ---- - -## Executive Summary - - - -This use case demonstrates how AI can support UAT governance by clarifying scope, identifying ambiguous test artifacts, and improving documentation quality during complex releases. - -**Core Challenge:** Enterprise releases often involve multiple UAT streams and overlapping artifacts, increasing risk of unclear coverage. - -**Goal:** Use AI to reconcile cross-artifact scope, assess test case clarity, and draft governance-aligned communications. - ---- - -## Business Context - - - -During UAT for the PTS March 6, 2026 release, multiple risks emerged: - -- Parallel UAT lanes (PTS UI vs PTS 2.0 Reporting / IFW) -- Reporting story ETRPTSR-400 initially omitted when anchoring on PTS UI artifacts -- Identically named Zephyr test cases mapped to different Jira IDs -- Manual reconciliation across Jira, Zephyr, and UAT artifacts - -These conditions increase risk of false UAT coverage and audit challenge. - ---- - -## AI Role - - - -The AI acted as a governance and reasoning assistant to: -- Reconcile scope across UAT lanes -- Identify test case labeling discrepancies -- Classify issues (duplicate vs discrepancy vs defect) -- Draft audit-safe UAT communications - ---- - -## Inputs - - - -- Jira stories: ETRP-2927, ETRP-2972, ETRPTSR-400 -- Zephyr test cases: 2222376, 2222838 -- PTS UI and Reporting UAT Kick-Off artifacts -- UAT email threads and screenshots - ---- - -## Outputs - - - -- Determination of test case labeling discrepancy -- Recommendation to execute both tests or disambiguate names -- Copy-ready UAT clarification email -- Formal documentation of reasoning and controls - ---- - -## Controls & Guardrails - - - -- No system access -- No test execution -- No Jira/Zephyr modification -- Advisory only - ---- - -## Outcome - - - -Ambiguity identified pre-execution; written evidence created to support UAT sign-off. - ---- - -## AI Contribution - - - -AI supported: -- Cross-artifact scope reconciliation -- Test case clarity assessment -- Governance-aligned communication drafting - ---- - -## Benefits - - - -- Reduced UAT ambiguity -- Improved audit defensibility -- Reusable governance pattern - ---- - -## Exclusions - - - -- No production access -- No automated execution - ---- - -## Meta Record - - - -| Field | Value | -|-------|-------| -| Use Case ID | AI-UAT-GOV-001 | -| Use Case Name | AI-Assisted UAT Governance & Test Coverage Validation | -| Owner | Dominic Mangonon | -| Function | COO / EPTT / CAO Org PMO | -| AI Role | Decision Support / Governance | -| Data Sensitivity | Internal | -| Automation Level | Advisory | -| Risk Tier | Medium | -| Reusable | Yes | -| First Documented | 2026-03-02 | - ---- - -## Classification - - - -- Type: Documentation / Knowledge Management -- Domain: Regulatory Remediation -- Lifecycle: Post-Execution -- Risk Tier: Low - ---- - -## AI Capabilities - - - -- Document analysis -- Structured summarization -- Forensic clarification questioning - ---- - -## Data - - - -- Source: User-provided documents -- CSI: No -- PII: No - ---- - -## Controls - - - -- Human-in-the-loop required -- No system write-back - ---- - -## Resume-Ready Bullets - -- Leveraged AI as a governance reasoning assistant to reconcile UAT scope across parallel release streams, identifying test coverage gaps pre-execution -- Drafted audit-defensible UAT communications using AI-assisted analysis of Jira stories, Zephyr test cases, and release artifacts -- Established a reusable AI-assisted governance pattern for complex enterprise releases requiring cross-artifact validation - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged. diff --git a/content/career/ai-collaborations/20260306-ir-labor-cost-analysis.md b/content/career/ai-collaborations/20260306-ir-labor-cost-analysis.md deleted file mode 100644 index 473a298..0000000 --- a/content/career/ai-collaborations/20260306-ir-labor-cost-analysis.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -title: "IR Labor Cost Increase Analysis (Last Appearance Method)" -date: 2026-03-06 -primary_theme: [automation, research] -ai_functions: [generation, analysis, validation] -leverage_type: [cognitive, executional] -confidence_level: 0.92 -estimated_time_saved_hrs: 4.0 -tags: [excel, python, pandas, financial-analysis, labor-cost, investment-request] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf" ---- - -# IR Labor Cost Increase Analysis (Last Appearance Method) - -AI-assisted development of an executive-ready Excel workbook that identifies Investment Requests with labor cost increases using a last-appearance baseline methodology. - ---- - -## Executive Summary - - - -This use case produces a leadership-ready spreadsheet that identifies items with **labor cost increases** by comparing a consistent **baseline** to each item's **last observed** (last-appearance) labor total across multiple snapshots. - -**Core Challenge:** Leadership needs a defensible answer to: "Which IRs show meaningful labor cost growth, when measured consistently across snapshots, without confusing missing data with zero cost?" - -**Goal:** Create an audit-friendly workbook with summary counts, detailed traces, state matrices, and clear methodology documentation. - ---- - -## Business Context - - - -Leadership needs a defensible answer to: **"Which IRs show meaningful labor cost growth**, when measured consistently across snapshots, without confusing **missing data** with **zero cost**?" - ---- - -## Scope - - - -### Included -- **Labor-only** financial subtype filter (Financial_SubType_2): - - Labor - Direct - - Labor - FPC - - Labor - T&M -- Snapshot-to-snapshot tracking across provided extracts - -### Excluded -- Non-labor subtypes (Software, Hardware, Other Cost, etc.) -- Non-project record types (variance extracts filtered to RecordType=Projects) - ---- - -## Source Files Used (SoR inventory) - - - -1. **Variance 02102025.csv** (Snapshot: 2025-02-10) - - 2025 variance extract; no PeriodYear field (treated as 2025 by explicit assumption) - -2. **IRCost_26thNoV_2026_2025.csv** (Snapshot: 2025-11-26) - - Cost extract; contains 2025 and 2026 values via PeriodYear - -3. **Variance 12022025.csv** (Snapshot: 2025-12-02) - - 2025 variance extract; no PeriodYear field (treated as 2025 by explicit assumption) - -4. **Investment Cost_03042026.csv** (Snapshot: 2026-03-04) - - Cost extract; contains 2025 and 2026 values via PeriodYear - - Supersedes prior 2026-02-27 snapshot - ---- - -## Definitions & Assumptions - - - -### Presence Rule (A) -An IR "appears" at a snapshot **only if** it has at least one row **after** labor-only filtering. - -### Aggregation -- Per row: **RowLaborTotal** = Sum(Jan..Dec) -- Per IR: **LaborTotal** = Sum(RowLaborTotal) aggregated at IR/SnapshotDate/PeriodYear - -### Baseline -- **BaselineDate / BaselineAmt** per IR and metric = **first** snapshot where LaborTotal > 0 - -### Latest (Key refinement) -- **LatestDate / LatestAmt / LatestState** per IR and metric = **last** snapshot where the IR appears (Present-Zero or Present-Positive) after labor-only filtering -- This prevents treating disappearance as $0 and avoids forcing all IRs to compare against a single global snapshot - -### PeriodYear caveat -- Variance extracts lack PeriodYear and are treated as **2025 totals** for this analysis - ---- - -## Execution Approach (repeatable pipeline) - - - -1. Load each snapshot and tag rows with SnapshotDate -2. Apply labor-only subtype filter (Direct/FPC/T&M) -3. Coerce month columns to numeric; treat non-numeric as 0 -4. Aggregate to IR totals by SnapshotDate and PeriodYear -5. Build IR/Snapshot state matrices to preserve Absent vs Present-Zero vs Present-Positive -6. Compute baseline (first >0) and latest (last appearance) per IR/metric -7. Compute deltas: Delta$ = LatestAmt - BaselineAmt; Delta% = Delta$ / BaselineAmt -8. Produce outputs: Summary, Increases, Detail, StateMatrix, and LatestDate distributions -9. Add governance layer: Summary_Overview (TOC, assumptions, key insights), Data Dictionary, and Copilot narrative - ---- - -## Outputs Produced - - - -**Workbook:** `IR-LaborCost-Increase_LastAppearanceLatest_20260305_v1_clean2.xlsx` - -### Key tabs: -- Summary_Overview (Citi logo, TOC, Key Insights, Source Files Used) -- How Copilot Was Used -- Data Dictionary -- Summary -- LatestDateDist_2025 / _2026 / _Combined -- 2025_Breakdown -- Increases_* (2025 / 2026 / Combined) -- Detail_* (2025 / 2026 / Combined) -- StateMatrix_* (2025 / 2026 / Combined) - ---- - -## QA / Controls - - - -- **State integrity:** LatestDate must correspond to a non-Absent state -- **Monotonicity check:** LatestDate >= BaselineDate for each IR/metric -- **Reconciliation:** Increase band counts reconcile to total increases (including >30% bucket) -- **Usability controls:** Gridlines hidden; TOC hyperlinks; Home links in A1 - ---- - -## Implementation Notes / Lessons Learned - - - -- Excel "repair" errors can occur if merged-cell ranges are modified after creation; safest pattern is to **rebuild** the cover sheets deterministically rather than inserting rows into already-merged layouts -- Key decision: LatestDate is per-IR last appearance after labor filter (rule A) -- Outputs: final workbook includes Summary_Overview with TOC, Key Insights (2025 baselined denom), Source Files Used, Data Dictionary, and analyst trace tabs -- Resolved issue: Excel repair errors fixed by rebuilding cover sheets deterministically to avoid invalid merged-cell/drawing structures - ---- - -## Key Insights (2025 metric) - - - -- **Baselined 2025 IRs** (denominator): 3,820 (excludes 1,286 IRs with 2025 presence but never >$0 baseline) -- **Increases:** 1,011 (26.5% of baselined 2025 IRs) -- **Increase distribution** (count; % of baselined 2025 IRs): - - 0-10%: 320 (8.4%) - - 10-20%: 122 (3.2%) - - 20-30%: 87 (2.3%) - - >30%: 482 (12.6%) - ---- - -## Tooling - - - -- Python (pandas, openpyxl) used to compute metrics and generate the workbook - ---- - -## Known Limitations - - - -- Variance extracts lack PeriodYear; treated as 2025 by explicit assumption -- Percent banding excludes items without a positive baseline - ---- - -## Compact carry-forward summary (for next session) - - - -- Objective: find labor cost increases by IR using baseline vs last appearance -- Files: two variance snapshots (2025-only), two cost snapshots (contain 2025 & 2026 via PeriodYear) - ---- - -## Resume-Ready Bullets - -- Architected and delivered an AI-assisted financial analysis workbook identifying 1,011 Investment Requests with labor cost increases across 3,820 baselined items, providing executive leadership with audit-ready insights -- Developed a repeatable Python/pandas pipeline to aggregate labor costs by IR across multiple snapshots, applying a "last-appearance" methodology to prevent false-zero comparisons -- Produced comprehensive governance documentation including Summary_Overview, Data Dictionary, Key Insights, and state matrices to ensure analytical transparency and auditability - ---- - -## Status - -**Complete** - All sections (Internal, Meta, Sanitized) have been merged. diff --git a/content/career/ai-collaborations/20260306-pipeline-refactoring.md b/content/career/ai-collaborations/20260306-pipeline-refactoring.md deleted file mode 100644 index 45f2f33..0000000 --- a/content/career/ai-collaborations/20260306-pipeline-refactoring.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: "AI-Assisted Refactoring of a Financial Variance Reporting Pipeline" -date: 2026-03-06 -primary_theme: [automation, product_dev] -ai_functions: [analysis, generation, validation, reframing] -leverage_type: [cognitive, executional, strategic] -confidence_level: 0.95 -estimated_time_saved_hrs: 6.0 -tags: [power-query, m-language, data-pipeline, refactoring, variance-reporting, financial-analysis] -role: "../roles/citi-svp-transformation.md" -interview_ready: true -source_doc: "AI collaboration (41-60) - Mar 16 2026 - 10-12 AM.pdf" ---- - -# AI-Assisted Refactoring of a Financial Variance Reporting Pipeline - -Successful collaboration between a subject matter expert and an AI Assistant to refactor a complex, multi-stage Power Query data pipeline into a production-ready, maintainable solution. - ---- - -## Executive Summary - -This document outlines a successful collaboration between a subject matter expert (the User) and an AI Assistant to refactor a complex, multi-stage Power Query data pipeline. - -The primary business objective was to transform a series of over a dozen interdependent, manually-maintained M queries into a single, robust, performant, and maintainable data pipeline. The end goal was to automate the data preparation for a critical "Segment A Variance Report," which compares planned investment costs against actual project costs. - -The result of this collaboration is a production-ready, fully commented, and architecturally sound Power Query solution that is now scalable, reliable, and easy to manage. - ---- - -## The Initial Challenge: A Disconnected & Brittle Process - -The project began with a collection of disparate M query scripts. While functional, this initial state presented significant challenges: - -### Performance Issues -Multiple queries were independently loading and processing the same large source files, causing redundant data ingestion and slow refresh times. - -### Maintenance Burden -Hardcoded file paths and business logic scattered across numerous queries made the pipeline brittle and difficult to update or transfer to new environments. - -### Logical Flaws -Subtle but critical logical errors in data joins and aggregations led to incorrect row counts and incomplete variance calculations. - -### Lack of Documentation -The absence of consistent, clear commenting made the complex data flow difficult to understand and debug. - ---- - -## The Collaborative Process: Iterative Refinement & Validation - -The solution was achieved through an iterative dialogue between the User and the AI Assistant. The process was not a single command but a strategic, multi-turn workflow that leveraged the strengths of both parties: - -### 1. Initial Code Review -The User provided individual query snippets for review. - -### 2. AI-Generated Refactoring -The AI analyzed each query, proposed improvements based on best practices (e.g., naming conventions, removing redundant steps), and generated revised code. - -### 3. User Testing & Expert Feedback -The User, possessing deep domain knowledge, tested the refactored code and provided specific, actionable feedback, identifying logical flaws that the AI had missed (e.g., "The row counts for LABOR totals don't align with ALL totals"). - -### 4. AI Root Cause Analysis & Correction -The AI used the User's expert feedback to diagnose the underlying logical error (e.g., realizing that filtering rows upfront was incorrect and that a conditional calculation was needed). - -### 5. Holistic Application -The AI then applied the corrected pattern systematically across all affected queries in the pipeline. - -### 6. Final Documentation -The AI generated a final, fully-commented version of the entire pipeline, along with high-level documentation for stakeholders. - ---- - -## Key Technical Challenges & AI-Driven Solutions - -Throughout the process, the AI was instrumental in solving several complex technical challenges: - -### Challenge: Redundant data loading from three separate source files across multiple queries -**AI Solution:** Proposed and implemented a centralized architecture using three "Base Queries" to load each file only once. All subsequent queries were refactored to reference these base queries, dramatically improving performance and maintainability. - -### Challenge: Ensuring the variance calculation included all relevant parent hierarchies, even those with no corresponding investment or project costs -**AI Solution:** Diagnosed that the initial joins were implicitly filtering out necessary data. The AI redesigned all 'Variance' queries to use a `JoinKind.FullOuter`, then implemented a "coalescing" pattern to create a single, non-null master key and month column, ensuring all records were preserved. - -### Challenge: Ensuring conditional aggregations (e.g., "In Compliance" or "LABOR" totals) did not drop parent hierarchies that had zero costs in that category -**AI Solution:** After being guided by the User's feedback, the AI refactored all conditional aggregation queries. The flawed "filter-first" approach was replaced with a robust "unpivot-then-conditionally-calculate" pattern, guaranteeing correct row alignment. - -### Challenge: A recurring error where a 'Table.Pivot' operation would fail due to a column name collision with a 'Rnk' column added for sorting -**AI Solution:** The AI diagnosed the root cause—the column name "Rnk" was being unpivoted into a row value. The AI systematically applied a "remove first, add back last" pattern to all six '...Totals...' queries to resolve the issue permanently. - ---- - -## The User's Critical Role: The Human-in-the-Loop - -This use case underscores that the most successful outcomes are achieved when human expertise directs AI capabilities. The User's contribution was essential to the project's success, demonstrating key skills in AI collaboration: - -### Clear Vision -The User provided a clear end-state vision from the start (the example PDF report), which served as the ultimate goal for the entire pipeline. - -### Domain Expertise -The User understood the business logic (e.g., how variance should be calculated, which hierarchies must be included) and was able to identify when the AI's technically correct code was logically incorrect. - -### Diligent Testing & Validation -The User meticulously tested each version of the refactored code, catching subtle but critical errors (like misaligned row counts or null value conversion errors) that the AI had missed. - -### Specific, Actionable Feedback -The User provided precise, technical feedback (e.g., "The error is on the PivotVariance step," "I think it's related to a null in the month column") that enabled the AI to quickly diagnose and correct its mistakes. - -### Architectural Guidance -The User corrected the AI's flawed assumption about creating a new master key list, correctly identifying that the `SegmentAHierarchies` query was the intended single source of truth for parent keys. - ---- - -## Final Outcome & Conclusion - -The final deliverable is a fully refactored, production-ready Power Query pipeline that is: - -- **Efficient:** Loads each data source only once -- **Maintainable:** Uses parameters for file paths and has a clear, modular structure -- **Reliable:** Contains robust logic for handling nulls, conditional aggregations, and complete variance calculations -- **Documented:** Features a holistic summary and detailed, step-by-step comments for every query - -This use case demonstrates a powerful paradigm for modern development: combining human subject matter expertise with AI-driven code generation and analysis. The User's strategic direction and validation, paired with the AI's ability to rapidly generate, diagnose, and refactor complex code, resulted in a superior outcome that was achieved far more efficiently than a purely manual or purely automated approach would have allowed. - ---- - -## Resume-Ready Bullets - -- Directed the AI-assisted refactoring of a multi-stage Power Query data pipeline, transforming over a dozen brittle, manually-maintained M queries into a single, production-ready, fully-documented solution -- Provided expert domain knowledge and iterative validation to identify and correct critical logical errors in data joins and aggregations that the AI had initially missed -- Established a scalable "Base Query" architecture that eliminated redundant data loading, significantly improving pipeline performance and maintainability -- Demonstrated effective human-AI collaboration skills by providing clear vision, actionable feedback, and architectural guidance throughout an iterative development process - ---- - -## Status - -**Complete** - All sections have been merged. diff --git a/content/career/ai-collaborations/CLAUDE.md b/content/career/ai-collaborations/CLAUDE.md deleted file mode 100644 index 4352157..0000000 --- a/content/career/ai-collaborations/CLAUDE.md +++ /dev/null @@ -1,149 +0,0 @@ -# AI Collaborations Directory - -Documented case studies of professional AI collaboration workflows demonstrating strategic human-AI partnership patterns. - -## Purpose - -This directory captures structured analyses of AI-assisted work sessions, serving as: -- Portfolio pieces demonstrating AI collaboration competency -- Methodology documentation for replicable workflows -- Evidence of quantified efficiency gains -- Prompting strategy reference material - -## Directory Structure - -``` -ai-collaborations/ -├── CLAUDE.md # This file -├── _index.md # Index by theme, time saved, AI functions -├── 20260301-documentation-preset.md # Use case files (YYYYMMDD-slug.md) -├── 20260301-excel-automation.md -├── 20260301-html-template-system.md -└── ... -``` - -## Frontmatter Schema - -```yaml ---- -title: "Use Case Title" -date: 2026-03-01 # ISO 8601 date -primary_theme: [automation, governance] # Array of themes -ai_functions: [synthesis, generation] # What AI did -leverage_type: [cognitive, executional] # How AI was leveraged -confidence_level: 0.95 # 0-1 scale -estimated_time_saved_hrs: 6.0 # Quantified impact -tags: [tag1, tag2] # Searchable tags -role: "../roles/citi-svp-transformation.md" # Link to role -interview_ready: true # Portfolio-ready? -source_doc: "filename.pdf" # Original PDF in source-docs/ -status: partial # Optional: if incomplete -notes: "Continues in next PDF" # Optional: processing notes ---- -``` - -## Content Structure - -Each use case merges three document types from source PDFs: - -### From Internal Version -- **Business_Context**: Full enterprise details, specific challenges -- **Strategic_Framing**: Alignment to company goals -- **Deliverables_Produced**: Specific artifacts, filenames -- **Efficiency_Impact**: Quantitative metrics - -### From Meta Version -- **Cognitive_Offloading**: What tasks AI handled -- **Framework_Generation**: Novel patterns created -- **Decision_Structuring**: How AI organized complex decisions -- **Prompting_Analysis**: Effective vs ineffective prompts -- **Future_Recommendations**: Lessons learned - -### From Sanitized Version -- **Title & Context**: Portfolio-ready framing -- **Initial_Challenge**: Anonymized obstacles -- **AI_Strategy_Used**: Transferable approach -- **Iteration_and_Refinement**: Collaboration cycles -- **Final_Output**: Deliverable summary -- **Scalability_Potential**: Industry applications -- **Resume_Ready_Bullets**: Key accomplishments - -## Section Markers - -Use HTML comments to track content origin: -```markdown - -Content from Internal version... - - -Content from Meta version... - - -Content from Sanitized version... -``` - -## Naming Conventions - -- **Files**: `YYYYMMDD-slug-title.md` (e.g., `20260301-excel-automation.md`) -- **Slugs**: kebab-case, descriptive but concise -- **Tags**: lowercase, hyphenated for multi-word - -## Taxonomies - -### Primary Themes -- `automation` - Workflow automation, process efficiency -- `governance` - Standards, compliance, quality control -- `product_dev` - Building tools, templates, systems -- `research` - Information gathering, analysis -- `strategy` - Planning, decision-making - -### AI Functions -- `synthesis` - Combining information into coherent outputs -- `generation` - Creating new content, code, documentation -- `analysis` - Examining data, identifying patterns -- `reframing` - Restructuring problems or solutions -- `validation` - Checking accuracy, quality assurance -- `retrieval` - Finding information, research -- `pattern_recognition` - Identifying trends, anomalies - -### Leverage Types -- `cognitive` - Offloading mental work (planning, analysis) -- `executional` - Offloading implementation (code, writing) -- `strategic` - AI as co-designer, not just executor -- `communicative` - Adapting content for audiences -- `automation` - Replacing manual repetitive tasks - -## Source Documents - -Original PDFs stored in `/home/dom/personal/career/source-docs/`: -- `AI_Collaboration (1-20) - Mar 16 2026 - 10-07 AM.pdf` -- `AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf` -- `AI collaboration (41-60) - Mar 16 2026 - 10-12 AM.pdf` -- `AI Collaboration (61-86h - Mar 16 2026 - 10-15 AM.pdf` - -## Processing Workflow - -1. **Read PDF** - Extract use cases (typically 3 versions each) -2. **Create file** - Use naming convention `YYYYMMDD-slug.md` -3. **Merge versions** - Combine Internal + Meta + Sanitized -4. **Mark sections** - Use HTML comments for origin tracking -5. **Update _index.md** - Add to appropriate categories -6. **Handle partials** - Mark `status: partial` if incomplete - -## Integration Points - -- **Role files**: Link via `role:` frontmatter field -- **Skills**: Cross-reference from `skills/_index.md` (AI collaboration, prompt engineering) -- **Website**: Synced via `sync-career-content.js` prebuild script - -## Current Status - -| PDF | Use Cases | Status | -|-----|-----------|--------| -| 1-20 | 3 cases | Complete | -| 21-40 | 5 cases | Complete | -| 41-60 | 1 case | Complete | -| 61-73 | 0 new (supplementary) | Complete | -| 74-86 | 0 new (supplementary) | Complete | - -**All PDFs processed.** 9 unique use cases extracted and documented. diff --git a/content/career/ai-collaborations/_index.md b/content/career/ai-collaborations/_index.md deleted file mode 100644 index dbd6312..0000000 --- a/content/career/ai-collaborations/_index.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: AI Collaboration Case Studies -description: Documented examples of strategic AI collaboration demonstrating workflow automation, content generation, and human-AI partnership patterns -last_updated: 2026-03-16 ---- - -# AI Collaboration Case Studies - -A collection of structured case studies documenting professional AI collaboration workflows. Each case includes quantified efficiency gains, prompting strategies, and replicable frameworks. - -## Summary Metrics - -| Metric | Total | -|--------|-------| -| Total Cases | 9 | -| Total Time Saved | 33.9 hours | -| Avg. Confidence Level | 0.92 | -| Primary Tools | Citi Stylus Workspaces (Spark) | - ---- - -## All Cases (Chronological) - -| Date | Case | Theme | Time Saved | -|------|------|-------|------------| -| 2026-01-28 | [Regulatory Sustainability Testing](./20260128-regulatory-sustainability-testing.md) | Governance | 2.5 hrs | -| 2026-03-01 | [Documentation Preset](./20260301-documentation-preset.md) | Automation | 3.0 hrs | -| 2026-03-01 | [Excel Automation](./20260301-excel-automation.md) | Product Dev | 8.5 hrs | -| 2026-03-01 | [HTML Template System](./20260301-html-template-system.md) | Automation | 6.0 hrs | -| 2026-03-01 | [Stylus Doc Analysis](./20260301-stylus-doc-analysis.md) | Product Dev | 3.0 hrs | -| 2026-03-02 | [Markdown Combiner](./20260302-markdown-combiner.md) | Automation | 1.2 hrs | -| 2026-03-02 | [UAT Governance & Zephyr](./20260302-uat-governance-zephyr.md) | Governance | 2.0 hrs | -| 2026-03-06 | [IR Labor Cost Analysis](./20260306-ir-labor-cost-analysis.md) | Research | 4.0 hrs | -| 2026-03-06 | [Pipeline Refactoring](./20260306-pipeline-refactoring.md) | Product Dev | 6.0 hrs | - ---- - -## Cases by Primary Theme - -### Automation & Governance -- [Documentation Preset](./20260301-documentation-preset.md) - AI-Powered Strategic Documentation Framework (3.0 hrs saved) -- [HTML Template System](./20260301-html-template-system.md) - Brand-Enforcing Presentation Templates (6.0 hrs saved) -- [Markdown Combiner](./20260302-markdown-combiner.md) - PowerShell File Consolidation (1.2 hrs saved) -- [UAT Governance & Zephyr](./20260302-uat-governance-zephyr.md) - Test Coverage Validation (2.0 hrs saved) -- [Regulatory Sustainability Testing](./20260128-regulatory-sustainability-testing.md) - Consent Order Documentation (2.5 hrs saved) - -### Product Development & Training -- [Excel Automation](./20260301-excel-automation.md) - VTT Transcript to Training Materials (8.5 hrs saved) -- [Stylus Doc Analysis](./20260301-stylus-doc-analysis.md) - Corpus Summarization & QA (3.0 hrs saved) -- [Pipeline Refactoring](./20260306-pipeline-refactoring.md) - Power Query Data Pipeline (6.0 hrs saved) - -### Research & Analysis -- [IR Labor Cost Analysis](./20260306-ir-labor-cost-analysis.md) - Financial Analysis Workbook (4.0 hrs saved) - ---- - -## Cases by AI Function Type - -### Synthesis & Generation -- Documentation Preset -- Excel Automation -- HTML Template System -- Stylus Doc Analysis -- Markdown Combiner -- IR Labor Cost Analysis -- Pipeline Refactoring - -### Analysis & Pattern Recognition -- Documentation Preset -- Excel Automation -- Stylus Doc Analysis -- UAT Governance & Zephyr -- IR Labor Cost Analysis -- Regulatory Sustainability Testing -- Pipeline Refactoring - -### Validation & Quality Assurance -- HTML Template System -- Stylus Doc Analysis -- UAT Governance & Zephyr -- IR Labor Cost Analysis -- Pipeline Refactoring - -### Reframing & Problem Solving -- Pipeline Refactoring (diagnosed logical errors, proposed architectural solutions) - ---- - -## Cases by Leverage Type - -### Cognitive Offloading -All cases demonstrate significant cognitive offloading, where complex planning and execution tasks were transferred to AI. - -### Strategic Partnership -- Documentation Preset (AI as co-designer) -- HTML Template System (AI as iterative collaborator) -- Regulatory Sustainability Testing (AI as governance advisor) -- Pipeline Refactoring (AI as code reviewer and refactoring partner) - -### Executional Automation -- Excel Automation (transcript analysis, content generation) -- Markdown Combiner (file consolidation) -- IR Labor Cost Analysis (Python/pandas pipeline) -- Pipeline Refactoring (Power Query code generation) - -### Advisory & Governance -- UAT Governance & Zephyr (test coverage validation) -- Regulatory Sustainability Testing (documentation drafting) - ---- - -## Framework Patterns - -These cases established several reusable AI collaboration patterns: - -1. **Iterative Refinement Cycle**: Generate → Feedback → Refine → Validate -2. **Multi-Audience Documentation**: Internal + External + Meta versions -3. **Cognitive Offloading Taxonomy**: Task → AI Functions → Leverage Type mapping -4. **Master Prompt Pattern**: Structured prompts for consistent, high-quality outputs -5. **Multi-Persona Workflow**: Synthesizer → QA Analyst → Strategic Analyst -6. **Self-Validating Documentation**: AI reviews its own output for accuracy -7. **Governance-First Advisory**: AI as reasoning assistant with human-in-the-loop controls -8. **Human-in-the-Loop Development**: Expert domain knowledge + AI code generation - ---- - -## Source Documents - -All cases extracted from: -- `AI_Collaboration (1-20) - Mar 16 2026 - 10-07 AM.pdf` — Complete -- `AI collaboration (21-40) - Mar 16 2026 - 10-10 AM.pdf` — Complete -- `AI collaboration (41-60) - Mar 16 2026 - 10-12 AM.pdf` — Complete -- `AI Collaboration (61-73) - Mar 16 2026 - 5-30 PM.pdf` — Complete (supplementary versions only) -- `AI Collaboration (74-86) - Mar 16 2026 - 5-31 PM.pdf` — Complete (supplementary versions only) - -See `/source-docs/` for original PDFs. - ---- - -## Processing Status - -| PDF | Use Cases | Status | -|-----|-----------|--------| -| 1-20 | 3 cases | Complete | -| 21-40 | 5 cases | Complete | -| 41-60 | 1 case | Complete | -| 61-73 | 0 new (supplementary) | Complete | -| 74-86 | 0 new (supplementary) | Complete | - -**All PDFs processed.** 9 unique use cases extracted and documented. diff --git a/content/career/certifications/_index.md b/content/career/certifications/_index.md deleted file mode 100644 index 6ccd605..0000000 --- a/content/career/certifications/_index.md +++ /dev/null @@ -1,39 +0,0 @@ -# Certifications & Training - -Professional development credentials. - -## Professional Certifications - -| Certification | Issuer | Obtained | Status | Evidence | -|---------------|--------|----------|--------|----------| -| FINRA Series 7 | FINRA | October 2008 | Inactive | [BNP Paribas Role](../roles/bnp-paribas-client-services.md) | - -*Note: Series 7 licenses require ongoing registration with a FINRA member firm. Status is inactive when not currently sponsored.* - -## Completed Training - -| Course/Program | Provider | Completed | Context | Evidence | -|----------------|----------|-----------|---------|----------| -| Six Sigma Improvement Initiative | BNP Paribas | 2010-2013 | Appointed to Fixed Income Documentation Team initiative; improved trade processing by ~10% | [Role](../roles/bnp-paribas-client-services.md) | - -## Academic Credentials - -| Degree | Institution | Year | GPA | Evidence | -|--------|-------------|------|-----|----------| -| MBA | Carnegie Mellon University, Tepper School of Business | 2015 | 3.68 | [Education](../education/carnegie-mellon-mba.md) | -| BS Finance | Rutgers University, Rutgers Business School | 2008 | 3.2 | [Education](../education/rutgers-bs-finance.md) | - -*See [Education](../education/_index.md) for detailed academic history including coursework and honors.* - -## Skills Mapping - -Certifications and training mapped to demonstrated skills: - -| Credential | Skills Demonstrated | -|------------|---------------------| -| Series 7 | Securities regulations, client suitability, trading operations | -| Six Sigma | Process optimization, root cause analysis, continuous improvement | -| MBA (CMU Tepper) | Strategic thinking, financial analysis, data analytics, leadership | -| BS Finance (Rutgers) | Financial analysis, quantitative methods | - -*See [Skills](../skills/_index.md) for complete skills inventory with proficiency levels and evidence.* diff --git a/content/career/context.md b/content/career/context.md deleted file mode 100644 index 7e7b990..0000000 --- a/content/career/context.md +++ /dev/null @@ -1,31 +0,0 @@ -# Career Context - -## Current Status -- **Role**: SVP, Transformation Senior Lead at Citi -- **Focus**: Regulatory remediation, enterprise risk/control framework transformation -- **Location**: New Jersey - -## Career Coaching Objectives -Seeking HR-style career coaching to: -- Clarify career objectives -- Align skills with job opportunities -- Develop personalized action plan for professional development -- Job search readiness - -## Target Direction -Exploring opportunities at the intersection of enterprise transformation and AI: -- AI-powered transformation initiatives -- Enterprise AI strategy and implementation -- Roles leveraging both business acumen and technical curiosity -- Building and scaling new capabilities within organizations - -## Positioning Challenges -- Difficulty describing background as a generalist -- Resonates with "ambitious generalist" framing (broad skills, adaptable) -- Career spans operations → consulting → advisory → corporate strategy → transformation - -## Key Differentiators -- Complex-to-simple translation (consistent feedback across roles) -- Hands-on with technology (VBA → AI tools) -- Deep regulatory/compliance experience -- Quantitative foundation (CMU Tepper, 720 GMAT) diff --git a/content/career/education/_index.md b/content/career/education/_index.md deleted file mode 100644 index 1ffe9f6..0000000 --- a/content/career/education/_index.md +++ /dev/null @@ -1,38 +0,0 @@ -# Education - -Academic background and degrees. - -## Degrees - -| Degree | Field | Institution | Year | GPA | -|--------|-------|-------------|------|-----| -| MBA | Business Administration | Carnegie Mellon (Tepper) | 2015 | 3.68 | -| BS | Finance | Rutgers University | 2008 | 3.2 | - -## Details - -- [Carnegie Mellon MBA](carnegie-mellon-mba.md) - Full details including coursework, activities, awards -- [Rutgers BS Finance](rutgers-bs-finance.md) - Undergraduate degree - -## Honors & Distinctions - -### Graduate -- **Consortium Fellow** - The Consortium for Graduate Study in Management -- **Merit Scholar** - CMU Tepper -- **1st Place** - 2013 SCIO Case Competition (Team Lead) -- **2nd Place** - 2013 McKinsey & Co. Case Competition -- **Finalist** - 2013 ROMBA National Case Competition - -### Undergraduate -- **Dean's List** - Spring 2005, Fall 2005 -- **Phi Delta Theta** - Treasurer - -## International Experience - -**Hong Kong-China Capstone** (CMU, 2015) -- 12-unit immersive international business project -- Grade: A - -## See Also - -- [Coursework Index](coursework/_index.md) - Detailed course inventory (27 MBA courses) diff --git a/content/career/education/carnegie-mellon-mba.md b/content/career/education/carnegie-mellon-mba.md deleted file mode 100644 index 8eb1be0..0000000 --- a/content/career/education/carnegie-mellon-mba.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -institution: "Carnegie Mellon University" -school: "Tepper School of Business" -degree: "Master of Business Administration (MBA)" -field_of_study: "Business Administration" -start_date: 2013-08 -end_date: 2015-05-17 -location: "Pittsburgh, PA" -gpa: 3.68 -gmat: 720 -honors: - - "Consortium Fellow" - - "Merit Scholar" -concentrations: - - "Finance" - - "Economics" - - "Information Systems" -activities: - - role: "V.P., Member Development" - organization: "Consulting Club" - - role: "Class Representative" - organization: "Graduate Student Assembly" - - role: "V.P. Finance" - organization: "Out & Allied" - - role: "Member" - organization: "Graduate Finance Association" -awards: - - name: "1st Place - SCIO Case Competition" - year: 2013 - note: "Team Lead" - - name: "2nd Place - McKinsey & Co. Case Competition" - year: 2013 - - name: "Finalist - ROMBA National Case Competition" - year: 2013 -international_experience: "Hong Kong-China Capstone Project" ---- - -## Summary - -Full-time MBA at Carnegie Mellon's Tepper School of Business with concentrations in Finance, Economics, and Information Systems. Achieved 3.68 GPA while holding leadership positions and competing in national case competitions. - -## Academic Performance - -**Cumulative GPA:** 3.68/4.0 (192 units) - -### Semester-by-Semester -| Semester | GPA | -|----------|-----| -| Fall 2013 | 3.69 | -| Spring 2014 | 3.76 | -| Fall 2014 | 3.58 | -| Spring 2015 | 3.67 | - -### Top Performance Areas (A/A+ grades) -- **Financial Accounting:** Acct I, II, Business Accounting I (A+) -- **Strategy & Operations:** Corporate Strategy, Corporate Restructuring, Optimization -- **Statistics & Analytics:** Data Mining, Probability & Statistics -- **Communications:** Writing for Managers, Interpersonal Communications - -## Leadership & Activities - -### Consulting Club (V.P., Member Development) -- Led member development and professional preparation - -### Graduate Student Assembly (Class Representative) -- Represented MBA class in student governance - -### Case Competitions -- **1st Place** - 2013 SCIO Case Competition (Team Lead) -- **2nd Place** - 2013 McKinsey & Co. Case Competition -- **Finalist** - 2013 ROMBA National Case Competition - -## International Experience - -**Hong Kong-China Capstone Project** (Spring 2015) -- 12-unit intensive capstone with international travel -- Grade: A -- Applied international business strategy in emerging market context - -## Honors - -- **Consortium Fellow** - The Consortium for Graduate Study in Management -- **Merit Scholar** - CMU Tepper merit-based scholarship diff --git a/content/career/education/coursework/_index.md b/content/career/education/coursework/_index.md deleted file mode 100644 index a5d406f..0000000 --- a/content/career/education/coursework/_index.md +++ /dev/null @@ -1,144 +0,0 @@ -# Coursework - -Detailed inventory of MBA courses by subject area. - -**Institution:** Carnegie Mellon University, Tepper School of Business -**Total Courses:** 27 graded + 2 pass/fail -**Cumulative GPA:** 3.68/4.0 - -## Confidence Legend - -- **High**: Can discuss in depth, apply in practice -- **Medium**: Solid understanding, may need refresher -- **Low**: Foundational exposure, would need study to apply - ---- - -## Accounting & Financial Management (6 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Financial and Managerial Accounting I | A | High | Financial reporting, cost analysis | -| Financial and Managerial Accounting II | A | High | Advanced accounting, financial statements | -| Business Accounting I | A+ | High | Practical accounting applications | -| Financial Statement Analysis | A- | High | Valuation, ratio analysis | -| Modern Data Management | B+ | Medium | Data organization, database systems | -| Financial Regulation | A- | High | Compliance, regulatory frameworks | - -**Career Relevance:** Foundation for all financial services roles. Direct application in BRD writing, financial governance at Citi. - ---- - -## Finance (5 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Finance I | B+ | Medium | Corporate finance fundamentals | -| Finance II | A- | High | Advanced finance, capital structure | -| Monetary Policy US & Abroad | A | High | Macroeconomics, policy analysis | -| Venture Capital & Private Equity | A- | High | VC investments, deal structure | -| B2B Marketing | B+ | Medium | Commercial negotiations | - -**Career Relevance:** Applied at Strategy& for M&A analysis, Morgan Stanley for wealth management strategy. - ---- - -## Statistics & Quantitative Analysis (3 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Probability and Statistics | A | High | Statistical methods, data analysis | -| Statistical Decision Making | B+ | Medium | Hypothesis testing, analytical decisions | -| Data Mining | A | High | Predictive analytics, pattern recognition | - -**Career Relevance:** Foundation for data architecture work at Citi, analytical rigor in consulting engagements. - ---- - -## Economics (2 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Managerial Economics | B | Medium | Microeconomic principles, pricing | -| Emerging Markets | A | High | Cross-border strategy, market analysis | - -**Career Relevance:** International perspective for global financial services work. - ---- - -## Operations & Strategy (4 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Operations Management | A- | High | Process optimization, supply chain | -| Optimization | A- | High | Mathematical optimization | -| Corporate Strategy | A | High | Strategic planning, competitive positioning | -| Corporate Restructuring | A | High | M&A, organizational transformation | - -**Career Relevance:** Core to Strategy& consulting work. Corporate Restructuring directly relevant to $4B acquisition analysis. - ---- - -## Management & Leadership (5 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Managing People and Teams | A- | High | Team dynamics, motivation | -| Managing Networks & Organizations | A- | High | Organizational structure, stakeholder management | -| Ethics & Leadership | A- | High | Leadership principles, ethical decisions | -| Managing International Capital Knowledge | B+ | Medium | Global knowledge management | -| Business Networks | B+ | Medium | Network analysis, influence | - -**Career Relevance:** Foundation for people management role at Citi (2023), stakeholder management across all roles. - ---- - -## Communications (3 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Management Presentations | A- | High | Public speaking, executive communication | -| Writing for Managers | A | High | Business writing, technical communication | -| Interpersonal Communications | A | High | Dialogue, emotional intelligence | - -**Career Relevance:** Consistently cited strength in performance reviews - "translating complex into understandable." - ---- - -## International Business (2 courses) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Hong Kong-China Abroad | B | Medium | Cultural immersion, market research | -| Hong Kong-China Capstone | A | High | Applied international strategy | - -**Career Relevance:** 12-unit immersive project. Supports 55+ countries traveled, global perspective. - ---- - -## Government & Policy (1 course) - -| Course | Grade | Confidence | Skills Gained | -|--------|-------|------------|---------------| -| Government & Business | A | High | Public policy, regulatory environment | - -**Career Relevance:** Foundation for regulatory work at Citi (Consent Order), PwC (Resolution Plans). - ---- - -## Summary by Strength - -### Strongest Areas (mostly A/A+) -1. Accounting & Financial Management -2. Strategy & Operations -3. Communications -4. Government & Policy - -### Solid Foundation (A-/B+) -1. Finance -2. Statistics & Quantitative -3. Management & Leadership - -### Opportunity to Refresh -1. Economics fundamentals -2. International capital management diff --git a/content/career/education/rutgers-bs-finance.md b/content/career/education/rutgers-bs-finance.md deleted file mode 100644 index 9ee9702..0000000 --- a/content/career/education/rutgers-bs-finance.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -institution: "Rutgers University" -school: "Rutgers Business School" -degree: "Bachelor of Science" -field_of_study: "Finance" -start_date: 2004-09 -end_date: 2008-05 -location: "New Brunswick, NJ" -gpa: 3.2 -honors: - - "Dean's List - Spring 2005" - - "Dean's List - Fall 2005" -activities: - - role: "Former Treasurer" - organization: "Phi Delta Theta Fraternity" ---- - -## Summary - -Undergraduate degree in Finance from Rutgers Business School, graduating into the 2008 financial crisis with immediate placement at BNP Paribas. - -## Academic Performance - -**GPA:** 3.2/4.0 - -### Honors -- Dean's List - Spring 2005 -- Dean's List - Fall 2005 - -## Activities - -### Phi Delta Theta Fraternity -- Served as Treasurer -- Financial management and budgeting responsibilities - -## Career Outcome - -Secured full-time position at BNP Paribas immediately upon graduation (July 2008), joining the rotational analyst program in Trading Operations during the global financial crisis. diff --git a/content/career/images/Headshot (sunset).jpg b/content/career/images/Headshot (sunset).jpg deleted file mode 100644 index 8f4b9ec..0000000 Binary files a/content/career/images/Headshot (sunset).jpg and /dev/null differ diff --git a/content/career/images/ImageLinkedin.png b/content/career/images/ImageLinkedin.png deleted file mode 100644 index 979cb59..0000000 Binary files a/content/career/images/ImageLinkedin.png and /dev/null differ diff --git a/content/career/images/cartoon-headshot.jpg b/content/career/images/cartoon-headshot.jpg deleted file mode 100644 index 44f43f6..0000000 Binary files a/content/career/images/cartoon-headshot.jpg and /dev/null differ diff --git a/content/career/leadership/_index.md b/content/career/leadership/_index.md deleted file mode 100644 index b4ab0fb..0000000 --- a/content/career/leadership/_index.md +++ /dev/null @@ -1,63 +0,0 @@ -# Leadership & Mentorship - -People leadership, mentorship, and community involvement. - -## Team Leadership - -| Period | Role | Team Size | Context | Evidence | -|--------|------|-----------|---------|----------| -| 2023-Present | SVP, Transformation Senior Lead | 2 direct reports | First-time people manager at Citi; distributed team (NYC/Tampa) | [Role](../roles/citi-svp-transformation.md), [Story](../stories/first-time-manager.md) | -| 2018-2019 | Senior Consultant | 40+ contracted workers | Managed risk and regulatory engagements at Treliant | [Role](../roles/treliant-senior-consultant.md) | - -## Cross-Functional Leadership - -Leadership through influence, without formal reporting authority. - -| Period | Initiative | Scope | Outcomes | Evidence | -|--------|------------|-------|----------|----------| -| 2022-2023 | MRA Design Council | 5 governance constituencies | Full alignment achieved; model transitioned from design tool to ongoing governance forum | [Story](../stories/stakeholder-influence-governance.md) | -| 2022 | Board Dashboard Governance | Cross-silo reconciliation | Dashboard delivered on time with audit-ready documentation | [Story](../stories/governance-under-pressure.md) | -| 2019-2020 | Concierge Service Model | Operations, Technology, Product | ~$15B AUM opportunity; 40%+ onboarding improvement | [Story](../stories/concierge-model-innovation.md) | - -## Mentorship - -| Period | Mentee/Scope | Focus Areas | Outcomes | -|--------|--------------|-------------|----------| -| 2023-Present | 2 direct reports (experienced professionals) | Priorities, workload management, cross-functional blockers | Established 1:1 cadences, provided clarity on objectives, removed blockers | - -**Development Approach:** -- Balance autonomy with guidance for experienced professionals -- Clarify "why" behind assignments, not just "what" -- Provide direct feedback on deliverables (what worked, what to improve) -- Protect time for development conversations amid delivery pressure - -## Academic & Community Leadership - -| Period | Role | Organization | Context | -|--------|------|--------------|---------| -| 2013-2015 | V.P., Member Development | CMU Consulting Club | Led member development and professional preparation for consulting careers | -| 2013-2015 | Class Representative | Graduate Student Assembly | Represented MBA class in student governance | -| 2013-2015 | V.P. Finance | Out & Allied | Financial management for LGBTQ+ student organization | -| 2004-2008 | Treasurer | Phi Delta Theta Fraternity | Financial management and budgeting responsibilities | - -## Case Competition Leadership - -| Year | Competition | Result | Role | -|------|-------------|--------|------| -| 2013 | SCIO Case Competition | 1st Place | **Team Lead** | -| 2013 | McKinsey & Co. Case Competition | 2nd Place | Team Member | -| 2013 | ROMBA National Case Competition | Finalist | Team Member | - -## Honors & Recognition - -- **Consortium Fellow** - The Consortium for Graduate Study in Management (national fellowship recognizing leadership and diversity) -- **Merit Scholar** - CMU Tepper merit-based scholarship - -## Leadership Philosophy - -Based on feedback and experience: - -1. **Autonomy requires clarity** - Giving people autonomy works when they understand priorities and success criteria -2. **Influence through rigor** - Build credibility through quality of thinking and clear communication -3. **Make the abstract concrete** - People align when they see actual work, not theoretical frameworks -4. **Facilitate, don't dictate** - Structure decisions so stakeholders own them collectively diff --git a/content/career/profile.md b/content/career/profile.md deleted file mode 100644 index 8738098..0000000 --- a/content/career/profile.md +++ /dev/null @@ -1,123 +0,0 @@ ---- -name: "Dom Mangonon" -headline: "SVP, Transformation Senior Lead at Citi" -location: "New Jersey" -email: "dom.mangonon@gmail.com" -linkedin: "https://linkedin.com/in/dommangonon" -twitter: "https://x.com/collapsecontext" -substack: "https://dommangonon.substack.com" -github: "https://dommango.github.io" -website: "" -travel: "55+ countries across 5 continents" -interests: - [ - "trekking", - "snowboarding", - "live music", - "DIY electronics", - "NY sports", - "AI exploration", - ] -background: "First-generation American" ---- - -## Professional Summary - -Senior financial services executive with 17 years of experience spanning strategy, enterprise transformation, regulatory remediation, and complex operating model change across global institutions. Currently serves as an execution lead for the Citi's highest priority firm-wide initiatives, including critical regulatory commitments and the transformation of the enterprise risk and control framework. Recognized for translating complex challenges into clear governance and delivery models, strengthening execution discipline, and systematically applying AI-enabled solutions to automate workflows, enhance decision making, and scale operational efficiencies. - -## Career Themes - -### 1. Complex-to-Simple Translation - -Consistent feedback across roles: ability to take disorganized, complex information and synthesize into clear deliverables for leadership and stakeholders. Demonstrated at Citi (CEO dashboards, regulatory requirements to BRDs), Strategy& (client presentations), and BNP (client reporting). - -### 2. Process Optimization & Efficiency - -From Six Sigma initiatives at BNP Paribas to automation at Citi, consistently identified and implemented efficiency improvements. Created Hot Keys workshops, VBA macros, and streamlined reporting processes across organizations. - -### 3. Regulatory & Risk Expertise - -Deep experience in regulatory environments: Consent Order remediation at Citi, Resolution Plans at PwC, and risk management during the 2008 financial crisis at BNP Paribas. Understand both strategic and operational dimensions of compliance. - -### 4. Financial Services Breadth - -Worked across the financial services value chain: investment banking operations, strategy consulting for banks and wealth managers, corporate transformation. Understand institutions from trading floor to boardroom. - -### 5. Quantitative Foundation - -MBA from CMU Tepper (3.68 GPA) with strong performance in analytics, strategy, and finance. Apply quantitative rigor to strategic problems. - -### 6. Technology & Automation - -Lifelong tinkerer with a bias toward building. From VBA macros at BNP Paribas to AI-powered automation at Citi, consistently leveraged technology to solve problems. Currently exploring AI tools and their application to enterprise transformation—this website itself was built via "vibecoding" with Claude Code. - -## Career Arc - -``` -Operations (BNP) → Strategy Consulting (PwC/Strategy&) → Advisory (Treliant) - → Corporate Strategy (MS) → Enterprise Transformation (Citi) -``` - -**Pattern:** Progressive shift from execution to strategy to transformation leadership, with each role building on prior experience. - -### The Through-Line - -**BNP Paribas (2008–2013)** — Started in operations during the 2008 financial crisis. Working inside a large bank as the system nearly collapsed gave me an appreciation for the many functions that keep a bank running — and exposed me to its fragility. Over five years I built deep operational knowledge across trading desks, client services, and global reporting, but I knew I wanted to move beyond the middle and back office. - -**CMU Tepper MBA (2013–2015)** — Chose Tepper specifically for its analytical rigor and quantitative reputation. The curriculum was exactly what I needed to bridge operations experience with strategic thinking. Tepper was also at the frontier of research in emerging technologies like AI and machine learning — a thread I didn't fully pull on until a decade later. Case competition wins (1st SCIO, 2nd McKinsey) and the Consortium Fellowship validated the pivot. - -**PwC / Strategy& (2014–2017)** — Consulting gave me the strategic toolkit: M&A analysis, operating model design, client migration planning. I was working at the intersection of wealth management strategy and execution — sizing $4B acquisition targets, migrating 32,000 clients, identifying $14M in run-rate savings. Intense, high-impact work, but the travel and pace eventually caught up. - -**Treliant (2018–2019)** — After burning out on consulting travel, I moved back to the NY area to settle down. An old PwC partner offered the chance to build a wealth management advisory practice from scratch — an entrepreneurial opportunity I couldn't pass up. In four months I co-authored a published article series on sales practice risk in ThinkAdvisor and mapped out 10 go-to-market campaigns. Unfortunately the firm decided to take the business in a different direction and terminated the practice before it could gain traction. Short tenure, but I delivered and published. - -**Morgan Stanley (2019–2020)** — Another PwC network connection brought me to Morgan Stanley's wealth management strategy group. I led projects supporting ~$15B in new AUM opportunity and designed a concierge service model that cut onboarding time by 40%+. Ultimately wasn't the right long-term fit. - -**Citi (2021–Present)** — Citi was eager to hire and the opportunity to lead large-scale enterprise transformation was too compelling to pass up. Started as a contractor and proved myself quickly — became one of the fastest contractor-to-hire conversions many had seen, with my manager Angelique as a huge advocate. Since then I've closed critical regulatory commitments, re-engineered data architecture across 150+ investments (~$1.1B visibility), overhauled financial governance for a ~$7.1B portfolio, and established PM standards across 15,000+ projects. - -**The AI Turn (2025)** — In early 2025 I made a deliberate decision to run towards AI rather than be anxious about it. I committed to finding real use cases — both personal and professional — to genuinely engage. Citi's enterprise AI rollout gave me free tokens to explore with, and I went deep: 9 documented collaboration case studies, 33.9 hours of quantified efficiency gains, published frameworks for human-AI partnership. The same instinct that made me a builder (VBA macros, Hot Keys workshops, process automation) now has a much more powerful set of tools. - -### Why It All Connects - -Each chapter built something the next one needed. Operations gave me institutional knowledge. The MBA gave me analytical frameworks. Consulting taught me to structure ambiguity for executive audiences. Building a practice showed me what entrepreneurial ownership feels like. Wealth management strategy deepened my client lens. And transformation at Citi brought it all together — running large, complex programs across regulatory, data, financial, and people dimensions. - -The AI thread was always there in the background (Tepper's research, automation at every stop) but became the foreground in 2025. Now I'm looking for the role that combines everything: enterprise transformation experience, strategic thinking, hands-on technical comfort, and genuine conviction about what AI changes. - -## What I'm Looking For - -Exploring opportunities at the intersection of enterprise transformation and AI. My career has consistently involved translating complex systems into actionable frameworks—skills that translate directly to AI implementation, adoption, and change management. - -**Interested in:** - -- AI-powered transformation initiatives -- Enterprise AI strategy and implementation -- Roles that leverage both business acumen and technical curiosity -- Building and scaling new capabilities within organizations - -**What I bring:** - -- Deep experience navigating complex, regulated environments -- Track record of simplifying complexity for executive audiences -- Hands-on comfort with technology and automation -- Strategic perspective combined with execution focus - ---- - -## Beyond Work - -### Builder & Tinkerer - -I've always been drawn to making things work. Whether it's VBA macros to automate trading desk workflows, DIY electronics projects, or building this website through AI-assisted "vibecoding" with Claude Code—I find satisfaction in turning ideas into working systems. - -Currently exploring the intersection of AI and practical problem-solving: How can these tools change how we work? How do we integrate them thoughtfully into enterprise environments? This website is both a showcase and an experiment in that exploration. - -### Adventurer - -**55+ countries across 5 continents.** Not just checking boxes—seeking out experiences that push comfort zones. - -Favorite adventures include trekking in Patagonia, exploring Southeast Asia, and finding live music venues in unexpected cities. Snowboarding whenever mountains and winter align. - -Travel has shaped how I approach work: comfort with ambiguity, adaptability to new contexts, and appreciation for different ways of solving problems. - -### NY Sports - -Lifelong New York sports fan—the highs, the lows, and everything in between. There's something about the shared experience of rooting for a team that builds community and teaches patience. diff --git a/content/career/projects/_index.md b/content/career/projects/_index.md deleted file mode 100644 index e0fef5c..0000000 --- a/content/career/projects/_index.md +++ /dev/null @@ -1,70 +0,0 @@ -# Projects - -Notable projects across roles. - -## By Impact - -### Enterprise-Scale ($1B+) -| Project | Role | Impact | -|---------|------|--------| -| [Consent Order Remediation](citi-consent-order.md) | Citi | $7.1B portfolio governance | -| [Strategic Investment Data Architecture](citi-data-architecture.md) | Citi | $1.1B visibility | - -### Strategic ($100M+) -| Project | Role | Impact | -|---------|------|--------| -| Online Brokerage M&A Analysis *(planned)* | Strategy& | $4B acquisition | -| Wealth Client Migration *(planned)* | Strategy& | $465M risk reduction | - -### Operational ($10M+) -| Project | Role | Impact | -|---------|------|--------| -| Insurance TOM Optimization *(planned)* | Strategy& | $14M run-rate savings | -| [Concierge Service Model](ms-concierge-model.md) | Morgan Stanley | $15B AUM opportunity | - -## By Role - -### Citi (2021-Present) -- [MRA Reporting Transformation](citi-mra-transformation.md) - Enterprise operating model design & governance -- [Consent Order Remediation](citi-consent-order.md) - Article XII.1.e RBCMs -- CEO/Board Dashboards *(planned)* - Strategic reporting -- Financial Governance Framework *(planned)* - $7.1B portfolio -- PM Standards Implementation *(planned)* - 15,000+ projects - -### Morgan Stanley (2019-2020) -- [Concierge Service Model](ms-concierge-model.md) - Wealth management - -### Strategy& (2015-2017) -- Online Brokerage M&A *(planned)* - Growth strategy -- Wealth Client Migration *(planned)* - Segmentation -- Insurance TOM *(planned)* - Cost optimization - -### BNP Paribas (2008-2013) -- Six Sigma Initiative *(planned)* - Trade processing -- Global Reporting Tools *(planned)* - 15+ tools implemented - -## By Technology/Domain - -### Regulatory & Governance -- Consent Order remediation -- Resolution Plans ("living wills") -- MRA lifecycle management - -### Data & Analytics -- Strategic investment data architecture -- PM Core Metrics framework -- CEO/Board dashboards - -### Process Optimization -- Six Sigma trade processing -- VBA automation -- EUC streamlining - -### Strategy & M&A -- Acquisition target identification -- Customer segmentation -- Operating model design - ---- - -*Note: Items marked (planned) do not yet have detail files. Individual project files to be created during discovery discussions to capture full context and STAR-format narratives.* diff --git a/content/career/projects/citi-consent-order.md b/content/career/projects/citi-consent-order.md deleted file mode 100644 index ba6f629..0000000 --- a/content/career/projects/citi-consent-order.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: "Consent Order Remediation Program" -company: "Citi" -project_type: "Enterprise Regulatory Transformation" -start_date: 2021-09-07 -end_date: present -scale: "Enterprise-wide" -budget: "$7.1B investment portfolio oversight" -tags: [consent-order, regulatory-remediation, article-xii, governance-framework, enterprise-transformation, compliance] -skills: [regulatory-translation, governance-design, stakeholder-management, change-management, executive-communication, evidence-based-closure] -competencies: [problem-solving, strategic-thinking, execution, leadership, communication] -impact_types: [regulatory-compliance, efficiency, team-growth] ---- - -## Executive Summary - -Led multiple workstreams within Citi's highest-priority regulatory remediation program—the Consent Order response mandated by the OCC and Federal Reserve. Responsibilities spanned operating model design, governance framework implementation, sustainability testing, and executive reporting across 15,000+ projects and a $7.1B investment portfolio. - -**Scope:** Article XII.1.e requirements → Operating model design → Sustainability testing → BAU transition - ---- - -## Strategic Context - -**Regulatory Background:** In 2020, Citi entered into Consent Orders with the OCC and Federal Reserve requiring comprehensive remediation of risk management, data governance, and internal controls. Article XII specifically addressed project/program management, requiring demonstrable governance across all transformation initiatives. - -**Enterprise Challenge:** -- 15,000+ projects across fragmented systems (RET, iCAPS, PTS) -- Vague regulatory language requiring interpretation into operational procedures -- Competing timelines and multiple parallel workstreams -- Need for Board-grade evidence packages and sustainable controls - -**My Entry Point:** Brought in as contractor (Sep 2021) to support remediation design; converted to full-time SVP (Mar 2022) based on impact and leadership capabilities. - ---- - -## My Core Contributions - -### 1. Article XII.1.e Requirements Translation - -**Challenge:** The Consent Order used abstract regulatory language ("effective reporting," "assurance-readiness") without operational definitions. Different business lines interpreted requirements differently. - -**What I Did:** -- Conducted **first-principles interpretation** of regulatory intent from Consent Order documents and auditor expectations -- Created **Unmapped MRA Requirements documents** (v1.8 - v1.12) with progressive clarification and embedded version lineage -- Built **field inventory and sourcing logic** mapping abstract requirements to concrete data points -- Documented **assumptions and boundary conditions** to prevent scope creep - -**Outcome:** -- Unified interpretation across business units -- Auditable evidence of regulatory intent translation -- Foundation for operating model design - -### 2. MRA Reporting Operating Model - -**Challenge:** Move from "what the requirement says" to "how we execute it sustainably." - -**What I Did:** -- **Owned the MRA Design Council workstream** defining operating model architecture -- Drafted **QC decision matrices** for Pass/Fail/N/A determinations -- Designed **governance architecture** with weekly oversight tracking and escalation constructs -- Built **Committee presentation templates** standardizing reporting across business units - -**Outcome:** -- Sustainable operating model owned by Oversight Function and MRAAOF -- Regulators approved approach without major revisions -- BAU teams execute independently - -*See: [MRA Reporting Transformation](citi-mra-transformation.md) for detailed project narrative* - -### 3. Sustainability Testing & Evidence Closure - -**Challenge:** Prove that the operating model actually works before handing to BAU. - -**What I Did:** -- **Led cross-functional testing** for RBCM 10.3 (Execute-phase) and RBCM 11.3 (Close-phase) -- Designed **testing strategy** with sampling approach and applicability rules -- **Personally executed majority of testing** due to resource constraints -- Created **closure packages** with evidence traceability and governance alignment - -**What Made It Hard:** -- Requirements still evolving during testing period -- Multiple close-phase requirements with tight timelines -- Balancing thoroughness with reviewer capacity - -**Outcome:** -- 4+ regulatory commitments closed on time -- Sustainability packages validated by IA, ORM, and MRAOF -- Lessons learned feeding into future requirement updates - -### 4. Enterprise Governance & Board Reporting - -**Challenge:** Translate multi-system complexity into language executives can understand and act on. - -**What I Did:** -- **Developed 3 strategic dashboards** for CEO and Board reporting -- Established **PM Core Metrics framework** with standardized definitions -- Created **financial governance framework** for $7.1B portfolio -- Built **reconciliation workbooks** showing data lineage and variance tracking - -**Outcome:** -- Board-grade reporting with defensible, sourced definitions -- Executive confidence in portfolio visibility -- Global PM standards adopted across 15,000+ projects - -### 5. Senior Oversight Function Launch - -**Challenge:** Quality and timeliness of regulatory remediation delivery needed structural improvement. - -**What I Did:** -- **Designed new senior oversight function** with clear roles and responsibilities -- Built **escalation constructs** for issue identification and resolution -- Created **governance templates** enabling consistent oversight across workstreams -- **Facilitated consensus** across Oversight, ORM, IA, and business units - -**Outcome:** -- Improved regulatory remediation delivery quality -- Structured accountability without additional headcount -- Model replicated across other Consent Order workstreams - ---- - -## RBCM Ownership Summary - -| RBCM | Scope | My Role | -|------|-------|---------| -| CAO-XIIE.4 | Work effort governance structure | Contributor | -| CAO-XIIE.6 | PM metrics & Board reporting | Design authority | -| CAO-XIIE.7 | Book of Work metrics framework | Contributor | -| CAO-XIIE.8 | BoW segmentation process | Testing oversight | -| CAO-XIIE.10.3 | Execute-phase requirements | **Primary author, testing lead** | -| CAO-XIIE.11.3 | Close-phase requirements | **Primary author, testing lead** | -| CAO-XIIE.13.1/13.2 | Quality Assurance working group | Design leadership (~50% artifacts) | - ---- - -## Key Outcomes - -**Regulatory:** -- 4+ critical regulatory commitments closed on time -- Regulators approved operating model without major revisions -- Sustainable controls validated through testing - -**Operational:** -- 15,000+ projects governed under standardized framework -- $7.1B portfolio visibility for executive leadership -- Reduced rework during regulatory reviews - -**Organizational:** -- BAU teams execute governance independently -- Cross-functional alignment on definitions and procedures -- Foundation for AI-powered automation of manual processes - ---- - -## Lessons Learned - -1. **Regulatory translation is a design problem:** Abstract requirements need to be forged into concrete, testable checkpoints - -2. **Sustainability testing proves sustainability:** Don't hand off until you've validated the BAU team can execute without you - -3. **Document your assumptions:** Explicit boundary conditions enable faster reviews and prevent scope creep - -4. **Influence without authority:** Cross-functional alignment requires facilitation skills, not organizational power - ---- - -## Interview Angles - -- **How do you navigate regulatory ambiguity?** First-principles interpretation, documented assumptions, iterative validation -- **How do you drive cross-functional alignment?** Design councils, working sessions, explicit decision documentation -- **How do you define "done" for governance work?** BAU can execute without you, and evidence is auditable - ---- - -## Keywords - -Consent Order • Regulatory remediation • Article XII • Governance design • Sustainability testing • Evidence-based closure • Cross-functional alignment • Enterprise transformation - ---- - -**Prepared:** March 1, 2026 -**Associated Role:** [Citi SVP Transformation](../roles/citi-svp-transformation.md) -**Related Projects:** [MRA Reporting Transformation](citi-mra-transformation.md), [Strategic Investment Data Architecture](citi-data-architecture.md) diff --git a/content/career/projects/citi-data-architecture.md b/content/career/projects/citi-data-architecture.md deleted file mode 100644 index d41fd68..0000000 --- a/content/career/projects/citi-data-architecture.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: "Strategic Investment Data Architecture" -company: "Citi" -project_type: "Data Architecture & Governance" -start_date: 2022-06-01 -end_date: 2023-09-30 -scale: "Enterprise-wide" -budget: "$1.1B visibility across 150+ strategic investments" -tags: [data-architecture, financial-governance, strategic-reporting, portfolio-management, data-reconciliation] -skills: [data-modeling, systems-integration, stakeholder-management, governance-design, financial-analysis] -competencies: [problem-solving, strategic-thinking, execution, communication] -impact_types: [efficiency, regulatory-compliance, technical-excellence] ---- - -## Executive Summary - -Re-engineered Citi's strategic investment data architecture to provide leadership with real-time visibility into ~$1.1B of spend across 150+ strategic investments. Built end-to-end data lineage, reconciliation frameworks, and governance processes that unified fragmented reporting across three core systems (RET, iCAPS, PTS). - -**Scope:** Data architecture design → System reconciliation → Governance framework → Executive reporting - ---- - -## Strategic Context - -**Business Challenge:** Citi's strategic investment portfolio lacked a unified view. Leadership couldn't answer basic questions: *How much are we spending? Where? On what outcomes?* Data was fragmented across multiple systems with inconsistent definitions, different refresh cycles, and no clear ownership. - -**Systems Landscape:** -- **RET (Gold Source):** Investment tracking system of record -- **iCAPS:** Project and program management data -- **PTS:** Resource and timeline tracking - -**Regulatory Pressure:** Article XII.1.e requirements demanded auditable governance over strategic investments, with clear evidence of oversight and financial controls. - -**Transformation Objective:** Create a **single source of truth** for strategic investment data that could: -- Support executive decision-making with timely, accurate information -- Satisfy regulatory requirements for auditability and evidence -- Enable portfolio segmentation and prioritization -- Reduce manual reconciliation effort - ---- - -## My Core Contributions - -### 1. Data Architecture Design - -**Problem:** No documented data lineage. Teams didn't know which system was authoritative for which fields. - -**What I Did:** -- Mapped **field-level sourcing logic** across all three systems: which fields came from where, when they refreshed, who owned them -- Documented **data quality rules** and validation criteria for each field -- Created **single management view** specification with explicit definitions to prevent misinterpretation -- Established **refresh frequency and success criteria** for automated data pulls - -**Outcome:** -- **Field Inventory Document:** Comprehensive mapping of 50+ data fields with sourcing logic, refresh cadence, and QC approach -- **Pre-populated vs. manual field classification:** Minimized free-text entry to reduce EUC risk -- Enabled downstream reporting with defensible, cited definitions - -### 2. Cross-System Reconciliation - -**Problem:** Week-over-week variance reporting was inconsistent. Numbers didn't match across systems, eroding leadership confidence. - -**What I Did:** -- Built **reconciliation workbooks** showing field-level alignment between RET, iCAPS, and PTS -- Created **illustrative one-time reconciliation** with week-over-week snapshots and variance explanations -- Documented **exception handling rules** for known discrepancies (timing differences, data entry lag) -- Established **tolerance thresholds** for acceptable variance - -**What Made It Hard:** -- **Different taxonomies:** Systems used different naming conventions for the same concepts -- **Timing differences:** Data refreshed at different cadences, creating apparent mismatches -- **Ownership ambiguity:** No clear accountability for cross-system consistency - -**Outcome:** -- **Reconciliation Framework:** Repeatable process for validating data consistency -- Leadership confidence in reported numbers increased significantly -- Variance explanations available on demand for any reporting period - -### 3. Governance Architecture - -**Problem:** Data quality was everyone's job, which meant it was no one's job. - -**What I Did:** -- Designed **QC decision matrices** defining Pass/Fail/N/A criteria for data quality checks -- Established **data stewardship model** with clear ownership by field and system -- Created **escalation constructs** for data quality issues -- Built **governance calendar** aligning data pulls with reporting cadence - -**Outcome:** -- **Data Governance Framework:** Documented roles, responsibilities, and checkpoints -- Sustainable BAU process owned by portfolio management team -- Quality issues caught and resolved before executive reporting - -### 4. Executive Reporting Enablement - -**Problem:** Leadership wanted a dashboard, but the underlying data wasn't trustworthy or well-defined. - -**What I Did:** -- Created **Board-grade dashboard framework** with defensible, sourced definitions -- Built **portfolio segmentation logic** enabling drill-down by category, business unit, and lifecycle phase -- Documented **metric calculations** with explicit formulas and data sources -- Designed **variance tracking** showing week-over-week changes with root cause explanations - -**Outcome:** -- **Strategic Investment Dashboard:** Single view of $1.1B portfolio with real-time data -- **Segmentation Capabilities:** Filter by priority tier, investment type, delivery risk -- Executive confidence in data enabled faster decision-making - ---- - -## Key Outcomes - -**Technical:** -- Unified data architecture across 3 core systems -- 50+ field mappings with documented lineage -- Automated reconciliation reducing manual effort by ~60% - -**Business:** -- $1.1B strategic investment visibility for executive leadership -- Portfolio segmentation enabling prioritization decisions -- Reduced reporting cycle time from days to hours - -**Governance:** -- Sustainable data stewardship model -- Evidence-based quality controls satisfying regulatory requirements -- Foundation for future automation and AI-powered analytics - ---- - -## Lessons Learned - -1. **Start with field-level clarity:** Abstract "data architecture" becomes concrete when you document every field's source, owner, and quality criteria - -2. **Build trust through reconciliation:** Leadership won't use data they don't trust. Showing your work (reconciliation evidence) builds confidence - -3. **Design for BAU first:** If the architecture requires your ongoing involvement to maintain, it's not done. Sustainability is the goal - -4. **Cross-system integration is a people problem:** Technical reconciliation is straightforward; getting teams to agree on ownership and definitions is the real challenge - ---- - -## Interview Angles - -- **How do you approach data quality challenges?** Start with field-level sourcing, build reconciliation frameworks, establish clear ownership -- **How do you build trust in data?** Transparency about methodology, documented definitions, evidence of validation -- **How do you design for sustainability?** BAU teams must be able to execute without you; document everything, train owners - ---- - -## Keywords - -Data architecture • Field-level sourcing • Cross-system reconciliation • Portfolio visibility • Executive dashboards • Data governance • Financial tracking • Strategic investments - ---- - -**Prepared:** March 1, 2026 -**Associated Role:** [Citi SVP Transformation](../roles/citi-svp-transformation.md) -**Related Projects:** [MRA Reporting Transformation](citi-mra-transformation.md) diff --git a/content/career/projects/citi-mra-transformation.md b/content/career/projects/citi-mra-transformation.md deleted file mode 100644 index 16f4337..0000000 --- a/content/career/projects/citi-mra-transformation.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: "MRA Reporting Transformation & Governance" -company: "Citi" -project_type: "Enterprise Regulatory Transformation" -start_date: 2021-09-01 -end_date: 2023-12-31 -scale: "Enterprise-wide" -budget: "7.1B investment portfolio oversight" -tags: [regulatory-remediation, operating-model-design, governance-framework, article-xii, mra-reporting, change-management] -skills: [regulatory-translation, systems-thinking, stakeholder-management, governance-design, data-governance, change-orchestration] -competencies: [problem-solving, communication, strategic-thinking, execution] -impact_types: [regulatory-compliance, efficiency, team-growth] ---- - -## Executive Summary - -Designed and implemented Citi's **MRA Reporting Operating Model** — a unified, scalable governance framework translating fragmented regulatory requirements into standardized reporting across 15,000+ projects. Consolidated vague Article XII.1.e language into documented, executable operating procedures with Board-grade dashboards, auditable evidence packages, and sustainable controls. - -**Scope:** Requirements definition → Operating model design → Evidence-based governance → Executive communication - ---- - -## Strategic Context - -**Regulatory Challenge:** Citi's Consent Order mandated specific MRA (Mapped Remedial Actions) reporting requirements, but Article XII.1.e used abstract language ("effective reporting," "assurance-readiness") without operational definitions. Regulators required **clearer outcome assurance (CSC/KPIs)** rather than just process adherence. - -**Enterprise Challenge:** 15,000+ projects across fragmented systems (RET, iCAPS, PTS), inconsistent definitions, and competing initiatives (RBCM 10/12, segmentation cadence) created confusion about: -- Which requirements applied where -- How to measure compliance -- Who owned what governance - -**Transformation Objective:** Create a **source-to-board operating model** that: -- Translated regulatory intent into concrete, testable requirements -- Standardized data lineage and QC across all systems -- Built auditable governance with clear ownership -- Produced executive-grade reporting on demand - ---- - -## My Core Contributions - -### 1. Regulatory Translation & Requirements Architecture - -**Problem:** Article XII language was vague; teams interpreted it differently across business lines. - -**What I Did:** -- Conducted **first-principles interpretation** of regulatory intent (from Consent Order documents, regulatory guidance, and auditor expectations) -- Mapped abstract requirements to **concrete checkpoints & evidence paths** aligned with BoW (Book of Work) lifecycle phases -- Created **field inventory, sourcing logic, and QC decision matrices** for Oversight Function adoption -- Documented **assumptions and boundaries** to prevent scope creep and misattribution - -**Outcome:** -- **v1.8 - v1.12 Unmapped MRA Requirements document:** Progressive clarification from draft to final, with embedded version lineage showing requirement evolution -- **Unified definition framework** reducing re-work during senior reviews -- Cross-functional alignment on **minimum reporting attributes and checks** at individual and portfolio levels - -**Evidence Highlights:** -- "Reporting section" ownership tracked across UMRAAOF governance -- Targeted communications (6.2 plan) driving adoption with explicit **compliance date (June 15, 2023)** -- Data pull/QC governance ensuring forum packages met standardized cadence - -### 2. Operating Model Design & Governance Architecture - -**Problem:** How do you move from "here's the requirement" to "here's a sustainable, repeatable process that the BAU team can execute?" - -**What I Did:** -- **Owned the MRA Remediation Reporting Design Council workstream** defining the operating model (reports A/B/C), data lineage, and QC approach -- Drafted **field inventory and sourcing logic** (pre-populated, SoR-sourced fields; minimal free text) to reduce EUC risk -- Designed **refresh frequency and success criteria**, embedding quality-check decision matrices for Oversight adoption -- Built **weekly oversight tracker and committee presentation template** with program-metric baselines to inform targets and cadence - -**What Made It Hard:** -- **Ambiguity under deadline:** Compressed quarter-end timeframes demanded "fast but rigorous" scope calls (e.g., excluding ARC from past-due counts) with footnoted rationales so reviewers could challenge without derailing timelines -- **Cross-silo normalization:** Different businesses/functions used different taxonomies, naming conventions, and phase logic; required **single management view** with embedded definitions to avoid misinterpretation -- **Pilot-to-production tension:** Early "Status Report" pilot was too manual; feedback loops drove the shift to **system-driven, weekly Oversight Tracker** architecture with explicit governance - -**Outcome:** -- **BAU Transition Draft (v1):** Task matrix, POCs, QC steps, calendars, inputs/outputs, process flow -- **Dashboard framework:** Governance-ready tool flow separating data prep vs. content production -- **Quality gates documented** with defined roles, responsibilities, and escalation paths - -**Evidence Highlights:** -- Presentation to Oversight, ORM, IA (Council packs: 10/01, 10/26, 11/23 with design evolution) -- Performance reviews (2022) noting Status Summary and Oversight Tracker ownership/transition -- Design Council decks corroborating role and scope (design lead; oversight of materials; team ownership under direction) - -### 3. Sustainability Testing & Evidence-Based Closure - -**Problem:** How do you prove that a new operating model actually works before handing it to BAU? - -**What I Did:** -- **Led cross-functional testing workstreams** (RBCM 13.1/13.2, CAO-XIIE.10/11.3) to validate: - - **Testing strategy:** Sampling approach, applicability rules, N/A dispositions - - **Design leadership:** Scaled QCR (Quality Control Review) model across Citi's BoW; authored ~50% of working-group checklists and process flows - - **Evidence QA:** Executed detailed evidence checks across RET, iCAPS, PTS; validated Pass/Fail/N.A. outcomes against regulatory expectations - - **Governance hand-off:** Documented findings, escalation constructs, and sustainability plan for IAI/ORM/MRAOF forums - -**What Made It Hard:** -- **Scope creep under ambiguity:** Regulatory requirements (close-phase applicability) were still evolving; had to **balance coverage with reviewer capacity** using documented sampling rationale and N/A principles (e.g., requirements not yet effective during testing period) -- **Resourcing constraints:** Multiple close-phase requirements with tight timelines; **personally executed most of the testing** in addition to documentation and governance responsibilities -- **Credibility boundaries:** Required clear articulation of what was **design vs. implementation**, what was **tested vs. observed**, and what **assumptions** governed the evidence package (to avoid overstating impact or sustainability) - -**Outcome:** -- **Sustainability testing packages** for RBCM 10.3 and 11.3 with evidence traceability, test methodology, and control-framework interpretation -- **Closure wrapper** with executive-ready storyline, evidence index, and recommended BA ownership/escalation -- **Lessons-learned documentation** feeding into requirement updates and system enhancements - -**Evidence Highlights:** -- Sustainability & Testing Results Summary (PPTX); testing lead and primary author designation -- Work-sample decks (2023-09-12, 2023-10-24) showing design leadership on checklists, flows, and segment-specific logic -- Performance reviews corroborating **analytical rigor, ownership, and resilience under pressure** - -### 4. Executive Communication & Governance Leadership - -**Problem:** How do you translate a complex, multi-system operating model into language that a Board or executive forum can understand and act on? - -**What I Did:** -- **Authored executive narratives** with clear definitions (e.g., "past due = original date; long-dated = 20+ years; ARC excluded from counts") and **cited sourcing logic** to preempt challenges -- **Built reconciliation workbooks** (FRB Correspondence alignment) showing week-over-week snapshots, status splits, QC depth, and illustrative examples -- **Designed Council facilitating & decision-documentation** approach: Set agendas, captured decisions/open questions, and socialized Status Summary construct for Oversight Committee use -- **Structured escalation pathways** under ambiguity with **decision matrices and success criteria** to drive consensus without derailing momentum - -**Outcome:** -- **Board-grade executive dashboard** with defensible, sourced definitions and traceable QC -- **Weekly Oversight Tracker** and Committee template adopted for 2022 transitions and program-metric reporting -- **Council decks** (packs #1-3: 2021-10 through 2021-11) with design evolution documented for post-hoc audit - ---- - -## Related Workstreams - -This unified MRA Reporting effort spanned multiple Article XII RBCMs: - -| RBCM | Scope | Your Role | -|------|-------|-----------| -| CAO-XIIE.4 | Work effort governance structure | Workstream contributor | -| CAO-XIIE.6 | PM metrics & Board reporting | Design authority | -| CAO-XIIE.7 | Book of Work metrics framework | Contributor | -| CAO-XIIE.10.3 | Execute-phase requirements (Sustainability Testing) | Primary author, testing lead | -| CAO-XIIE.11.3 | Close-phase requirements (Sustainability Testing) | Primary author, testing lead | -| CAO-XIIE.13.1/13.2 | Quality Assurance / Other Work Efforts QA | Design oversight; ~50% artifact ownership | - ---- - -## Key Behaviors Demonstrated - -- **Complex-to-Simple Translation:** Took fragmented regulatory language and forged a single, auditable operating model -- **First-Principles Problem Framing:** Oriented solutions toward **intervention** (what should the system do?) rather than just monitoring -- **Systems Design & De-duplication:** Balanced QA coverage with reviewer capacity; prevented overlap with existing IQA, TPO, HC/SC/PQA checks -- **Structured Facilitation Under Ambiguity:** Pilot → critique → redesign loops; decision-option matrices; escalation constructs to drive consensus -- **Executionald Craftsmanship:** Governance-ready checklists, flows, wireframes, and sample communications enabling smooth hand-off -- **Stakeholder Influence Without Formal Authority:** Facilitated consensus across Oversight, ORM, IA, multiple business units without named authority over any of them - ---- - -## Interview Angles - -- **Designing operating models at scale:** How you translated vague Article XII requirements into a repeatable, auditable BAU process across 15,000+ projects -- **Navigating regulatory ambiguity:** How you structured decision-making and evidence gathering when requirements were still evolving -- **Building governance under time pressure:** How you moved from design to working-group adoption to sustainability testing without derailing timelines -- **Complex communication with executives:** How you packaged multi-system complexity into Board-ready narratives with defensible sourcing logic - ---- - -## Timeline - -``` -Sep 2021 (Contractor Start) - │ - ├─ Initial Consent Order scoping & RBCM architecture - │ -Mar 2022 (Full-time SVP Conversion) - │ - ├─ Q3 2022 – Council formation; requirements clarification - ├─ Q4 2022 – Operating model design finalized; BAU transition plan - │ - ├─ Q1-Q2 2023 – Design Council working-group facilitation (Oversight, ORM, IA) - │ - ├─ Q2-Q3 2023 – Sustainability testing execution across lifecycle phases - │ - ├─ Q4 2023 – Closure packages finalized; governance alignment; BAU ownership transition - │ -Dec 2023 - └─ MRA operating model fully BAU-owned; monitoring via Oversight Tracker -``` - ---- - -**Prepared:** January 28, 2026 -**Last Updated:** February 28, 2026 -**Associated Role:** [Citi SVP Transformation](../roles/citi-svp-transformation.md) diff --git a/content/career/projects/ms-concierge-model.md b/content/career/projects/ms-concierge-model.md deleted file mode 100644 index 50fcbb1..0000000 --- a/content/career/projects/ms-concierge-model.md +++ /dev/null @@ -1,185 +0,0 @@ ---- -title: "Concierge Service Model for Ultra-High-Net-Worth Clients" -company: "Morgan Stanley" -project_type: "Business Strategy & Operating Model Design" -start_date: 2019-09-01 -end_date: 2020-08-31 -scale: "Business Unit" -budget: "~$15B AUM opportunity" -tags: [wealth-management, operating-model-design, client-experience, ultra-high-net-worth, family-office, service-design] -skills: [service-design, client-research, stakeholder-interviews, operating-model-design, business-case-development, partnership-development] -competencies: [strategic-thinking, innovation, execution, communication] -impact_types: [revenue, customer-satisfaction, efficiency] ---- - -## Executive Summary - -Designed and launched a "white-glove" concierge service model targeting Morgan Stanley's ultra-high-net-worth and family office clients—a segment with complex needs that standard wealth management offerings couldn't address. The model contributed to ~$15B in new assets under management by solving onboarding, analytics, and relationship management challenges. - -**Scope:** Client research → Service design → Pilot launch → Partnership development - ---- - -## Strategic Context - -**Market Opportunity:** Morgan Stanley's ultra-high-net-worth segment (clients with $25M+ in assets) represented significant growth potential, but the firm was losing opportunities to competitors with more tailored service offerings. - -**Client Pain Points:** -- **Complex onboarding:** Multi-entity structures (trusts, LLCs, foundations) created friction in account setup -- **Analytics gaps:** Standard reporting didn't meet family office sophistication (consolidated views, alternative asset tracking) -- **Relationship fragmentation:** Clients worked with multiple advisors without coordinated service - -**Competitive Pressure:** Private banks and independent multi-family offices were winning business with more customized solutions. - -**Strategic Mandate:** Build a differentiated service tier that could compete for the firm's most valuable clients while demonstrating scalability for broader rollout. - ---- - -## My Core Contributions - -### 1. Client Research & Advisor Interviews - -**Challenge:** Leadership had hypotheses about client needs but lacked systematic validation from the field. - -**What I Did:** -- Designed **structured interview protocols** focused on client pain points and unmet needs -- Conducted **field interviews with the firm's top Financial Advisors** (top 10% by AUM) -- Synthesized findings into **prioritized capability gaps** with evidence from multiple sources -- Created **client journey maps** documenting friction points across the relationship lifecycle - -**Insights Discovered:** -- Onboarding was the #1 pain point—complex structures took months, creating negative first impressions -- Analytics needs varied by client sophistication—some wanted simplicity, others demanded institutional-grade reporting -- Relationship continuity mattered more than any single feature—clients wanted a "quarterback" who understood their full picture - -**Outcome:** -- Research findings directly shaped service model design -- Prioritized resources toward highest-impact capabilities -- Built advisor buy-in through collaborative discovery - -### 2. Service Model Design - -**Challenge:** Translate client insights into an operating model that could be delivered consistently. - -**What I Did:** -- Designed **concierge service architecture** with three core pillars: - - **Onboarding:** Dedicated specialist team for complex multi-entity structures - - **Analytics:** Custom reporting and portfolio analytics tailored to family office needs - - **Relationship Management:** Single point of contact coordinating across product specialists -- Created **service level definitions** with clear standards for response times and deliverables -- Developed **staffing model** balancing specialization with cost efficiency -- Built **technology requirements** specification for platform enhancements - -**Design Principles:** -- **High-touch where it matters:** Human specialists for complex decisions, automation for routine tasks -- **Scalable customization:** Modular capabilities that could be configured per client -- **Advisor enablement:** Support the FA relationship rather than replace it - -**Outcome:** -- Documented operating model ready for pilot -- Clear resource requirements and investment case -- Advisory council approval for pilot launch - -### 3. Pilot Execution - -**Challenge:** Prove the model worked with real clients before broader rollout. - -**What I Did:** -- Managed **pilot launch** with select Financial Advisors and clients -- Established **success metrics** (onboarding time, client satisfaction, AUM growth) -- Coordinated **cross-functional execution** across Operations, Technology, and Product -- Built **feedback loops** capturing lessons learned for model refinement - -**What Made It Hard:** -- Balancing pilot scope with resource constraints -- Managing expectations across multiple stakeholder groups -- Iterating quickly based on early feedback - -**Outcome:** -- Pilot demonstrated measurable improvement in onboarding time and client satisfaction -- ~$15B in new AUM attributed to concierge-served relationships -- Model validated for broader rollout planning - -### 4. Strategic Partnership Development - -**Challenge:** Some capabilities required external partners rather than internal build. - -**What I Did:** -- Led **custodian bank partnership evaluation** to address capability gaps: - - Defined partnership requirements and success criteria - - Designed and managed RFP process with multiple custodian banks - - Coordinated due diligence with Legal, Compliance, and Operations - - Presented recommendations to senior leadership -- Served as **relationship manager for fintech partner**: - - Provided product development guidance - - Advised on regulatory considerations - - Facilitated internal stakeholder connections - -**Outcome:** -- Structured partnership evaluation enabling informed leadership decision -- Fintech partner successfully navigated wealth management landscape -- Partnership capabilities integrated into service model roadmap - ---- - -## Key Outcomes - -**Business Impact:** -- ~$15B in new assets under management attributed to concierge relationships -- Differentiated service tier for firm's most valuable client segment -- Competitive positioning against private banks and multi-family offices - -**Operational Impact:** -- Reduced onboarding time for complex structures by 40%+ -- Standardized service delivery with clear SLAs -- Scalable model ready for broader rollout - -**Strategic Impact:** -- Validated demand for high-touch service in UHNW segment -- Informed technology investment priorities -- Created blueprint for future segment-specific service models - ---- - -## Lessons Learned - -1. **Start with the client:** Field research revealed needs that internal assumptions missed. Invest in primary research before designing solutions - -2. **Design for the advisor, not just the client:** Financial Advisors are the delivery channel—build tools that make them more effective, not replace them - -3. **Pilot early, iterate fast:** Real client feedback is worth more than months of internal design. Launch small, learn quickly - -4. **Partnerships extend capabilities:** Not everything needs to be built internally. Strategic partnerships can accelerate time-to-market - ---- - -## Context: Career Transition - -This project represented a pivot from consulting back into corporate strategy—applying operating model design and client research skills from Strategy& to a specific business challenge within a major financial institution. - -The experience of **building something new** (the concierge model) rather than advising on transformation shaped my appetite for execution-focused roles. Key capabilities developed: -- **Primary research** with clients and field teams -- **Operating model design** for complex service delivery -- **Partnership evaluation** and vendor selection -- **Cross-functional coordination** in a large enterprise - -These skills carried directly into the transformation work at Citi. - ---- - -## Interview Angles - -- **How do you approach new market opportunities?** Start with client research, validate hypotheses through primary data, design solutions that address real pain points -- **How do you balance customization with scalability?** Modular capabilities, configurable service levels, clear design principles -- **How do you build something new in a large organization?** Pilot-based validation, cross-functional coordination, stakeholder alignment through evidence - ---- - -## Keywords - -Concierge service • Ultra-high-net-worth • Family office • Operating model design • Client research • Service design • Partnership development • Pilot launch • Wealth management - ---- - -**Prepared:** March 1, 2026 -**Associated Role:** [Morgan Stanley AVP](../roles/morgan-stanley-avp.md) diff --git a/content/career/roles/_index.md b/content/career/roles/_index.md deleted file mode 100644 index de11e83..0000000 --- a/content/career/roles/_index.md +++ /dev/null @@ -1,79 +0,0 @@ -# Roles - -Employment history in reverse chronological order. - -## Timeline - -| Period | Title | Company | File | -|--------|-------|---------|------| -| 2021-Present | SVP, Transformation Senior Lead | Citi | [citi-svp-transformation.md](citi-svp-transformation.md) | -| 2019-2020 | AVP, Corporate & Institutional Solutions | Morgan Stanley | [morgan-stanley-avp.md](morgan-stanley-avp.md) | -| 2018-2019 | Senior Consultant, Wealth & Asset Management | Treliant LLC | [treliant-senior-consultant.md](treliant-senior-consultant.md) | -| 2015-2017 | Senior Associate, Financial Services Strategy | Strategy& (PwC) | [strategy-and-senior-associate.md](strategy-and-senior-associate.md) | -| 2014 | MBA Intern, Capital Markets Advisory | PwC / Strategy& | [pwc-mba-intern.md](pwc-mba-intern.md) | -| 2010-2013 | Client Services Analyst, Commodities | BNP Paribas | [bnp-paribas-client-services.md](bnp-paribas-client-services.md) | -| 2008-2010 | Rotational Analyst, Trading Operations | BNP Paribas | [bnp-paribas-rotational.md](bnp-paribas-rotational.md) | - -### Pre-MBA / Undergraduate Roles - -| Period | Title | Company | File | -|--------|-------|---------|------| -| 2007-2008 | Account Executive, Advertising Sales | Targum Publishing | [targum-account-executive.md](targum-account-executive.md) | -| 2007 | Control Intern, Corporate Finance | Viacom | [viacom-control-intern.md](viacom-control-intern.md) | -| 2006 | Sales Intern | Bear Stearns | [bear-stearns-sales-intern.md](bear-stearns-sales-intern.md) | - -## By Industry - -### Financial Services - Banking -- [Citi](citi-svp-transformation.md) - Enterprise Transformation -- [Morgan Stanley](morgan-stanley-avp.md) - Wealth Management Strategy -- [BNP Paribas](bnp-paribas-client-services.md) - Trading Operations -- [Bear Stearns](bear-stearns-sales-intern.md) - Sales (Pre-crisis) - -### Professional Services - Consulting -- [Strategy& / PwC](strategy-and-senior-associate.md) - Strategy Consulting -- [Treliant](treliant-senior-consultant.md) - Regulatory Advisory - -### Media & Entertainment -- [Viacom](viacom-control-intern.md) - Corporate Finance -- [Targum Publishing](targum-account-executive.md) - Advertising Sales - -## By Function - -### Strategy & Transformation -- [Citi](citi-svp-transformation.md) - Enterprise transformation, regulatory remediation -- [Morgan Stanley](morgan-stanley-avp.md) - Business unit strategy -- [Strategy&](strategy-and-senior-associate.md) - Financial services strategy consulting - -### Operations & Client Services -- [BNP Paribas - Client Services](bnp-paribas-client-services.md) - Commodities/Prime Brokerage -- [BNP Paribas - Rotational](bnp-paribas-rotational.md) - Trading operations - -### Advisory & Consulting -- [Treliant](treliant-senior-consultant.md) - Wealth management advisory -- [PwC Intern](pwc-mba-intern.md) - Capital markets regulatory - -### Sales & Business Development -- [Targum](targum-account-executive.md) - Advertising sales -- [Bear Stearns](bear-stearns-sales-intern.md) - Client acquisition - -## Career Progression - -``` -2006 ─── Bear Stearns (Intern) ─── Sales -2007 ─── Viacom (Intern) ─── Corporate Finance -2007-08 ─ Targum ─── Advertising Sales - │ - └── RUTGERS BS FINANCE (2008) ──┐ - │ -2008-10 ─ BNP Paribas ─── Rotational Analyst -2010-13 ─ BNP Paribas ─── Client Services Analyst - │ - └── CMU TEPPER MBA (2015) ──────┐ - │ -2014 ─── PwC/Strategy& (Intern) ── Capital Markets -2015-17 ─ Strategy& ─── Senior Associate -2018-19 ─ Treliant ─── Senior Consultant -2019-20 ─ Morgan Stanley ─── AVP -2021- ─ Citi ─── SVP Transformation -``` diff --git a/content/career/roles/bear-stearns-sales-intern.md b/content/career/roles/bear-stearns-sales-intern.md deleted file mode 100644 index c10bdd8..0000000 --- a/content/career/roles/bear-stearns-sales-intern.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Sales Intern" -company: "Bear, Stearns & Co. Inc." -start_date: 2006-06 -end_date: 2006-08 -location: "New York, NY" -employment_type: internship -tags: [investment-banking, sales, wealth-management, undergraduate] -skills: [lead-generation, client-acquisition, sales] -pre_mba: true ---- - -## Summary - -Summer internship in private wealth management at Bear Stearns (pre-financial crisis), supporting client acquisition and lead generation efforts. - -## Key Responsibilities - -- Generate qualified leads for sales team -- Support new account opening process -- Cold calling prospects - -## Notable Achievements - -- Generated 50+ qualified leads -- Resulted in 6 new accounts and $2.5M in total assets diff --git a/content/career/roles/bnp-paribas-client-services.md b/content/career/roles/bnp-paribas-client-services.md deleted file mode 100644 index 9af10ef..0000000 --- a/content/career/roles/bnp-paribas-client-services.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: "Client Services Analyst, Commodities/Prime Brokerage" -company: "BNP Paribas" -division: "Corporate and Investment Banking" -start_date: 2010-02 -end_date: 2013-05-10 -location: "New York, NY" -employment_type: full-time -logo: "/logos/bnp-paribas.png" -tags: [investment-banking, commodities, prime-brokerage, client-services, operations] -skills: [client-relationship-management, process-optimization, six-sigma, vba-automation, regulatory-compliance] -certifications: ["FINRA Series 7 (October 2008)"] ---- - -## Summary - -Promoted from rotational analyst to a permanent team member supporting commodities and prime brokerage operations. Led process improvement initiatives and production of client-facing deliverables. - -## Key Responsibilities - -- Manage client relationships for commodities and prime brokerage clients -- Deliver presentations to existing and prospective clients -- Coordinate reporting tools development with Paris and London teams - -## Notable Achievements - -### Process Optimization -- Developed process controls and VBA macros for trade reconciliation -- Standardized reporting procedures to meet regulatory standards - -### Client Development -- Delivered 20+ presentations to existing and prospective clients -- Directly resulted in opening of 8 new accounts -- Instituted 15+ new reporting tools by coordinating Business Analysts and IT teams globally - - diff --git a/content/career/roles/bnp-paribas-rotational.md b/content/career/roles/bnp-paribas-rotational.md deleted file mode 100644 index aebe964..0000000 --- a/content/career/roles/bnp-paribas-rotational.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "Rotational Analyst, Trading Operations" -company: "BNP Paribas" -division: "Corporate and Investment Banking" -start_date: 2008-07-07 -end_date: 2010-02 -location: "New York, NY" -employment_type: full-time -logo: "/logos/bnp-paribas.png" -tags: [investment-banking, trading-operations, derivatives, rotational-program] -skills: [derivatives-operations, collateral-management, documentation, vba, cross-functional-collaboration] -rotations: - - "Rate and Credit Derivatives - Documentation Group" - - "Collateral Management" - - "Equity Derivatives - Referential Data Group" ---- - -## Summary - -Entry-level rotational analyst program across trading operations functions, gaining exposure to derivatives documentation, collateral management, and referential data operations. Secured full-time position through on campus recruiting - -## Key Responsibilities - -- Support derivatives documentation and trade confirmation during the peak of the Global Financial Crisis -- Manage collateral operations and reconciliation -- Build and maintain referential data for equity derivatives - -## Notable Achievements - -### Rotation Highlights -- **Rate and Credit Derivatives:** Reduced unconfirmed credit default swaps during 2008 financial crisis -- **Collateral Management:** Initiated London office project to update payment ticket formatting, reducing collateral verification time by 30 minutes daily -- **Equity Derivatives:** Wrote 6 spreadsheet macros analyzing risk exposure and P&L -- **Project Managment** Supported internal Six Sigma initiativie to improve processing for Fixed Income derivatives - - -### Process Optimization -- Appointed to Six Sigma improvement initiative for Fixed Income Documentation Team -- Improved trade processing by ~10% (3 days reduction) - - -### Risk Management -- Reduced unconfirmed credit default swaps with 60 hedge-fund/institutional counterparties -- Mitigated operational risk during 2008 global financial crisis -- Eliminated potential overnight risk exposure -- Proficient in all operational aspects including regulatory compliance, margin settlement, and managing $100M+ in assets - -### Career Progression -- Secured full-time position following completion of the selective rotational program -- Selected for permanent role in Client Services based on performance diff --git a/content/career/roles/citi-svp-transformation.md b/content/career/roles/citi-svp-transformation.md deleted file mode 100644 index f34cef8..0000000 --- a/content/career/roles/citi-svp-transformation.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: "Senior Vice President, Transformation Senior Lead" -company: "Citi" -start_date: 2021-09-07 -end_date: present -location: "New York, NY" -employment_type: full-time -level: "SVP" -team_size: 2 -logo: "/logos/citi.png" -tags: [enterprise-transformation, regulatory-compliance, program-management, consent-order] -skills: [stakeholder-management, governance-design, regulatory-reporting, process-optimization, people-management] ---- - -## Summary - -Lead cross-organizational efforts on strategic regulatory remediation and enterprise risk/control framework transformation initiatives. Transitioned from contractor to full-time SVP, driving governance design and regulatory compliance programs across the enterprise. - -## Key Responsibilities - -- Lead enterprise-wide transformation initiatives for regulatory compliance and remediation -- Design and implement governance frameworks for regulatory commitments -- Develop strategic dashboards for executive leadership and Board of Directors -- Establish global standards for program/project management across 15,000+ projects -- Oversee financial governance for ~$7.1B technology and business investment portfolio -- Manage distributed team of direct reports - -## Notable Achievements - -### Enterprise Regulatory Reporting Transformation -- **Designed & implemented enterprise regulatory reporting operating model** translating complex regulatory requirements into a documented, scalable governance framework across 15,000+ projects -- **Authored regulatory requirements documentation** with progressive clarification of regulatory intent, embedded version lineage, field inventory, and quality control decision matrices -- **Built cross-functional governance forum** establishing alignment across multiple business units and control functions to translate regulatory language into operational procedures through structured facilitation -- **Led sustainability testing** across program lifecycle phases, validating testing strategy, designing scalable quality control model, and executing evidence review across enterprise systems -- **Created Board-grade executive materials** including dashboard framework with defensible definitions, oversight tracking, presentation templates, and stakeholder communication plans -- **Outcome:** Established sustainable business-as-usual operating model; regulators approved approach without major revisions - -### Enterprise Governance & Board Reporting -- **Developed and delivered strategic dashboards** reconciling fragmented cross-silo regulatory data into Board- and Audit-grade reporting with clear definitions -- **Established global program management standards** across 15,000+ project portfolio with structured lifecycle phase requirements -- **Overhauled financial governance framework** for ~$7.1B technology and business investment portfolio through standardized cost estimation, tracking, variance analysis, and portfolio segmentation -- **Led reporting initiatives** translating executive dashboard requirements from initial build to sustainable operations - -### Regulatory Remediation & Controls -- **Secured on-time closure of 4+ critical regulatory commitments** through validated controls and documented evidence packages -- **Designed & launched senior oversight function** improving quality and timeliness of regulatory remediation delivery with structured escalation and stakeholder governance -- **Executed testing and evidence quality assurance** including testing strategy definition, sampling methodology validation, cross-system evidence verification, and risk/control findings packaging -- **Established evidence-based risk frameworks** documenting assumptions, boundary conditions, and control-framework interpretation for governance review and audit acceptance - -### Data Architecture & Technology -- **Re-engineered data architecture** for 150+ strategic investments with visibility into ~$1.1B spend, documenting field requirements, refresh frequency, and quality control approach -- **Built reconciliation frameworks** aligning data across enterprise systems with field-level logic and variance tracking -- **Leveraged AI-powered tools** to automate manual reporting processes, reducing effort and improving data timeliness -- **Created efficiency tools & templates** including training workshops, dashboard templates, and governance checklists improving team productivity -- **Developed AI-powered training curriculum** for enterprise tool adoption with automated content refresh, ensuring training materials stay current without manual intervention - -### Automation & AI Exploration -- **Championed automation-first mindset** across manual reporting processes, identifying opportunities for AI integration -- **Piloted AI-assisted workflows** for document processing and evidence synthesis -- **Built template systems** reducing manual entry and improving data quality through pre-populated fields -- **Explored enterprise AI adoption patterns** for scaling efficiency gains to broader transformation work -- **Documented [9 AI collaboration case studies](../ai-collaborations/_index.md)** saving 33.9 hours across governance, automation, product development, and research workflows (avg. 0.92 confidence level) -- **Established reusable AI partnership frameworks** including iterative refinement cycles, multi-persona workflows, master prompt patterns, and human-in-the-loop development — applied across regulatory documentation, data pipeline refactoring, and training content generation - -## Performance History - -### 2023 -- **Rating:** Valued Contributor (Manager) / Exceeds Expectations (Self) -- **Strengths:** Complex-to-simple translation, rapid information synthesis, efficiency champion -- **Development:** Increase transparency on objectives, more frequent communication on priorities -- **First-time people manager** with distributed team diff --git a/content/career/roles/morgan-stanley-avp.md b/content/career/roles/morgan-stanley-avp.md deleted file mode 100644 index daccbda..0000000 --- a/content/career/roles/morgan-stanley-avp.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: "Assistant Vice President, Corporate & Institutional Solutions" -company: "Morgan Stanley" -start_date: 2019-07-29 -end_date: 2020-10-15 -location: "New York, NY" -employment_type: full-time -level: "AVP" -logo: "/logos/morgan-stanley.png" -tags: [wealth-management, business-strategy, client-experience, partnerships] -skills: [strategic-planning, stakeholder-interviews, operating-model-design, partnership-development] ---- - -## Summary - -Led portfolio of strategic projects for wealth management and institutional solutions, focusing on new business development, client experience design, and strategic partnerships. - -## Key Responsibilities - -- Lead business unit strategy initiatives for wealth management clients -- Design operating models and service delivery frameworks -- Conduct field research with CFOs and Financial Advisors -- Evaluate strategic partnerships and third-party solutions - -## Notable Achievements - -### Business Development -- Led portfolio of projects for ~$15B new assets under management (AUM) -- Designed "white-glove" concierge service model for wealth management clients -- Pursued strategic partnership with leading global custodian bank - -### Strategic Advisory -- Aligned trading products expansion strategy -- Advised on "in-house" vs. third-party solution decisions -- Conducted field interviews with CFOs and Financial Advisors to inform strategy diff --git a/content/career/roles/pwc-mba-intern.md b/content/career/roles/pwc-mba-intern.md deleted file mode 100644 index 0a2f7c7..0000000 --- a/content/career/roles/pwc-mba-intern.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: "MBA Intern, Capital Markets Advisory" -company: "PwC / Strategy&" -start_date: 2014-06-02 -end_date: 2014-08-15 -location: "New York, NY" -employment_type: internship -tags: [consulting, capital-markets, regulatory, investment-banking] -skills: [business-requirements, regulatory-compliance, project-management, financial-analysis] ---- - -## Summary - -Summer MBA internship in capital markets advisory practice, supporting regulatory transformation projects for bulge-bracket investment banks. - -## Key Responsibilities - -- Manage work streams for regulatory transformation projects -- Develop business requirement documents (BRDs) -- Support Resolution Plan ("living will") development for systemically important institutions - -## Notable Achievements - -### Regulatory Projects -- Managed work stream for leading investment banking client's regulatory reporting platform transformation -- Developed business requirement documents (BRDs) guiding firm transformation -- Provided analysis and exhibits for large Japanese banking client's Resolution Plan -- Structured "living will" required of institutions posing systemic risk to global financial system diff --git a/content/career/roles/strategy-and-senior-associate.md b/content/career/roles/strategy-and-senior-associate.md deleted file mode 100644 index 4167f98..0000000 --- a/content/career/roles/strategy-and-senior-associate.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: "Senior Associate, Financial Services Strategy Consulting" -company: "Strategy& (formerly Booz & Co.)" -parent_company: "PwC Network" -start_date: 2015-09-14 -end_date: 2017-10-10 -location: "Chicago, IL / New York, NY" -employment_type: full-time -tags: [strategy-consulting, financial-services, m-and-a, operating-model, wealth-management] -skills: [strategy-development, m-and-a-analysis, customer-segmentation, change-management, cost-optimization] ---- - -## Summary - -Financial services strategy consultant advising banking, wealth management, and insurance clients on growth strategy, operating model transformation, and customer experience initiatives. - -## Key Responsibilities - -- Lead strategy engagements for banking and wealth management clients -- Develop M&A analysis and acquisition target identification -- Design customer segmentation and migration strategies -- Create target operating models with cost optimization - -## Notable Achievements - -### Growth Strategy -- Evaluated organic and M&A growth opportunities for leading online brokerage -- Sized ~$2T AUM opportunity from industry shift to online/independent models -- Identified acquisition targets leading to ~$4B acquisition of direct competitor -- Collaborated with CMO on marketing strategy and promotional incentives - -### Customer Segmentation (Wealth Management) -- Created segmentation/migration strategy for large retail bank -- Executed migration of 32,000 low-balance wealth management clients to robo-advisor and self-directed channels -- Increased advisor capacity & productivity by ~5% -- Reduced fiduciary risk by $465M - -### Target Operating Model (Insurance) -- Identified ~$14M in run-rate savings for insurance broker subsidiary -- Led global cost and organizational restructuring effort -- Modeled near-shore and off-shore centralization costs -- Developed comprehensive business case with risk considerations - -### Client Experience & Change Management -- Designed end-to-end client lifecycle experience for wealth management firm -- Created key stakeholder personas and customer journey use cases -- Developed learning & development curriculum for financial advisors -- Segmented financial advisor population for targeted coaching diff --git a/content/career/roles/targum-account-executive.md b/content/career/roles/targum-account-executive.md deleted file mode 100644 index abde936..0000000 --- a/content/career/roles/targum-account-executive.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: "Account Executive, Advertising Sales" -company: "Targum Publishing Company" -publication: "The Daily Targum" -start_date: 2007-07 -end_date: 2008-05 -location: "New Brunswick, NJ" -employment_type: part-time -tags: [sales, advertising, media, undergraduate] -skills: [sales, client-acquisition, account-management, deadline-management] -pre_mba: true ---- - -## Summary - -Advertising sales role for Rutgers University's student newspaper while completing undergraduate degree. Built client relationships and consistently met sales quotas. - -## Key Responsibilities - -- Generate advertising revenue for online and print publication -- Acquire new clients and maintain existing relationships -- Meet weekly sales quotas and deadlines - -## Notable Achievements - -- Generated over $25,000 in revenue for Rutgers newspaper (online and print) -- Met deadlines and sales quotas of $1,750/week -- Secured 9 new clients while maintaining 15+ existing relationships diff --git a/content/career/roles/treliant-senior-consultant.md b/content/career/roles/treliant-senior-consultant.md deleted file mode 100644 index 2c66555..0000000 --- a/content/career/roles/treliant-senior-consultant.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: "Senior Consultant, Wealth & Asset Management Advisory" -company: "Treliant LLC" -start_date: 2018-11-24 -end_date: 2019-04-23 -location: "New York, NY" -employment_type: full-time -tags: [consulting, wealth-management, business-development, regulatory, sales-practice-risk, reg-bi, robo-advisors] -skills: [thought-leadership, go-to-market-strategy, risk-management, team-leadership, published-author] ---- - -## Summary - -Developed advisory practice for PE-backed boutique consulting firm focused on wealth and asset management clients, combining published thought leadership with client engagement and practice-building across regulatory risk, sales practice compliance, and digital transformation in wealth management. - -## Key Responsibilities - -- Build and develop wealth & asset management advisory practice from the ground up -- Research and author thought leadership on emerging regulatory topics (Reg BI, robo-advisor compliance, sales practice risk) -- Design go-to-market campaigns targeting wealth management and broker-dealer prospects -- Manage risk and regulatory client engagements with contracted consultant teams -- Position firm as subject matter authority in wealth management compliance space - -## Notable Achievements - -### Published Thought Leadership -- Co-authored **2-part article series** published in [ThinkAdvisor](https://www.thinkadvisor.com/) (Feb 2019): - - [Part 1: "Sales Practice Risk in the Digital Era: Where We Are, Where We're Going"](https://www.thinkadvisor.com/2019/02/15/sales-practice-risk-in-the-digital-era-part-1-where-we-are-where-were-going/) — regulatory landscape analysis covering DOL fiduciary rule, SEC Reg BI, state-level fiduciary standards, and robo-advisor compliance requirements - - [Part 2: "Mitigating Sales Practice Risk"](https://www.thinkadvisor.com/2019/02/22/sales-practice-risk-in-the-digital-era-part-2-mitigating-the-risk/) — risk mitigation framework including centralized compliance systems, analytics for detecting unusual broker activity, and AI/ML-enhanced suitability questionnaires -- Co-authors: Gregory K. Soueid (Managing Director, Head of Wealth Management), Lynn W. Woosley (Engagement Director) - -### Practice Development -- Identified 10 go-to-market campaigns for prospecting across wealth management compliance verticals -- Managed risk and regulatory engagements with 40+ contracted workers - -### Domain Expertise Demonstrated -- Sales practice risk and suitability requirements across retail, HNW, and automated channels -- Fiduciary vs. best-interest standards (DOL rule, SEC Reg BI, Form CRS) -- Robo-advisor regulatory compliance (SEC registration, FINRA guidance, model validation) -- Elder financial abuse considerations in suitability frameworks diff --git a/content/career/roles/viacom-control-intern.md b/content/career/roles/viacom-control-intern.md deleted file mode 100644 index b4fb7ae..0000000 --- a/content/career/roles/viacom-control-intern.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Control Intern, Corporate Finance" -company: "Viacom, Inc." -start_date: 2007-06 -end_date: 2007-08 -location: "New York, NY" -employment_type: internship -tags: [corporate-finance, financial-analysis, process-improvement, undergraduate] -skills: [financial-analysis, process-documentation, presentation, data-analysis] -pre_mba: true ---- - -## Summary - -Summer internship in corporate finance supporting financial planning and analysis, including process improvement and executive presentations. - -## Key Responsibilities - -- Support corporate finance and financial planning functions -- Document and analyze business processes -- Prepare analysis for senior leadership - -## Notable Achievements - -- Improved legal invoice turnaround by 10% through flowchart analysis -- Documented and presented corporate aviation spending analysis to VP of Financial Planning diff --git a/content/career/skills/_index.md b/content/career/skills/_index.md deleted file mode 100644 index 3bc295d..0000000 --- a/content/career/skills/_index.md +++ /dev/null @@ -1,102 +0,0 @@ -# Skills - -Skills inventory with proficiency levels and evidence. - -## Technical Skills - -| Skill | Proficiency | Evidence | -|-------|-------------|----------| -| MS Office 365 (Excel, PowerPoint) | Expert | All roles; VBA macros at BNP | -| VBA/Macros | Advanced | [BNP Paribas](../roles/bnp-paribas-client-services.md) - 6 macros for trading desk | -| Data Modeling (PowerQuery, SQL) | Advanced | [Citi](../roles/citi-svp-transformation.md) - data architecture, field inventory & sourcing logic; [RBCM-12 EUC pipeline](../stories/rbcm12-budgeting-resourcing-metrics.md) | -| EUC Governance & Development | Advanced | [RBCM-12 pipeline](../stories/rbcm12-budgeting-resourcing-metrics.md); [Unmapped MRA EUC](../stories/unmapped-mra-reporting-euc.md) - audit-grade controls, release protocols | -| Process Documentation (BRDs) | Expert | [Citi](../roles/citi-svp-transformation.md) - BAU Transition, QC decision matrices; [PwC](../roles/pwc-mba-intern.md) | -| Six Sigma | Practitioner | [BNP Paribas](../roles/bnp-paribas-client-services.md) - improvement initiative | -| Regulatory Documentation & Compliance | Expert | [Citi](../roles/citi-svp-transformation.md) - MRA reporting requirements, Article XII evidence packages | -| Operating Model Design | Expert | [Citi MRA Transformation](../projects/citi-mra-transformation.md) - enterprise-scale design; design council facilitation | -| Governance Framework Design | Expert | [Citi](../roles/citi-svp-transformation.md) - financial governance, oversight frameworks, escalation constructs | -| AI Collaboration & Prompt Engineering | Advanced | [9 documented cases](../ai-collaborations/_index.md) - 33.9 hrs saved; master prompt patterns, iterative refinement cycles, multi-persona workflows | -| Human-AI Workflow Design | Advanced | [Citi](../roles/citi-svp-transformation.md) - AI-assisted document processing, training curriculum automation; [8 reusable framework patterns](../ai-collaborations/_index.md#framework-patterns) | - -## Soft Skills - -| Skill | Proficiency | Evidence | -|-------|-------------|----------| -| Complex-to-Simple Communication | Expert | 2023 review feedback; CEO dashboards at Citi; [MRA translation](../stories/regulatory-translation-mra.md) | -| Stakeholder Management & Facilitation | Expert | [Citi](../roles/citi-svp-transformation.md) - Board reporting, design council, governance; [Stakeholder alignment story](../stories/stakeholder-influence-governance.md) | -| Systems Thinking & First-Principles Design | Expert | [MRA operating model design](../projects/citi-mra-transformation.md); regulatory translation story | -| Execution Under Pressure | Expert | [Governance under pressure story](../stories/governance-under-pressure.md); [Citi RBCM testing & closure](../roles/citi-svp-transformation.md) | -| People Management | Developing | First-time manager in 2023 (2 direct reports at Citi) | -| Presentation/Storytelling | Expert | [BNP](../roles/bnp-paribas-client-services.md) - 20+ client presentations; [Citi Board-grade dashboards](../roles/citi-svp-transformation.md) | -| Cross-functional Collaboration | Expert | Global teams at BNP (Paris, London), Citi (Tampa, multiple business units) | -| Change Orchestration | Advanced | [MRA Design Council](../projects/citi-mra-transformation.md) facilitation; communications planning; governance hand-off | -| Influence Without Formal Authority | Expert | [Stakeholder influence story](../stories/stakeholder-influence-governance.md) - driving alignment across Oversight, ORM, IA without reporting authority | - -## Domain Knowledge - -| Domain | Depth | Evidence | -|--------|-------|----------| -| Enterprise Transformation | Expert | [Citi](../roles/citi-svp-transformation.md) - $7.1B portfolio oversight; cross-org program governance | -| Regulatory Compliance & Remediation | Expert | [Citi MRA Transformation](../projects/citi-mra-transformation.md) - Article XII.1.e requirements design; [Consent Order remediation](../roles/citi-svp-transformation.md) | -| Operating Model Design | Expert | [MRA reporting operating model](../projects/citi-mra-transformation.md) - requirements architecture, governance frameworks, sustainability testing | -| Governance Framework Design | Expert | [Citi](../roles/citi-svp-transformation.md) - financial governance ($7.1B), PM standards (15,000+ projects), oversight structures | -| MRA / Mapped Remedial Actions Management | Expert | [MRA transformation project](../projects/citi-mra-transformation.md) - requirements definition, design council leadership, evidence-based closure | -| Program/Project Management | Expert | [Citi](../roles/citi-svp-transformation.md) - 15,000+ project portfolio; lifecycle requirements; metrics & reporting | -| Wealth Management Strategy | Advanced | [Strategy&](../roles/strategy-and-senior-associate.md), [Morgan Stanley](../roles/morgan-stanley-avp.md), [Treliant](../roles/treliant-senior-consultant.md) | -| M&A / Growth Strategy | Advanced | [Strategy&](../roles/strategy-and-senior-associate.md) - $4B acquisition analysis | -| Trading Operations & Risk Management | Advanced | [BNP Paribas](../roles/bnp-paribas-client-services.md) - commodities, derivatives; regulatory frameworks during 2008 crisis | -| Financial Statement Analysis | Intermediate | [CMU MBA](../education/carnegie-mellon-mba.md) - A- grade | -| Data Analytics | Intermediate | [CMU MBA](../education/carnegie-mellon-mba.md) - Data Mining (A) | - -## Competency Tags - -Based on demonstrated experience: - -### Leadership -- First-time people manager (2023) -- Team coaching and development -- Leading cross-organizational initiatives - -### Problem-Solving -- Root cause analysis through first-principles thinking -- Process optimization and system redesign -- Six Sigma methodology -- Regulatory translation & requirements interpretation -- Ambiguity resolution through structured facilitation - -### Communication -- Executive presentations (CEO/Board level) -- Complex-to-simple translation (regulatory to operational) -- Business requirements documentation (BRDs, operating procedures) -- Stakeholder communication planning across constituencies -- Evidence-based executive packaging - -### Strategic Thinking -- M&A analysis and target identification -- Customer segmentation -- Operating model architecture and design -- Enterprise governance frameworks -- Regulatory remediation strategy - -### Execution -- Regulatory deliverable completion (>90% audit acceptance) -- On-time project delivery despite resourcing constraints -- Governance framework implementation and BAU hand-off -- Evidence-based testing and control validation -- Delivery under regulatory deadline pressure - -### Collaboration & Leadership -- Cross-functional consensus building (without formal authority) -- Design council facilitation across competing stakeholder interests -- Program governance and escalation management -- Influence across silos (Oversight, ORM, IA, business units) - -### Innovation -- AI-powered automation (EUC processes) -- Efficiency tools (Hot Keys workshops, templates); [Keyboard shortcuts training](../stories/keyboard-shortcuts-training.md) -- Creative reporting solutions (source-to-board operating model) -- Process innovation under regulatory constraints -- Training program design and delivery; [Keyboard shortcuts training](../stories/keyboard-shortcuts-training.md) -- Quality standardization; [Formatting best practices](../stories/formatting-best-practices.md) -- Strategic AI collaboration; [9 case studies](../ai-collaborations/_index.md) with quantified efficiency gains (33.9 hrs saved) -- Human-AI workflow design; reusable [framework patterns](../ai-collaborations/_index.md#framework-patterns) for enterprise adoption diff --git a/content/career/stories/_index.md b/content/career/stories/_index.md deleted file mode 100644 index 2af55b8..0000000 --- a/content/career/stories/_index.md +++ /dev/null @@ -1,42 +0,0 @@ -# Stories - -Interview-ready examples organized by competency. - -## By Competency - -### Leadership -- [Driving Executive Alignment Across Silos Without Formal Authority](stakeholder-influence-governance.md) - How to influence across governance boundaries -- [Creating Formatting Standards to Raise Team Deliverable Quality](formatting-best-practices.md) - Systems thinking applied to team quality improvement - -### Problem-Solving -- [Translating Vague Regulatory Requirements into an Enterprise Operating Model](regulatory-translation-mra.md) - First-principles thinking applied to regulatory translation - -### Communication -- [Driving Executive Alignment Across Silos Without Formal Authority](stakeholder-influence-governance.md) - Executive communication and stakeholder facilitation - -### Collaboration -- [Driving Executive Alignment Across Silos Without Formal Authority](stakeholder-influence-governance.md) - Cross-functional alignment under uncertainty - -### Strategic Thinking -- [Translating Vague Regulatory Requirements into an Enterprise Operating Model](regulatory-translation-mra.md) - Systems thinking and architecture design - -### Execution -- [Building Governance Frameworks Under Regulatory Deadline Pressure](governance-under-pressure.md) - Delivering complex work under deadline constraints -- [Translating Vague Regulatory Requirements into an Enterprise Operating Model](regulatory-translation-mra.md) - End-to-end execution from design through sustainability testing -- [Re-engineering a Budgeting & Resourcing Monitoring EUC into an Audit-Ready Data Pipeline](rbcm12-budgeting-resourcing-metrics.md) - Transforming manual processes into controlled, auditable systems -- [Building an EUC from Scratch to Bridge Reporting Gaps](unmapped-mra-reporting-euc.md) - Creating interim solutions designed for transition - -### Innovation -- [Building a New Service Model from Client Research to Pilot Launch](concierge-model-innovation.md) - End-to-end innovation from research to pilot with ~$15B AUM impact -- [Building a Keyboard Shortcuts Training Program to Accelerate Team Productivity](keyboard-shortcuts-training.md) - Self-initiated enablement program with team-wide adoption - -## Interview-Ready - -Stories marked as polished and ready to use: -- [Translating Vague Regulatory Requirements into an Enterprise Operating Model](regulatory-translation-mra.md) - **Problem-solving** - How to approach ambiguous regulatory requirements through first-principles thinking and design iteration -- [Building Governance Frameworks Under Regulatory Deadline Pressure](governance-under-pressure.md) - **Execution** - Balancing speed with rigor under compressed timelines -- [Driving Executive Alignment Across Silos Without Formal Authority](stakeholder-influence-governance.md) - **Leadership/Communication** - Influencing across boundaries and driving consensus through structured facilitation -- [Building a Keyboard Shortcuts Training Program to Accelerate Team Productivity](keyboard-shortcuts-training.md) - **Innovation** - Self-initiated training program with measurable adoption and behavior change -- [Re-engineering a Budgeting & Resourcing Monitoring EUC into an Audit-Ready Data Pipeline](rbcm12-budgeting-resourcing-metrics.md) - **Execution** - Transforming manual workflows into controlled, auditable PowerQuery pipelines -- [Creating Formatting Standards to Raise Team Deliverable Quality](formatting-best-practices.md) - **Leadership** - Systems thinking applied to team-wide quality improvement -- [Building an EUC from Scratch to Bridge Reporting Gaps](unmapped-mra-reporting-euc.md) - **Execution** - Creating compliant interim solutions with designed transition paths diff --git a/content/career/stories/concierge-model-innovation.md b/content/career/stories/concierge-model-innovation.md deleted file mode 100644 index aa18d89..0000000 --- a/content/career/stories/concierge-model-innovation.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: "Building a New Service Model from Client Research to Pilot Launch" -competency: "innovation" -interview_ready: true -tags: [innovation, strategic-thinking, client-research, service-design, morgan-stanley] -project: "../projects/ms-concierge-model.md" ---- - -## STAR Format - -### Situation - -At Morgan Stanley, our ultra-high-net-worth segment (clients with $25M+ in assets) was underperforming expectations. We were losing opportunities to competitors—private banks and multi-family offices—that offered more customized service. Leadership suspected the problem was service delivery, but didn't have systematic evidence of what clients actually needed. - -The challenge: Build something new in a large, established organization where "we've always done it this way" is a strong gravitational force. - -### Task - -I was brought in as AVP in the Business Unit Strategy team to **design and launch a new service model** for the firm's most valuable clients. This meant: -1. Validate (or invalidate) leadership's hypotheses through primary research -2. Design an operating model that could be delivered consistently -3. Pilot with real clients to prove the concept -4. Build the business case for broader rollout - -This wasn't advisory work—I needed to build something that actually worked. - -### Action - -**Step 1: Start with the Client** - -I designed structured interview protocols and conducted field research with the firm's top Financial Advisors (top 10% by AUM). The goal was to understand client pain points directly from the people who served them daily. - -Key insights emerged: -- **Onboarding was broken:** Complex multi-entity structures (trusts, LLCs, foundations) took months to set up, creating terrible first impressions -- **Analytics didn't match sophistication:** Family offices wanted institutional-grade reporting; we gave them retail -- **No single point of contact:** Clients bounced between specialists without anyone "quarterbacking" their relationship - -These findings contradicted some internal assumptions and redirected our design priorities. - -**Step 2: Design for Delivery** - -I created a "concierge" service architecture with three pillars: -- **Onboarding:** Dedicated specialist team for complex structures -- **Analytics:** Custom reporting tailored to family office needs -- **Relationship Management:** Single coordinator across product specialists - -The key design principle: **Support the Financial Advisor relationship, don't replace it.** The FA remained the primary relationship; we built tools to make them more effective. - -I documented service level definitions, staffing models, and technology requirements—everything needed to actually deliver, not just present. - -**Step 3: Pilot Early, Iterate Fast** - -Instead of endless design cycles, I pushed for a pilot with select FAs and clients. We established success metrics (onboarding time, client satisfaction, AUM growth) and built feedback loops to capture lessons. - -The pilot required cross-functional coordination across Operations, Technology, and Product—none of whom reported to me. I facilitated alignment through evidence from the research phase: "Here's what clients told us. Here's how we address it." - -**Step 4: Build Partnership Capabilities** - -Some capabilities required external partners. I led the custodian bank partnership evaluation—defining requirements, managing the RFP, coordinating due diligence—to fill gaps we couldn't build internally. - -### Result - -**Outcome:** -- ~$15B in new assets under management attributed to concierge-served relationships -- 40%+ reduction in onboarding time for complex structures -- Differentiated service tier competing effectively against private banks -- Model validated for broader rollout planning - -**What I'm Proud Of:** -- **Starting with research, not assumptions.** Field interviews revealed needs that internal hypotheses missed. The research redirected our design priorities toward what actually mattered. -- **Designing for delivery, not presentations.** I created documentation that operations teams could execute, not just decks for leadership. -- **Piloting early.** Real client feedback was worth more than months of internal design. We learned faster by launching small. -- **Building something new in a large organization.** Innovation in an established firm requires evidence, facilitation, and persistence—not just good ideas. - ---- - -## Interview Angles - -- **Tell me about a time you built something new.** This story demonstrates end-to-end innovation: research → design → pilot → scale planning -- **How do you approach innovation in established organizations?** Start with evidence (research), design for execution (not just presentation), pilot early to learn fast -- **How do you validate ideas before investing heavily?** Primary research with customers/field teams, followed by pilot-based validation with real metrics - ---- - -## Keywords - -Service innovation • Client research • Operating model design • Pilot launch • Cross-functional coordination • Design thinking • Wealth management • Ultra-high-net-worth diff --git a/content/career/stories/first-time-manager.md b/content/career/stories/first-time-manager.md deleted file mode 100644 index 4a1d88a..0000000 --- a/content/career/stories/first-time-manager.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: "Becoming a First-Time People Manager Under Transformation Pressure" -competency: "leadership" -interview_ready: true -tags: [leadership, people-management, team-development, first-time-manager, citi] ---- - -## STAR Format - -### Situation - -In 2023, I was promoted to a formal people management role at Citi while leading some of the firm's highest-priority regulatory transformation work. I inherited a team of 2 direct reports based in Tampa—both experienced professionals who had been operating independently. - -The challenge: Learn to be an effective manager while continuing to deliver on demanding transformation work, with a team that was geographically distributed and accustomed to working autonomously. - -### Task - -My responsibilities expanded to include: -1. **People development:** Coaching, feedback, career conversations -2. **Workload management:** Balancing assignments across team capabilities -3. **Continued delivery:** The regulatory work didn't slow down because I became a manager -4. **Remote leadership:** Building team cohesion with a Tampa-based team while I was in New York - -This was a significant transition. My prior experience was leading through influence—driving alignment across stakeholders who didn't report to me. Now I had formal authority, but also formal responsibility for others' development and performance. - -### Action - -**Step 1: Establish Regular Connection** - -I immediately set up consistent 1:1 cadences with both direct reports. The goal was to understand: -- What was working in their current assignments? -- What development areas did they want to focus on? -- Where could I add value vs. where should I get out of the way? - -I learned that both team members valued autonomy but wanted clearer visibility into priorities and more direct feedback on their work. - -**Step 2: Balance Autonomy with Guidance** - -Rather than micromanaging (which would have been counterproductive for experienced professionals), I focused on: -- **Clarifying objectives:** Making sure they understood the "why" behind assignments, not just the "what" -- **Removing blockers:** Using my cross-functional relationships to unblock issues they couldn't resolve independently -- **Providing context:** Sharing information about broader program priorities so they could make better local decisions - -**Step 3: Deliver Feedback Directly** - -My performance review noted that I needed to "increase transparency on objectives" and communicate more frequently on priorities. I took this seriously: -- Started providing more explicit feedback on deliverables—what worked, what could improve -- Increased visibility into my own calendar and priorities so the team understood competing demands -- Made development conversations more structured rather than ad hoc - -**Step 4: Balance Management with Delivery** - -The hardest part: I was still a primary contributor on critical workstreams while learning to manage. I had to be intentional about: -- Delegating appropriately (not hoarding work because "it's faster if I do it") -- Protecting time for management responsibilities (1:1s, feedback, development conversations) -- Modeling sustainable work practices despite deadline pressure - -### Result - -**Outcome:** -- Successfully onboarded into people management role while maintaining delivery on transformation work -- Team delivered on assigned regulatory workstreams (RBCM sustainability testing) -- Performance reviews reflected progress on management skills - -**Feedback Received:** -- Manager rating: "3-Valued Contributor" (first year in management role) -- Strengths highlighted: Complex-to-simple translation, rapid information synthesis, efficiency champion -- Development areas: Increase transparency on objectives, more frequent communication on priorities - -**What I Learned:** -- **Management is a different skill set.** Technical excellence doesn't automatically translate to people leadership. I had to be intentional about developing new capabilities. -- **Autonomy requires clarity.** Giving people autonomy works when they understand priorities and success criteria. I needed to provide more context, not less. -- **Feedback is a gift.** Being direct about performance—both positive and developmental—is more helpful than being vague to avoid discomfort. -- **Remote leadership requires intentionality.** You can't rely on hallway conversations or informal check-ins. Structure becomes more important. - -**What I'd Do Differently:** -- Establish clearer development goals earlier in the relationship -- Create more structured feedback mechanisms rather than relying on ad hoc conversations -- Be more proactive about communicating shifting priorities - ---- - -## Interview Angles - -- **Tell me about your first experience managing people.** This story demonstrates honest self-reflection about the transition from individual contributor to manager -- **How do you balance delivery with people management?** Intentional time allocation, appropriate delegation, protecting time for management responsibilities -- **What did you learn from feedback on your management style?** Took development feedback seriously (transparency, communication) and adjusted approach - ---- - -## Keywords - -First-time manager • People development • Remote leadership • Feedback • Team development • Work delegation • Performance management diff --git a/content/career/stories/formatting-best-practices.md b/content/career/stories/formatting-best-practices.md deleted file mode 100644 index fe6cb91..0000000 --- a/content/career/stories/formatting-best-practices.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: "Creating Formatting Standards to Raise Team Deliverable Quality" -competency: "leadership" -interview_ready: true -tags: [quality-standards, team-enablement, systems-thinking, communication, citi] -role: "../roles/citi-svp-transformation.md" ---- - -## STAR Format - -### Situation - -As PM Senior Lead (C14) in Citi Transformation, I identified recurring formatting inconsistencies and quality issues across my ~20-person team's deliverables. Slides varied in fonts, colors, spacing, table styles, and commentary patterns. This created rework cycles and undermined the professional polish of materials going to senior leadership. - -The root cause: Citi brand principles existed, but they weren't translated into **practical, operational rules** that analysts could apply without interpretation. - -### Task - -I independently decided to create a **Formatting Best Practices** deck that would standardize execution and reduce rework. This was self-initiated — I saw the gap and chose to fill it. - -### Action - -**Authored the Practical Standard** -- Served as sole author of a comprehensive formatting standard covering fonts, colors, spacing, tables, and commentary patterns -- Focused on the most common formatting decisions rather than trying to cover every edge case - -**Translated Brand to Operations** -- Took Citi brand principles and translated them into **operational rules** suitable for analysts -- Made the rules specific and actionable: exact font sizes, specific color codes, spacing measurements - -**Built Adoption Tools** -- Created reusable templates, examples, and sample matrices that demonstrated the standards in practice -- Made it easy to "do the right thing" by providing starting points rather than just rules - -### Result - -**Quality Impact:** -- Improved consistency of team deliverables -- Reduced formatting defects and rework cycles - -**Adoption:** -- Manager and peers adopted the standards organically -- Standards became the default approach rather than an imposed mandate - -**What I'm Proud Of:** -- Identifying a "death by a thousand cuts" problem and addressing it systematically -- Translating abstract principles into concrete, actionable guidance -- Building for adoption — not just documenting rules, but creating tools that made following them easier than not - ---- - -## Interview Angles - -- **How do you raise team quality?** Identify recurring friction, create practical standards, build adoption tools -- **Tell me about systems thinking:** Saw individual formatting issues as symptoms of a missing standard, addressed the root cause rather than fixing each instance -- **How do you drive change without formal authority?** Created something useful, made it easy to adopt, let quality speak for itself - ---- - -## Key Behaviors - -- Proactive problem-solving -- Systems thinking applied to craft -- Raising execution quality across the team -- Leading through influence, not mandate - ---- - -## Keywords - -Quality standards • Team enablement • Formatting • Brand translation • Templates • Systems thinking • Organic adoption diff --git a/content/career/stories/governance-under-pressure.md b/content/career/stories/governance-under-pressure.md deleted file mode 100644 index b349bcf..0000000 --- a/content/career/stories/governance-under-pressure.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: "Building Governance Frameworks Under Regulatory Deadline Pressure" -competency: "execution" -interview_ready: true -tags: [governance-design, regulatory-compliance, stakeholder-management, execution, citi] -project: "../projects/citi-mra-transformation.md" ---- - -## STAR Format - -### Situation - -At Citi, we had compressed quarter-end timelines for delivering MRA (Mapped Remedial Actions) reporting evidence to regulators. Leadership needed **Board-grade dashboards by specific dates** — 03/31/22 and 04/15/22 — with no room for delay. - -The problem: The underlying data was fragmented, inconsistent, and sometimes contradictory. We had to: -- Reconcile data across business lines with different definitions and taxonomies -- Create dashboards that could be challenged by auditors and regulators -- Do it fast enough to meet the deadline - -If we moved slowly (trying to be perfect), we'd miss the deadline. If we moved fast (with shortcuts), we'd have audit pushback. - -### Task - -I was responsible for **designing the data architecture and governance framework** that would: -1. Reconcile inconsistencies quickly without creating debt -2. Build defensible dashboards with clear sourcing logic -3. Document assumptions so reviewers could challenge them *before* we went to the Board - -### Action - -**Step 1: Scoped the Work Ruthlessly** -- Identified which data points were critical vs. nice-to-have -- Made **explicit scope calls** on thorny issues (e.g., "Should ARC be excluded from past-due counts?") -- Documented each decision with **footnoted rationales** — not to hide from scrutiny, but to invite it early - -**Step 2: Built a One-Time Reconciliation Framework** -- Created an **illustrative reconciliation workbook** (FRB Correspondence Reconciliation v1.xlsx) that showed: - - Gold Source alignment (reconciling iCAPS with hand-maintained data) - - Week-over-week snapshots showing where numbers diverged - - Explicit "type of work" required to produce senior reporting (not a recurring artifact) -- Ensured every number could be traced back to a source system with documented assumptions - -**Step 3: Created the Operating Model** -- Once the one-time reconciliation showed us what was possible, I **transitioned to a repeatable BAU process:** - - Built a **Management Summary deck** with severity/1-2 views and unmapped population by EMT and phase - - Designed the **BAU Transition Draft** (task matrix, POCs, QC steps, calendars, inputs/outputs, process flow) - - Created a **governance framework** with named roles, clear responsibilities, and escalation paths - -**Step 4: Handled Cross-Silo Normalization** -- Different businesses used different naming conventions and phase logic; the reconciliation would fail if we didn't align upfront -- Rather than force a single taxonomy (which would take forever to agree on), I created a **mapping layer:** - - Field-level definitions with footnotes explaining where conventions differed - - QC decision matrices that accommodated multiple interpretations (but with clear escalation if assumptions were wrong) - - Weekly trails showing timing/definition drivers so reviewers could preempt questions - -**Step 5: Maintained Attention to Detail While Moving Fast** -- Tracked week-over-week changes across snapshot counts to catch unexpected divergences -- Documented **near-cutoff figures** where small changes drove big portfolio moves -- Called out timing/definition drivers explicitly so senior reviewers didn't have to ask "why did this number change?" - -**Step 6: Transitioned to Sustainable Governance** -- After the one-time dashboard was delivered, I **authored the Transition Draft** to move production from "craft build" to **repeatable BAU** -- Built the **Weekly MRA Oversight Tracker** and **Committee presentation template** for ongoing governance -- Ensured the framework didn't require me — BAU could own it and Oversight could challenge it - -### Result - -**Outcome:** -- **Dashboard delivered on time** (Q1'22 and updated 04/15/22) with defensible definitions and clear sourcing logic -- **Regulatory confidence:** No pushback from auditors or regulators on assumptions — the documentation meant reviewers could challenge *before* it went to the Board -- **Repeatable process established:** BAU didn't have to recreate the reconciliation every quarter; the governance framework made it sustainable -- **Audit-ready:** Reconciliation workbook, dashboard, and sourcing logic all available for Consent Order reviews - -**Business Impact:** -- Avoided rework by handling scope and definitions upfront -- Reduced risk of regulatory pushback by inviting challenge early -- Established a governance model that Oversight Function and MRAAOF could use independently - -**What I'm Proud Of:** -- Balanced speed with rigor. Compressed timelines don't mean sloppy — they mean ruthless prioritization and clear rationales. -- The reconciliation workbook was a *one-time* artifact, but it informed everything downstream. No waste. -- Moved seamlessly from "here's what the data actually shows" to "here's a repeatable process the team can sustain" — that's the real value. - ---- - -## Interview Angles - -- **How do you prioritize under constraints?** Ruthless scope calls, explicit rationales, invite challenge early -- **How do you move fast without cutting corners?** Front-load definitions and assumptions; document the 'why'; test before you scale -- **What does 'governance-ready' mean to you?** Clear roles, documented decisions, audit trails, and a process that doesn't depend on any one person - ---- - -## Keywords - -Operating under pressure • Governance design • Data reconciliation • Cross-silo alignment • Executive communication • Regulatory readiness • Sustainable process design diff --git a/content/career/stories/keyboard-shortcuts-training.md b/content/career/stories/keyboard-shortcuts-training.md deleted file mode 100644 index 6dfcfb5..0000000 --- a/content/career/stories/keyboard-shortcuts-training.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: "Building a Keyboard Shortcuts Training Program to Accelerate Team Productivity" -competency: "innovation" -interview_ready: true -tags: [training, productivity, enablement, instructional-design, coaching, citi] -role: "../roles/citi-svp-transformation.md" ---- - -## STAR Format - -### Situation - -At Citi Transformation, I observed inefficiencies in my team's workflow. Team members were heavily mouse-dependent when building PowerPoint slides, which slowed down deck production and increased formatting inconsistencies. As a ~20-person team producing frequent executive materials, these small inefficiencies compounded into significant time loss and quality issues. - -### Task - -I decided to address this by creating an **interactive training curriculum** to accelerate PowerPoint proficiency and reduce mouse-dependence across the team. This was a self-initiated project — not assigned, but identified as a high-impact opportunity. - -### Action - -**Designed the Full Training Program** -- Served as sole designer/author of a complete training program with clear objectives, structured exercises, and progressive skill-building -- Built a **QAT (Quick Access Toolbar) setup** to reduce friction in adoption — team members could immediately apply shortcuts without memorizing keyboard combinations - -**Delivered Live Sessions** -- Conducted **3 live training sessions** with ~20 team members total -- Integrated real Citi text and slide examples for authentic practice -- Structured sessions to be hands-on, not lecture-based — participants practiced shortcuts in real-time - -**Applied Instructional Design Principles** -- Sequenced learning from basic to advanced shortcuts -- Created reference materials team members could use after sessions -- Focused on most impactful shortcuts rather than exhaustive coverage - -### Result - -**Adoption:** -- Manager (Alana) consistently adopted the shortcuts taught and modeled the behaviors -- Team-wide behavioral change in slide-building workflow - -**Quality & Efficiency:** -- Faster editing with fewer errors -- More standardized PowerPoint craftsmanship across deliverables - -**What I'm Proud Of:** -- Identifying an unglamorous but high-impact opportunity and executing it end-to-end -- Designing for real adoption (QAT setup, authentic practice) rather than just knowledge transfer -- The ripple effect: manager adoption signaled importance and accelerated team-wide change - ---- - -## Interview Angles - -- **Tell me about a time you improved team productivity:** Identified mouse-dependent workflow as friction, designed and delivered training program that changed team behavior -- **How do you approach enablement/coaching?** Design for adoption (reduce friction), use authentic examples, focus on practice over lecture -- **Initiative without being asked:** Saw an opportunity, built the solution, delivered it — demonstrated ownership beyond core responsibilities - ---- - -## Key Behaviors - -- Instructional design -- Productivity engineering -- Coaching & enablement leadership -- Proactive problem identification - ---- - -## Keywords - -Training design • Productivity optimization • PowerPoint efficiency • Quick Access Toolbar • Team enablement • Behavioral change • Coaching diff --git a/content/career/stories/rbcm12-budgeting-resourcing-metrics.md b/content/career/stories/rbcm12-budgeting-resourcing-metrics.md deleted file mode 100644 index c247bbe..0000000 --- a/content/career/stories/rbcm12-budgeting-resourcing-metrics.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: "Re-engineering a Budgeting & Resourcing Monitoring EUC into an Audit-Ready Data Pipeline" -competency: "execution" -interview_ready: true -tags: [data-engineering, powerquery, euc, governance, automation, regulatory, citi] -role: "../roles/citi-svp-transformation.md" ---- - -## STAR Format - -### Situation - -CPMC (Corporate Project Management Controls) required a monthly, controlled, audit-ready monitoring process for budgeting and resourcing across Org PMOs. The process needed to track approved IRs, TBD resource exposure, labor actuals, and IR-level variance. - -**The Challenge:** -- Early versions were manual and error-prone -- Later versions required automation, governance, and repeatable evidence -- The data came from multiple systems (PTS, Cognos, Gold Source) with no single source of truth - -I served as the **architectural lead and release approver** for the EUC (End-User Computing) pipeline that powered this reporting. - -### Task - -My remit was to: -1. Transform the B&R Monitoring EUC from manual copy-paste workflows into a controlled PowerQuery data pipeline -2. Establish monthly release protocols with quality control and governance -3. Author critical sections of the PCM (Policy and Control Manual) and design the operating model - -I was Secondary Owner for both the **B&R Monitoring EUC (102418640)** and the **IR Variance Dataset (102421708)**. While I didn't dictate metric thresholds (group decision), I owned *how* the system operationalized them. - -### Action - -**1. Re-engineered the EUC into a Controlled PowerQuery Pipeline** -- Drove the transition from manual copy-paste workflows (v1.x) to a **PQ-parameterized v5.0 pipeline** -- Added file-path parameters, month-end parameters, schema-drift resilience, consistent transformations, and structured refresh -- Reduced operational error risk and enabled monthly "refresh-and-review" - -**2. Established Monthly Release Protocol** -- Defined the runbook: create Use Copy, register via EUC Control Toolbar, update parameters, refresh queries/pivots, conduct QC checks, and approve final release -- The BA produced the "Lite" version; I sent communications and performed final approval of accuracy/controls - -**3. Authored Critical PCM Sections** -- Wrote/updated sections of the Budgeting & Resourcing PCM (v2.0 → v3.1) that codified inputs, cadence, maker-checker, evidence handling, exception flow, and Segment-A variance pipeline integration -- Embedded the automated pipeline in BAU governance - -**4. Designed Lineage Boundaries** -- Supported the approach to compute IR-level variance in 102421708 and append outputs into B&R reporting -- Met stakeholder cadence expectations without compromising traceability - -### Result - -**Technical Outcomes:** -- **Pivot table integrity:** Monthly refreshes sometimes reset month filters. I consistently identified and corrected these resets to prevent publishing incorrect Org PMO performance statuses -- **PowerQuery breakpoint diagnosis:** Isolated failures to specific query steps (schema drift, header promotion, data-type mismatches, parameter path errors) and corrected root causes to prevent corrupted or partial datasets - -**Governance Outcomes:** -- Metric thresholds were group-approved; my impact was on the controlled operationalization and release -- I was Secondary Owner on the EUCs (Primary listed separately) with architecture and release-approval rights -- PCM ownership remained with CPMC Governance; I contributed as an author - -**What I'm Proud Of:** -- Taking a fragile manual process and engineering it into something robust and auditable -- Balancing technical rigor with stakeholder pragmatism — meeting cadence without compromising traceability -- Building the release protocol so others could execute it without me - ---- - -## Interview Angles - -- **Tell me about a time you improved a data process:** Transformed manual copy-paste workflow into parameterized PowerQuery pipeline with governance controls -- **How do you handle complex, multi-source data?** Design lineage boundaries, standardize transformations, build refresh-and-review protocols -- **What does "audit-ready" mean to you?** Documented evidence paths, version control, maker-checker, traceable from source to output - ---- - -## Skills Demonstrated - -- Data pipeline design & modernization in Excel/PowerQuery under audit-grade controls -- Quality-gate design for recurring regulatory/controls reporting -- Operating model & governance authorship (PCM) -- Cross-functional alignment on metric lineage, cadence, and BAU embed -- Risk-mitigating architecture decisions in complex, multi-source reporting environments - ---- - -## Keywords - -PowerQuery • EUC governance • Data pipeline • Regulatory reporting • Audit controls • Version control • Schema drift • Operational resilience • BAU sustainability diff --git a/content/career/stories/regulatory-translation-mra.md b/content/career/stories/regulatory-translation-mra.md deleted file mode 100644 index 0334f25..0000000 --- a/content/career/stories/regulatory-translation-mra.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: "Translating Vague Regulatory Requirements into an Enterprise Operating Model" -competency: "problem-solving" -interview_ready: true -tags: [regulatory-translation, systems-thinking, strategic-thinking, execution, citi] -project: "../projects/citi-mra-transformation.md" ---- - -## STAR Format - -### Situation - -At Citi, our Consent Order required us to implement "effective MRA reporting" across 15,000+ projects — but the regulatory language in Article XII.1.e was abstract. Regulators wanted **clearer outcome assurance (CSC/KPIs)**, not just process adherence. - -The challenge: Different business lines interpreted the vague requirements differently. Teams didn't know: -- Which requirements actually applied to their projects -- How to measure compliance -- Who was accountable for what - -Without clarity, we'd either over-build (wasting resources) or under-deliver (failing the Consent Order). - -### Task - -I was brought in as SVP, Transformation Senior Lead to **translate the regulatory intent into a concrete, scalable operating model** that the entire organization could execute consistently. - -Specifically, I needed to: -1. Define what "effective reporting" actually meant (with auditable evidence) -2. Create a standardized process that worked across fragmented systems (RET, iCAPS, PTS) -3. Design it so BAU teams could own it sustainably - -### Action - -**Step 1: First-Principles Interpretation** -- Dug into the Consent Order documents and regulatory guidance to understand *why* the regulators cared about MRA reporting -- Worked backward from regulatory intent: they wanted **assurance that requirements were actually implemented, not just reported on** -- Mapped abstract concepts ("effective reporting," "assurance-readiness") to concrete checkpoints and evidence paths - -**Step 2: Designed the Operating Model** -- Created a **MRA Reporting Operating Model** with three key components: - - **Field inventory & sourcing logic:** Which data points had to come from which systems, with pre-populated fields to minimize manual error - - **Quality control decision matrices:** Clear criteria for what "pass," "fail," or "N/A" meant at individual and portfolio levels - - **Governance architecture:** Weekly oversight tracking, escalation constructs, and stakeholder roles — all documented so anyone could execute it - -**Step 3: Built the Design Council** -- Established a **cross-functional design council** with Oversight Function, ORM, IA, and business representatives -- Ran working sessions to test the model: *"Does this requirement actually match the regulatory intent? Can we measure it? Who owns it?"* -- Iterated through 3 major versions (packs #1-3) based on feedback, with **explicit version lineage** tracking requirement evolution - -**Step 4: Executed Sustainability Testing** -- Didn't just hand off the model — **led cross-functional testing** to prove it worked -- Tested 19 of 24 execute-phase requirements using a defined sampling approach and applicability rules -- Documented all findings in an **executive-ready sustainability package** with evidence traceability and control-framework interpretation -- Secured governance alignment from IA, ORM, and MRAOF to confirm the approach would be BAU-sustainable - -**Step 5: Packaged for Executive Consumption** -- Created **Board-grade dashboards** with clear, cited definitions (e.g., "past due = original date; long-dated = 20+ years; ARC excluded from counts") -- Built a **weekly Oversight Tracker** template that BAU teams could use to report status and flag issues -- Authored executive narratives explaining *why* each design choice mattered for regulatory compliance - -### Result - -**Outcome:** -- **v1.8 - v1.12 Unmapped MRA Requirements document:** Progressive clarification from draft to final, with embedded version lineage showing how we resolved ambiguities -- **Operating model fully documented & tested:** Sustainability testing package validated that the design actually worked across fragmented systems -- **BAU ready:** By Q4 2023, the Oversight Function and MRAAOF fully owned the operating model; no longer dependent on me for governance decisions -- **Regulatory confidence:** The model demonstrated to regulators that we had moved from "vague compliance" to **auditable, measured assurance** - -**Business Impact:** -- Eliminated confusion across 15,000+ projects about which MRA requirements applied -- Reduced rework during regulatory reviews by standardizing definitions and evidence paths -- Created a sustainable, repeatable process that could scale with future Consent Order changes - -**What I'm Proud Of:** -- Taking abstract regulatory language and forging it into something concrete and auditable — a real operating model, not just a policy document -- Designing for *sustainability:* The whole point was to hand it off to BAU and have it work without me -- Staying rigorous under pressure: Compressed timelines meant "fast decisions," but I documented assumptions and boundaries so reviewers could challenge without derailing momentum - ---- - -## Interview Angles - -- **How do you approach ambiguous requirements?** Start with intent, map to concrete evidence, test iteratively, document rationales -- **How do you drive alignment across silos?** Design councils, working sessions, documented feedback loops, explicit versioning -- **What's your definition of "good" design?** It's sustainable — BAU can execute it without you, and it's auditable so you can prove it works - ---- - -## Keywords - -Regulatory translation • Operating model design • First-principles thinking • Cross-functional facilitation • Stakeholder alignment • Evidence-based governance • Execution under ambiguity diff --git a/content/career/stories/stakeholder-influence-governance.md b/content/career/stories/stakeholder-influence-governance.md deleted file mode 100644 index 36908f7..0000000 --- a/content/career/stories/stakeholder-influence-governance.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: "Driving Executive Alignment Across Silos Without Formal Authority" -competency: "communication" -interview_ready: true -tags: [stakeholder-management, leadership, communication, regulatory-compliance, citi] -project: "../projects/citi-mra-transformation.md" ---- - -## STAR Format - -### Situation - -At Citi, the MRA Reporting operating model required alignment across **five different governance constituencies:** -- Oversight Function (who wanted intervention-focused controls) -- ORM (Operational Risk Management) -- IA (Internal Audit) -- MRAAOF (MRA Oversight Function) -- Multiple business units (who had competing priorities) - -The challenge: These groups had different views on what "MRA reporting" should look like. Oversight wanted **outcome-based KPIs**. IA wanted **evidence trails and sampling justification**. Business units wanted **minimal manual effort**. Without alignment, we'd either: -- Build something that failed audit (too loose) -- Build something unsustainable (too rigid) -- Get stuck in endless debate - -I had **no formal authority** over any of these groups — no reporting line, no budget, no veto power. - -### Task - -I was responsible for **facilitating consensus** across these groups while maintaining: -- Regulatory defensibility (auditors had to buy it) -- Operational sustainability (BAU had to be able to execute it) -- Executive clarity (the Board and CEO needed to understand it) - -### Action - -**Step 1: Structured the Design Council** -- Instead of ad-hoc meetings, I created a **formal Design Council** with explicit cadence (monthly), agenda-setting process, and decision documentation -- Invited representatives from each constituency (Oversight, ORM, IA, MRAAOF, business PMOs) — not as a rubber stamp, but to surface conflicts early -- Built in **working sessions** between Council meetings where we could dig into technical details - -**Step 2: Made Conflicts Visible (Not Hidden)** -- Rather than hiding disagreements behind closed doors, I **documented open options:** - - Option A: Strict QC approach (auditor-preferred, operationally heavier) - - Option B: Risk-based sampling (operationally lighter, requires documented rationales) - - Option C: Hybrid approach (most sustainable, requires clear governance) -- Presented each option with **tradeoffs clearly stated** — auditor confidence vs. BAU effort vs. definition rigor - -**Step 3: Built Credibility Through Rigor** -- When I presented options, they were backed by: - - **Evidence:** Actual data showing impact (e.g., "Strict QC requires 40 hours/week; risk-based sampling requires 15 hours/week + governance overhead") - - **Regulatory grounding:** Citations to Consent Order language and regulatory guidance - - **Operational testing:** Pilot runs showing what each approach actually cost to execute -- This meant stakeholders trusted my analysis, even when I was recommending something they hadn't suggested - -**Step 4: Facilitated Decisions (Without Authority)** -- When groups disagreed, I didn't pick winners — I **structured the decision:** - - "Here's the regulatory requirement" - - "Here are the three ways to satisfy it" - - "Here are the tradeoffs" - - "Oversight leads; IA advises; MRAAOF owns; ORM escalates if risk issues" -- This gave each group a clear role, and they owned the decision collectively - -**Step 5: Made It Real With Concrete Artifacts** -- Abstract arguments go nowhere. I **built prototypes:** - - **Checklists & process flows:** Showed *exactly* what work each approach required - - **Committee presentation templates:** Showed what stakeholders would see in governance meetings - - **Weekly tracker mockups:** Made the governance process tangible, not theoretical -- When people could see "this is what you'll be doing every week," alignment happened faster - -**Step 6: Socialized Decisions Persistently** -- Didn't announce the model once; instead, I: - - Built the **6.2 Communications Plan** with explicit messaging by audience (PMOs, SPOCs, PMs, oversight partners) - - Established **Office Hours** for Q&A and issue resolution - - Created **FAQs** addressing adoption concerns - - Scheduled follow-up sessions with each constituency to ensure they felt heard - -**Step 7: Escalated With Grace** -- When groups truly disagreed and couldn't resolve it at Design Council level, I escalated to **Oversight** (the sponsoring function) with a clear memo: - - "Here's what the groups agree on" - - "Here's where they diverge" - - "Here's what each option costs/risks" - - "Here's my recommendation and why" -- Oversight then made the call, and I executed it without blame-shifting - -### Result - -**Outcome:** -- **Full alignment achieved** across Oversight, ORM, IA, MRAAOF, and business units on the final operating model -- **Design Council adopted as governance body:** The model became so credible that it transitioned from a design tool to an ongoing governance forum -- **Seamless handoff to BAU:** When the model went live, all constituencies were aligned — no surprises, no pushback - -**Business Impact:** -- Compressed timeline: Went from conceptual model to validated, governance-ready design in ~12 months (normally this takes 18-24) -- Regulatory confidence: Auditors saw broad stakeholder alignment and approved the model without major revisions -- Sustained adoption: By Q4 2023, BAU owned the process with continued Oversight Committee governance - -**Stakeholder Feedback:** -- Oversight noted "clear definitions and defensible sourcing logic" -- IA appreciated the "structured evidence paths and sampling documentation" -- Business units found it "operationally sustainable with clear roles" -- CEO/Board saw it as a model for how to translate regulatory intent into executable processes - -**What I'm Proud Of:** -- **Influence without authority:** I had no leverage, but the quality of thinking and clarity of communication built credibility that influenced everyone -- **Making the abstract concrete:** People don't align on "governance frameworks" — they align when they see the actual work they'll be doing -- **Scaling from design to sustained governance:** The Council didn't dissolve after design; it became the ongoing governance body, which means the decisions stuck - ---- - -## Interview Angles - -- **How do you drive decisions when you don't have authority?** Build credibility through rigor, make tradeoffs visible, give stakeholders clear roles, escalate with clarity -- **How do you break through silos?** Structured forums, documented disagreements, concrete prototypes, persistent socialization -- **What's your philosophy on stakeholder management?** Everyone should understand how their decisions impact the final model — no surprises, no finger-pointing - ---- - -## Keywords - -Stakeholder alignment • Cross-functional leadership • Influence without authority • Governance design • Decision facilitation • Organizational change • Executive communication diff --git a/content/career/stories/unmapped-mra-reporting-euc.md b/content/career/stories/unmapped-mra-reporting-euc.md deleted file mode 100644 index c4944bf..0000000 --- a/content/career/stories/unmapped-mra-reporting-euc.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Building an EUC from Scratch to Bridge Reporting Gaps During IT Solution Development" -competency: "execution" -interview_ready: true -tags: [euc, data-engineering, regulatory, transition-leadership, problem-solving, citi] -role: "../roles/citi-svp-transformation.md" ---- - -## STAR Format - -### Situation - -As Program Management Senior Lead, I was responsible for piloting standardized reporting for Unmapped MRAs (Material Risk Areas). However, a gap existed: the enterprise IT-managed solution was still being developed, but reporting needed to happen now. - -**The Challenge:** -- No existing tool to produce the required reporting -- Regulatory timelines couldn't wait for the IT solution -- Source systems were fragmented (PTS, Cognos, Gold Source) and mandated by enterprise design - -### Task - -I needed to **create an EUC from scratch** to bridge the reporting gap while the long-term IT-managed solution was developed. This wasn't just a temporary workaround — it needed to be controlled, auditable, and capable of smooth transition to the permanent solution. - -### Action - -**1. Built End-to-End EUC Process** -- Designed the complete EUC including process logic, folder taxonomy, and monthly runbook -- Engineered data logic including ID normalization, dedupe patterns, merge sequencing, and schema drift handling - -**2. Executed Monthly Processing Runs** -- Supervised monthly processing runs and owned accuracy of outputs -- Performed quality control checks and variance analysis each cycle - -**3. Maintained EUC Compliance** -- Documented procedures, change control, archival, and audit interactions -- Maintained full EUC compliance: documented procedures, change control, archival, and audit interactions - -**4. Drove Transition Planning** -- Authored the BRD (Business Requirements Document) for the tool-based long-term solution -- Planned the transition path so the EUC could be retired cleanly once the IT solution was ready - -### Result - -**Delivery:** -- Successfully bridged the reporting gap with a fully functional, compliant EUC -- Monthly outputs met regulatory reporting requirements on time - -**Skills Demonstrated:** -- Regulatory reporting expertise -- EUC governance and compliance -- Data engineering and operating-model design -- Stakeholder alignment and transition leadership - -**What I'm Proud Of:** -- Creating something from nothing under time pressure — and making it auditable, not just functional -- Designing for transition: the EUC was built to be retired, not to become permanent technical debt -- Directing the design work while performing final approvals — bridging strategic and hands-on execution - ---- - -## Interview Angles - -- **Tell me about a time you built something from scratch:** Created reporting EUC while IT solution was in development, maintained compliance throughout -- **How do you handle interim solutions?** Design for transition from day one — document, control, plan the sunset -- **How do you work with fragmented data sources?** Normalize IDs, build merge sequences, handle schema drift, document lineage - ---- - -## Notes - -- Direct report supported coding edits; I directed design and performed final approvals -- Source systems (PTS, Cognos, Gold Source) mandated by enterprise design — I worked within those constraints - ---- - -## Keywords - -EUC development • Regulatory reporting • Data engineering • Operating model design • Transition planning • Schema drift • Audit compliance • Gap bridging diff --git a/e2e/landing.spec.ts b/e2e/landing.spec.ts new file mode 100644 index 0000000..a19192f --- /dev/null +++ b/e2e/landing.spec.ts @@ -0,0 +1,99 @@ +import { test, expect } from "@playwright/test"; +import { PROJECTS } from "../lib/content/projects"; +import { POSTS } from "../lib/content/writing"; + +test.describe("Landing structure", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/"); + }); + + test("leads with projects, not the resume", async ({ page }) => { + const projectsTop = await page + .locator("#projects") + .evaluate((el: HTMLElement) => el.offsetTop); + const resumeTop = await page + .locator("#resume") + .evaluate((el: HTMLElement) => el.offsetTop); + + expect(projectsTop).toBeLessThan(resumeTop); + }); + + test("renders a card for every project", async ({ page }) => { + await expect(page.locator("#projects .work-card")).toHaveCount( + PROJECTS.length, + ); + + for (const project of PROJECTS) { + await expect( + page.locator("#projects").getByText(project.name, { exact: true }), + ).toBeVisible(); + } + }); + + test("linked project cards are anchors with a real href", async ({ page }) => { + const linked = PROJECTS.filter((p) => p.href); + + for (const project of linked) { + const card = page.locator(`#projects a.work-card[href="${project.href}"]`); + await expect(card).toHaveAttribute("target", "_blank"); + await expect(card).toHaveAttribute("rel", /noreferrer/); + } + + // Projects with no public repo and no live URL must not render as links. + await expect(page.locator("#projects a.work-card")).toHaveCount( + linked.length, + ); + }); + + test("project cards are keyboard focusable", async ({ page }) => { + const firstLinked = page.locator("#projects a.work-card").first(); + await firstLinked.focus(); + await expect(firstLinked).toBeFocused(); + }); + + // The core invariant of the redesign: Writing stays invisible until the + // Substack has real posts, rather than shipping a "Coming soon" stub. + test("writing section and nav link track post count together", async ({ + page, + }) => { + const expected = POSTS.length > 0 ? 1 : 0; + + await expect(page.locator("#writing")).toHaveCount(expected); + await expect( + page.locator(".nav-links").getByText("Writing", { exact: true }), + ).toHaveCount(expected); + }); + + test("no career-first content survives on the page", async ({ page }) => { + await expect(page.locator(".themes-grid")).toHaveCount(0); + await expect(page.getByText("Request CV")).toHaveCount(0); + await expect(page.getByText(/Harnessing AI/i)).toHaveCount(0); + }); + + test("nav is reachable on mobile", async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await expect( + page.locator(".nav-links").getByText("Projects", { exact: true }), + ).toBeVisible(); + }); +}); + +// The long headline and the wide-tracked contact echo each blew past the +// viewport on phones. Nothing should make the page scroll sideways. +test.describe("No horizontal overflow", () => { + for (const width of [320, 360, 390, 430, 768, 1024, 1440]) { + test(`page does not scroll sideways at ${width}px`, async ({ page }) => { + await page.setViewportSize({ width, height: 844 }); + await page.goto("/"); + await page.evaluate(() => document.fonts.ready); + await page.waitForTimeout(600); + + const { scrollWidth, clientWidth } = await page.evaluate(() => ({ + scrollWidth: document.documentElement.scrollWidth, + clientWidth: document.documentElement.clientWidth, + })); + + expect(scrollWidth).toBeLessThanOrEqual(clientWidth); + }); + } +}); diff --git a/e2e/travel.spec.ts b/e2e/travel.spec.ts index 7df0df9..d96bab2 100644 --- a/e2e/travel.spec.ts +++ b/e2e/travel.spec.ts @@ -3,7 +3,9 @@ import { test, expect } from "@playwright/test"; test.describe("Travel map", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.getByText("My Travel Map").scrollIntoViewIfNeeded(); + // "My Travel Map" was pre-brutalist copy and no longer exists, so this + // hook failed on every test. Scroll to the section itself instead. + await page.locator("#travel").scrollIntoViewIfNeeded(); }); test("renders the travel map globe", async ({ page }) => { diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..861b585 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,7 +12,17 @@ const eslintConfig = defineConfig([ "out/**", "build/**", "next-env.d.ts", + "test-results/**", + "playwright-report/**", ]), + { + // Build/data scripts are CommonJS run directly by node, not bundled. + // require() is correct there, so don't apply the app's ESM rule to them. + files: ["scripts/**/*.js"], + rules: { + "@typescript-eslint/no-require-imports": "off", + }, + }, ]); export default eslintConfig; diff --git a/hooks/useCareerData.ts b/hooks/useCareerData.ts deleted file mode 100644 index 2d5cbff..0000000 --- a/hooks/useCareerData.ts +++ /dev/null @@ -1,106 +0,0 @@ -'use client' - -import { useEffect, useState } from 'react' - -interface CareerEntry { - title: string - date: string - description?: string - tags?: string[] - [key: string]: unknown -} - -interface UseCareerDataReturn { - data: CareerEntry[] | null - loading: boolean - error: Error | null - refetch: () => Promise -} - -/** - * Custom hook for fetching career data - * Handles loading and error states - */ -export function useCareerData(): UseCareerDataReturn { - const [data, setData] = useState(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) - - const fetchData = async () => { - try { - setLoading(true) - setError(null) - - // In a real app, this would fetch from an API - // For now, we assume data is loaded server-side - // This hook can be used for client-side refetching if needed - - setLoading(false) - } catch (err) { - const errorObj = err instanceof Error ? err : new Error(String(err)) - setError(errorObj) - setLoading(false) - } - } - - useEffect(() => { - fetchData() - }, []) - - return { - data, - loading, - error, - refetch: fetchData - } -} - -/** - * Hook for caching data with timestamps - */ -export function useCachedData( - key: string, - fetcher: () => Promise, - cacheTime = 5 * 60 * 1000 // 5 minutes -) { - const [data, setData] = useState(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) - - useEffect(() => { - const cached = typeof window !== 'undefined' - ? sessionStorage.getItem(`cache_${key}`) - : null - - if (cached) { - const { data: cachedData, timestamp } = JSON.parse(cached) - if (Date.now() - timestamp < cacheTime) { - setData(cachedData) - setLoading(false) - return - } - } - - fetcher() - .then((result) => { - setData(result) - if (typeof window !== 'undefined') { - sessionStorage.setItem( - `cache_${key}`, - JSON.stringify({ - data: result, - timestamp: Date.now() - }) - ) - } - }) - .catch((err) => { - setError(err instanceof Error ? err : new Error(String(err))) - }) - .finally(() => { - setLoading(false) - }) - }, [key, fetcher, cacheTime]) - - return { data, loading, error } -} diff --git a/hooks/useMediaQuery.ts b/hooks/useMediaQuery.ts deleted file mode 100644 index 2206a26..0000000 --- a/hooks/useMediaQuery.ts +++ /dev/null @@ -1,54 +0,0 @@ -'use client' - -import { useEffect, useState } from 'react' - -/** - * Hook to detect media query matches - * @param query - CSS media query string - * @returns boolean indicating if media query matches - */ -export function useMediaQuery(query: string): boolean { - const [matches, setMatches] = useState(false) - - useEffect(() => { - // Set initial value - const mediaQuery = window.matchMedia(query) - setMatches(mediaQuery.matches) - - // Listen for changes - const handleChange = (e: MediaQueryListEvent) => { - setMatches(e.matches) - } - - mediaQuery.addEventListener('change', handleChange) - return () => mediaQuery.removeEventListener('change', handleChange) - }, [query]) - - return matches -} - -/** - * Common breakpoints - */ -export const BREAKPOINTS = { - sm: '(min-width: 640px)', - md: '(min-width: 768px)', - lg: '(min-width: 1024px)', - xl: '(min-width: 1280px)', - '2xl': '(min-width: 1536px)' -} as const - -/** - * Helper hooks for common breakpoints - */ -export function useIsMobile() { - return !useMediaQuery(BREAKPOINTS.md) -} - -export function useIsTablet() { - return useMediaQuery(BREAKPOINTS.md) && !useMediaQuery(BREAKPOINTS.lg) -} - -export function useIsDesktop() { - return useMediaQuery(BREAKPOINTS.lg) -} diff --git a/hooks/useScrollProgress.ts b/hooks/useScrollProgress.ts deleted file mode 100644 index 95b53ea..0000000 --- a/hooks/useScrollProgress.ts +++ /dev/null @@ -1,57 +0,0 @@ -'use client' - -import { useEffect, useRef, useState } from 'react' - -/** - * Hook to track scroll progress (0-100) - * @returns number between 0 and 100 - */ -export function useScrollProgress(): number { - const [progress, setProgress] = useState(0) - - useEffect(() => { - const handleScroll = () => { - const windowHeight = window.innerHeight - const documentHeight = document.documentElement.scrollHeight - windowHeight - const scrolled = window.scrollY - const scrollProgress = documentHeight > 0 ? (scrolled / documentHeight) * 100 : 0 - setProgress(scrollProgress) - } - - window.addEventListener('scroll', handleScroll) - return () => window.removeEventListener('scroll', handleScroll) - }, []) - - return progress -} - -/** - * Hook to detect if element is in viewport - * @param options - IntersectionObserver options - * @returns ref to attach to element, isVisible boolean - */ -export function useInView( - options?: IntersectionObserverInit -): [React.RefObject, boolean] { - const ref = useRef(null) - const [isInView, setIsInView] = useState(false) - - useEffect(() => { - const observer = new IntersectionObserver(([entry]) => { - if (entry.isIntersecting) { - setIsInView(true) - observer.unobserve(entry.target) - } - }, options) - - if (ref.current) { - observer.observe(ref.current) - } - - return () => { - observer.disconnect() - } - }, [options]) - - return [ref, isInView] -} diff --git a/lib/constants.ts b/lib/constants.ts deleted file mode 100644 index 9dfff08..0000000 --- a/lib/constants.ts +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Application-wide constants - */ - -// Site metadata -export const SITE_NAME = 'Personal Portfolio' -export const SITE_DESCRIPTION = 'My professional portfolio and career journey' -export const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://dommango.github.io' - -// Navigation links -export const NAV_LINKS = [ - { label: 'Home', href: '/' }, - { label: 'Career', href: '/career' }, - { label: 'Skills', href: '/skills' }, - { label: 'Education', href: '/education' }, - { label: 'Contact', href: '/contact' } -] as const - -// Social media links -export const SOCIAL_LINKS = { - github: 'https://github.com/dommango', - linkedin: 'https://linkedin.com/in/dommangonon', - twitter: 'https://x.com/collapsecontext', - email: 'dom.mangonon@gmail.com' -} as const - -// Skills categories -export const SKILL_CATEGORIES = { - FRONTEND: 'Frontend', - BACKEND: 'Backend', - DEVOPS: 'DevOps', - TOOLS: 'Tools & Services' -} as const - -// Pagination defaults -export const DEFAULT_PAGE_SIZE = 10 -export const MAX_PAGE_SIZE = 100 - -// Form validation -export const FORM_LIMITS = { - NAME: { - MIN: 2, - MAX: 100 - }, - EMAIL: { - MAX: 254 // RFC 5321 - }, - SUBJECT: { - MIN: 5, - MAX: 200 - }, - MESSAGE: { - MIN: 10, - MAX: 5000 - } -} as const - -// Time formats -export const DATE_FORMAT = 'MMM d, yyyy' -export const DATE_TIME_FORMAT = 'MMM d, yyyy h:mm a' - -// Animation durations (ms) -export const ANIMATION_DURATION = { - FAST: 150, - NORMAL: 300, - SLOW: 500, - VERY_SLOW: 800 -} as const - -// Content cache time -export const CACHE_TIME = { - SHORT: 5 * 60 * 1000, // 5 minutes - MEDIUM: 30 * 60 * 1000, // 30 minutes - LONG: 24 * 60 * 60 * 1000 // 24 hours -} as const - -// Color palette -export const COLORS = { - PRIMARY: '#3b82f6', // blue-600 - SECONDARY: '#8b5cf6', // violet-600 - SUCCESS: '#10b981', // emerald-600 - ERROR: '#ef4444', // red-500 - WARNING: '#f59e0b', // amber-500 - MUTED: '#6b7280' // gray-500 -} as const - -// Typography -export const TYPOGRAPHY = { - HEADING_1: 'text-4xl md:text-5xl font-bold', - HEADING_2: 'text-3xl md:text-4xl font-bold', - HEADING_3: 'text-2xl md:text-3xl font-bold', - BODY_LARGE: 'text-lg', - BODY_DEFAULT: 'text-base', - BODY_SMALL: 'text-sm', - CAPTION: 'text-xs' -} as const - -// Spacing scale -export const SPACING = { - XS: '0.25rem', // 4px - SM: '0.5rem', // 8px - MD: '1rem', // 16px - LG: '1.5rem', // 24px - XL: '2rem', // 32px - '2XL': '3rem', // 48px - '3XL': '4rem' // 64px -} as const - -// Z-index scale -export const Z_INDEX = { - BASE: 0, - DROPDOWN: 1000, - STICKY: 1020, - FIXED: 1030, - MODAL_BACKDROP: 1040, - MODAL: 1050, - POPOVER: 1060, - TOOLTIP: 1070 -} as const - -// HTTP Status Codes -export const HTTP_STATUS = { - OK: 200, - CREATED: 201, - BAD_REQUEST: 400, - UNAUTHORIZED: 401, - FORBIDDEN: 403, - NOT_FOUND: 404, - CONFLICT: 409, - INTERNAL_SERVER_ERROR: 500, - SERVICE_UNAVAILABLE: 503 -} as const diff --git a/lib/content/education.ts b/lib/content/education.ts deleted file mode 100644 index c7b6220..0000000 --- a/lib/content/education.ts +++ /dev/null @@ -1,54 +0,0 @@ -import fs from 'fs' -import path from 'path' -import matter from 'gray-matter' - -const CAREER_DIR = process.env.NODE_ENV === 'production' - ? path.join(process.cwd(), 'content/career') - : '/home/dom/career' - -export interface Degree { - school: string - degree: string - field: string - graduation_year: number - gpa?: string - content: string - slug: string -} - -export interface Education { - degrees: Degree[] -} - -export function getEducation(): Education { - const educationDir = path.join(CAREER_DIR, 'education') - - if (!fs.existsSync(educationDir)) { - console.warn('Education directory not found at', educationDir) - return { degrees: [] } - } - - const files = fs.readdirSync(educationDir) - .filter(f => f.endsWith('.md') && f !== '_index.md') - - const degrees = files.map(filename => { - const fullPath = path.join(educationDir, filename) - const fileContents = fs.readFileSync(fullPath, 'utf8') - const { data, content } = matter(fileContents) - - return { - school: data.school || '', - degree: data.degree || '', - field: data.field || '', - graduation_year: data.graduation_year || new Date().getFullYear(), - gpa: data.gpa || '', - content, - slug: filename.replace('.md', ''), - } as Degree - }) - - // Sort by graduation year descending (most recent first) - return { - degrees: degrees.sort((a, b) => b.graduation_year - a.graduation_year), - } -} diff --git a/lib/content/profile.ts b/lib/content/profile.ts deleted file mode 100644 index 64a8bec..0000000 --- a/lib/content/profile.ts +++ /dev/null @@ -1,99 +0,0 @@ -import fs from 'fs' -import path from 'path' -import matter from 'gray-matter' - -const CAREER_DIR = process.env.NODE_ENV === 'production' - ? path.join(process.cwd(), 'content/career') - : '/home/dom/career' - -export interface CareerTheme { - title: string - description: string -} - -export interface Profile { - name: string - headline: string - location: string - email: string - linkedin: string - twitter: string - substack: string - github: string - website: string - travel: string - interests: string[] - summary: string - careerThemes: CareerTheme[] - content: string -} - -export function getProfile(): Profile { - const profilePath = path.join(CAREER_DIR, 'profile.md') - - if (!fs.existsSync(profilePath)) { - console.warn('Profile file not found at', profilePath) - return getDefaultProfile() - } - - const fileContents = fs.readFileSync(profilePath, 'utf8') - const { data, content } = matter(fileContents) - - // Parse career themes from content - const careerThemes = parseCareerThemes(content) - - return { - name: data.name || '', - headline: data.headline || '', - location: data.location || '', - email: data.email || '', - linkedin: data.linkedin || '', - twitter: data.twitter || '', - substack: data.substack || '', - github: data.github || '', - website: data.website || '', - travel: data.travel || '', - interests: data.interests || [], - summary: extractSummary(content), - careerThemes, - content, - } -} - -function extractSummary(content: string): string { - // Extract the Professional Summary section - const match = content.match(/## Professional Summary\n\n(.+?)(?=\n##|$)/s) - return match ? match[1].trim() : '' -} - -function parseCareerThemes(content: string): CareerTheme[] { - const themes: CareerTheme[] = [] - const themeMatches = content.matchAll(/### (\d+\..+?)\n(.+?)(?=\n###|\n## |$)/gs) - - for (const match of themeMatches) { - const title = match[1].replace(/^\d+\.\s*/, '').trim() - const description = match[2].trim() - themes.push({ title, description }) - } - - return themes -} - -function getDefaultProfile(): Profile { - return { - name: 'Professional', - headline: 'Portfolio', - location: '', - email: '', - linkedin: '', - twitter: '', - substack: '', - github: '', - website: '', - travel: '', - interests: [], - summary: 'Career information loading...', - careerThemes: [], - content: '', - } -} diff --git a/lib/content/projects.ts b/lib/content/projects.ts new file mode 100644 index 0000000..b22a743 --- /dev/null +++ b/lib/content/projects.ts @@ -0,0 +1,93 @@ +// Projects — hand-authored portfolio data, read at build time. +// +// Typed TS rather than JSON on purpose: these are written by hand, not +// generated, and an empty JSON array would infer never[] under strict. +// +// `href` is the single link the card points at. Omit it for projects with +// neither a public repo nor a reachable URL — those render as plain cards. + +export interface Project { + /** Catalog ID in the card's top-left, e.g. "#sous-0001/05". */ + id: string + name: string + /** Stack line, rendered uppercase in the card. */ + stack: string + year: string + /** The one number or fact worth leading with. Rendered in the accent color. */ + impact: string + points: string[] + href?: string + /** Where `href` goes — sets the card's link label. */ + hrefKind?: 'live' | 'repo' +} + +export const PROJECTS: Project[] = [ + { + id: '#sous-0001/05', + name: 'SousIQ', + stack: 'Express · React 19 · Postgres + pgvector · Claude', + year: '2025 →', + impact: 'Live · field-tested in a working bakery', + points: [ + 'Parses vendor invoices into line items, then matches them to inventory products with embeddings + fuzzy search', + 'Multi-tenant on Postgres row-level security; 5,437-item USDA reference set for grounding', + 'Claude Haiku for parsing and detection, Sonnet for the harder passes', + ], + href: 'https://sousiq-production.up.railway.app', + hrefKind: 'live', + }, + { + id: '#brkt-0002/05', + name: 'Bracketeer', + stack: 'Next 16 · Prisma 7 · Auth.js · Railway', + year: '2026 →', + impact: 'Live · ran a real World Cup pool', + points: [ + 'Create a pool, invite friends, make bracket picks, watch a leaderboard update from live results', + 'Knockout seeding follows FIFA Annex C — the tiebreak rules are genuinely gnarly', + 'Started as a pool for friends, grew into a multi-tenant platform', + ], + href: 'https://fifawc26.up.railway.app', + hrefKind: 'live', + }, + { + id: '#plcm-0003/05', + name: 'Claude Code Placemat', + stack: 'Static HTML · GitHub Actions · scheduled agent', + year: '2026 →', + impact: 'Maintains itself · MIT', + points: [ + 'A one-page reference for Claude Code: shortcuts, slash commands, flags, hooks, MCP', + 'A scheduled agent re-reads the latest release every day and opens a PR when anything drifts', + 'The interesting part is not the page — it is that nobody updates it by hand', + ], + href: 'https://dommango.github.io/claude-code-placemat/', + hrefKind: 'live', + }, + { + id: '#modm-0004/05', + name: 'modular-mind', + stack: 'Python · 10-stage pipeline', + year: '2026', + impact: '3,500+ patches · 269 module profiles', + points: [ + 'Builds a corpus of VCV Rack modular-synth patches, then generates new ones from learned patterns', + 'Decodes the binary patch format, profiles each module, validates signal flow before emitting', + 'Teaching a model what a patch that actually makes sound looks like', + ], + href: 'https://github.com/dommango/modular-mind', + hrefKind: 'repo', + }, + { + id: '#prial-0005/05', + name: 'PRIAL Pipeline', + stack: 'Python · SEC bulk data', + year: '2026', + impact: '23,000+ firms from raw filings', + points: [ + 'Turns monthly SEC Form ADV bulk filings into a deduped registry of investment-adviser firms', + 'Pulls officers from Schedule A/B and firm sites from Schedule D, then enriches with AUM growth', + 'Mostly an exercise in wrangling government data that was never meant to be joined', + ], + }, +] diff --git a/lib/content/roles.ts b/lib/content/roles.ts deleted file mode 100644 index e56149c..0000000 --- a/lib/content/roles.ts +++ /dev/null @@ -1,58 +0,0 @@ -import fs from 'fs' -import path from 'path' -import matter from 'gray-matter' - -const CAREER_DIR = process.env.NODE_ENV === 'production' - ? path.join(process.cwd(), 'content/career') - : '/home/dom/career' - -export interface Role { - title: string - company: string - start_date: string - end_date: string - location: string - tags?: string[] - skills?: string[] - content: string - slug: string - logo?: string -} - -export function getRoles(): Role[] { - const rolesDir = path.join(CAREER_DIR, 'roles') - - if (!fs.existsSync(rolesDir)) { - console.warn('Roles directory not found at', rolesDir) - return [] - } - - const files = fs.readdirSync(rolesDir) - .filter(f => f.endsWith('.md') && f !== '_index.md') - - const roles = files.map(filename => { - const fullPath = path.join(rolesDir, filename) - const fileContents = fs.readFileSync(fullPath, 'utf8') - const { data, content } = matter(fileContents) - - return { - title: data.title || '', - company: data.company || '', - start_date: data.start_date || '', - end_date: data.end_date || '', - location: data.location || '', - tags: data.tags || [], - skills: data.skills || [], - content, - slug: filename.replace('.md', ''), - logo: data.logo || undefined, - } as Role - }) - - // Sort by start_date descending (most recent first) - return roles.sort((a, b) => { - const aDate = a.end_date === 'present' ? new Date() : new Date(a.end_date) - const bDate = b.end_date === 'present' ? new Date() : new Date(b.end_date) - return bDate.getTime() - aDate.getTime() - }) -} diff --git a/lib/content/skills.ts b/lib/content/skills.ts deleted file mode 100644 index c8f781c..0000000 --- a/lib/content/skills.ts +++ /dev/null @@ -1,92 +0,0 @@ -import fs from 'fs' -import path from 'path' -import matter from 'gray-matter' - -const CAREER_DIR = process.env.NODE_ENV === 'production' - ? path.join(process.cwd(), 'content/career') - : '/home/dom/career' - -export interface SkillItem { - name: string - proficiency: string - evidence?: string -} - -export interface SkillCategory { - category: string - skills: SkillItem[] -} - -export interface Skills { - technical: SkillItem[] - soft: SkillItem[] - domain: SkillItem[] - content: string -} - -export function getSkills(): Skills { - const skillsPath = path.join(CAREER_DIR, 'skills', '_index.md') - - if (!fs.existsSync(skillsPath)) { - console.warn('Skills file not found at', skillsPath) - return getDefaultSkills() - } - - const fileContents = fs.readFileSync(skillsPath, 'utf8') - const { content } = matter(fileContents) - - return { - technical: parseSkillsSection(content, 'Technical Skills'), - soft: parseSkillsSection(content, 'Soft Skills'), - domain: parseSkillsSection(content, 'Domain Knowledge'), - content, - } -} - -function parseSkillsSection(content: string, sectionName: string): SkillItem[] { - const skills: SkillItem[] = [] - - // Find the section - const sectionRegex = new RegExp(`## ${sectionName}\\n\\n(.+?)(?=\\n## |$)`, 's') - const match = content.match(sectionRegex) - - if (!match) return skills - - const sectionContent = match[1] - - // Parse table rows - const tableRegex = /\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|/g - let row - let isHeader = true - - while ((row = tableRegex.exec(sectionContent)) !== null) { - // Skip header row - if (isHeader) { - isHeader = false - continue - } - - const name = row[1].trim() - const proficiency = row[2].trim() - const evidence = row[3].trim() - - if (name && proficiency) { - skills.push({ - name, - proficiency, - evidence, - }) - } - } - - return skills -} - -function getDefaultSkills(): Skills { - return { - technical: [], - soft: [], - domain: [], - content: '', - } -} diff --git a/lib/content/writing.ts b/lib/content/writing.ts new file mode 100644 index 0000000..ab954d6 --- /dev/null +++ b/lib/content/writing.ts @@ -0,0 +1,24 @@ +// Writing — posts from the Substack (Context//Collapse). +// +// Populated at build time by scripts/fetch-substack.js, which overwrites +// SUBSTACK_POSTS below. Typed TS rather than JSON: an empty JSON array +// infers never[] under strict, and this list is empty until Dom publishes. +// +// The Writing section and its nav link both render only when this is +// non-empty, so the section stays invisible rather than shipping a stub. + +export interface WritingPost { + title: string + url: string + /** ISO date string. */ + date: string + subtitle?: string +} + +export const SUBSTACK_URL = 'https://dommangonon.substack.com' + +// GENERATED — do not edit by hand. See scripts/fetch-substack.js. +export const POSTS: WritingPost[] = [] +// END GENERATED + +export const hasPosts = (): boolean => POSTS.length > 0 diff --git a/lib/services/chat.ts b/lib/services/chat.ts index fbe566e..faa2e29 100644 --- a/lib/services/chat.ts +++ b/lib/services/chat.ts @@ -14,52 +14,36 @@ export interface ChatResponse { error?: string } -// Context about Dom that the AI should know -export const DOM_CONTEXT = `You are Dom Mangonon's personal AI assistant on his portfolio website. You help visitors learn about Dom's background, experience, and interests. +// Context about Dom that the AI should know. Keep this in sync with +// lib/content/projects.ts — the projects are the point of the site. +export const DOM_CONTEXT = `You are Dom Mangonon's AI assistant on his personal site. The site is a portfolio: it leads with the things Dom has built. Help visitors understand those projects first, and his career only if they ask. ## About Dom -- Full name: Dominic "Dom" Mangonon -- Current role: Senior Vice President at Citi (Finance/Technology) -- Location: Based in the United States -- Website: dommango.github.io - -## Career Highlights -- Strong background in financial technology and enterprise software -- Experience with data analytics, process automation, and digital transformation -- Has worked across multiple industries with focus on finance sector -- Leadership experience managing teams and cross-functional projects - -## Technical Skills -- Languages: TypeScript, JavaScript, Python, SQL -- Frontend: React, Next.js, Tailwind CSS -- Backend: Node.js, APIs, databases -- Tools: Git, cloud platforms, data visualization - -## Travel & Personal Interests -- Avid traveler who has visited 52 countries across 5 continents -- Notable regions: Extensive travel in Asia, Europe, and the Americas -- Interested in exploring different cultures and cuisines -- Travel philosophy: believes in immersive experiences over tourist attractions - -## Career Goals -- Continuing to grow in technology leadership roles -- Building innovative solutions at the intersection of finance and technology -- Mentoring the next generation of tech professionals -- Contributing to open source and the developer community - -## Website Tech Stack -- Built with Next.js 16 and React 19 -- TypeScript with strict mode -- Tailwind CSS 4 for styling -- Static site export deployed to GitHub Pages -- Content managed via Markdown with gray-matter +- Dominic "Dom" Mangonon, New York metropolitan area +- Seventeen years in financial services; currently SVP, Transformation at Citi, where he works on enterprise AI adoption +- Went all in on AI in 2025 and started shipping software nights and weekends, all built with Claude Code — including this site + +## Projects (the main thing on the site) +- SousIQ — restaurant cost management. Parses vendor invoices into line items and matches them to inventory products using embeddings and fuzzy search. Postgres with pgvector, row-level security for multi-tenancy, Claude Haiku for parsing and Sonnet for harder passes. Live and field-tested in a working bakery. Source is private. +- Bracketeer — tournament bracket pool. Create a pool, invite friends, make picks, watch a live leaderboard. Knockout seeding implements FIFA Annex C. Next.js, Prisma, Auth.js, Railway. Live, and ran a real World Cup pool. Started as a pool for friends. +- Claude Code Placemat — a one-page Claude Code reference (shortcuts, slash commands, flags, hooks, MCP) that maintains itself: a scheduled agent re-reads each release and opens a PR when anything drifts. Static HTML on GitHub Pages, MIT licensed. +- modular-mind — builds a corpus of 3,500+ VCV Rack modular-synth patches and generates new ones from learned patterns. Decodes the binary patch format, profiles modules, validates signal flow. Python. +- PRIAL Pipeline — turns monthly SEC Form ADV bulk filings into a deduped registry of 23,000+ investment-adviser firms, with officers and firm sites. Python. Private. + +## Career, briefly +Operations at BNP Paribas through the 2008 crisis, MBA at CMU Tepper, consulting at PwC/Strategy& and Treliant, wealth-management strategy at Morgan Stanley, and Citi since 2021. The site has a short timeline; LinkedIn has the long version. + +## Writing +Dom writes at Context//Collapse on Substack (dommangonon.substack.com) — notes on building with AI. + +## Also +Has travelled to 52 countries across 5 continents; the site has an interactive map. ## Response Guidelines -- Be friendly, professional, and helpful -- Keep responses concise (2-3 sentences for simple questions) -- If asked about specific details you don't know, suggest checking the relevant page on the website -- Never make up specific numbers, dates, or facts - say "I'd recommend checking with Dom directly" for specifics -- You can encourage visitors to use the contact form to reach out +- Be friendly and direct. Keep it to 2-3 sentences for simple questions. +- The site is a single page — point people to a section (Projects, Writing, Career, Travel, Contact), never to a separate page or URL path. +- Never invent numbers, dates, or facts. If you don't know, say so and suggest they reach out via the Contact section. +- Don't oversell him. The projects speak for themselves; describe them plainly. ` /** diff --git a/lib/services/emailjs.ts b/lib/services/emailjs.ts index 5168d15..6e552a5 100644 --- a/lib/services/emailjs.ts +++ b/lib/services/emailjs.ts @@ -1,10 +1,5 @@ import emailjs from '@emailjs/browser' -export interface ResumeRequestParams { - toName: string - toEmail: string -} - export interface ContactMessageParams { fromName: string fromEmail: string @@ -30,61 +25,11 @@ export function initEmailJS(): void { emailjs.init(publicKey) } -/** - * Send resume request email via EmailJS - */ -export async function sendResumeEmail({ - toName, - toEmail -}: ResumeRequestParams): Promise { - const serviceId = process.env.NEXT_PUBLIC_EMAILJS_SERVICE_ID - const templateId = process.env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID - - if (!serviceId || !templateId) { - return { - success: false, - message: 'Email service not configured' - } - } - - try { - const response = await emailjs.send( - serviceId, - templateId, - { - to_name: toName, - to_email: toEmail, - reply_to: toEmail - } - ) - - if (response.status === 200) { - return { - success: true, - message: 'Resume sent successfully! Check your inbox.' - } - } - - return { - success: false, - message: 'Failed to send email. Please try again.' - } - } catch (error) { - console.error('EmailJS error:', error) - - return { - success: false, - message: error instanceof Error - ? `Email error: ${error.message}` - : 'An unexpected error occurred' - } - } -} - /** * Send a general contact message via EmailJS. * Uses NEXT_PUBLIC_EMAILJS_CONTACT_TEMPLATE_ID when configured, otherwise - * falls back to the resume template id so the message still reaches the inbox. + * falls back to NEXT_PUBLIC_EMAILJS_TEMPLATE_ID so the message still reaches + * the inbox. */ export async function sendContactEmail({ fromName, diff --git a/lib/utils.ts b/lib/utils.ts deleted file mode 100644 index 73ce45d..0000000 --- a/lib/utils.ts +++ /dev/null @@ -1,270 +0,0 @@ -/** - * Utility functions for common operations - */ - -/** - * Merge class names conditionally - */ -export function cn(...classes: (string | undefined | false | null)[]): string { - return classes.filter(Boolean).join(' ') -} - -/** - * Format date to readable string - */ -export function formatDate(date: Date | string, format: string = 'MMM d, yyyy'): string { - const dateObj = typeof date === 'string' ? new Date(date) : date - - // Simple date formatting - for production, use date-fns - const options: Intl.DateTimeFormatOptions = { - year: 'numeric', - month: 'short', - day: 'numeric' - } - - return dateObj.toLocaleDateString('en-US', options) -} - -/** - * Truncate string to specified length - */ -export function truncate(str: string, length: number, suffix: string = '...'): string { - if (str.length <= length) return str - return str.substring(0, length).trim() + suffix -} - -/** - * Slugify string for URLs - */ -export function slugify(str: string): string { - return str - .toLowerCase() - .trim() - .replace(/[^\w\s-]/g, '') - .replace(/\s+/g, '-') - .replace(/-+/g, '-') -} - -/** - * Debounce function - */ -export function debounce any>( - func: T, - wait: number -): (...args: Parameters) => void { - let timeout: NodeJS.Timeout | null = null - - return function executedFunction(...args: Parameters) { - const later = () => { - timeout = null - func(...args) - } - - if (timeout) clearTimeout(timeout) - timeout = setTimeout(later, wait) - } -} - -/** - * Throttle function - */ -export function throttle any>( - func: T, - limit: number -): (...args: Parameters) => void { - let inThrottle: boolean - - return function executedFunction(...args: Parameters) { - if (!inThrottle) { - func(...args) - inThrottle = true - setTimeout(() => (inThrottle = false), limit) - } - } -} - -/** - * Deep clone object - */ -export function deepClone(obj: T): T { - if (obj === null || typeof obj !== 'object') return obj - if (obj instanceof Date) return new Date(obj.getTime()) as any - if (obj instanceof Array) return obj.map(item => deepClone(item)) as any - if (obj instanceof Object) { - const cloned = {} as T - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - cloned[key] = deepClone(obj[key]) - } - } - return cloned - } - return obj -} - -/** - * Check if object is empty - */ -export function isEmpty(obj: Record): boolean { - return Object.keys(obj).length === 0 -} - -/** - * Format number as currency - */ -export function formatCurrency(amount: number, currency: string = 'USD'): string { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency - }).format(amount) -} - -/** - * Format number with commas - */ -export function formatNumber(num: number): string { - return num.toLocaleString('en-US') -} - -/** - * Validate email address - */ -export function isValidEmail(email: string): boolean { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - return emailRegex.test(email) -} - -/** - * Validate URL - */ -export function isValidUrl(url: string): boolean { - try { - new URL(url) - return true - } catch { - return false - } -} - -/** - * Get initials from name - */ -export function getInitials(name: string): string { - return name - .split(' ') - .map(word => word[0]) - .join('') - .toUpperCase() - .slice(0, 2) -} - -/** - * Calculate reading time for text - */ -export function calculateReadingTime(text: string): number { - const wordsPerMinute = 200 - const wordCount = text.trim().split(/\s+/).length - return Math.ceil(wordCount / wordsPerMinute) -} - -/** - * Retry async function with exponential backoff - */ -export async function retry( - fn: () => Promise, - options: { - maxAttempts?: number - delayMs?: number - backoffMultiplier?: number - } = {} -): Promise { - const { maxAttempts = 3, delayMs = 1000, backoffMultiplier = 2 } = options - - let lastError: Error | null = null - - for (let attempt = 1; attempt <= maxAttempts; attempt++) { - try { - return await fn() - } catch (error) { - lastError = error as Error - if (attempt < maxAttempts) { - const delay = delayMs * Math.pow(backoffMultiplier, attempt - 1) - await new Promise(resolve => setTimeout(resolve, delay)) - } - } - } - - throw lastError || new Error('Max retry attempts reached') -} - -/** - * Memoize async function results - */ -export function memoize Promise>(fn: T): T { - const cache = new Map() - - return (async (...args: any[]) => { - const key = JSON.stringify(args) - - if (cache.has(key)) { - return cache.get(key) - } - - const result = await fn(...args) - cache.set(key, result) - - return result - }) as T -} - -/** - * Get random element from array - */ -export function getRandomElement(arr: T[]): T { - return arr[Math.floor(Math.random() * arr.length)] -} - -/** - * Shuffle array - */ -export function shuffle(arr: T[]): T[] { - const shuffled = [...arr] - for (let i = shuffled.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]] - } - return shuffled -} - -/** - * Group array by key - */ -export function groupBy( - arr: T[], - key: (item: T) => K -): Record { - return arr.reduce((groups, item) => { - const groupKey = key(item) - if (!groups[groupKey]) { - groups[groupKey] = [] - } - groups[groupKey].push(item) - return groups - }, {} as Record) -} - -/** - * Unique array by key - */ -export function uniqueBy( - arr: T[], - key: (item: T) => K -): T[] { - const seen = new Set() - return arr.filter(item => { - const k = key(item) - if (seen.has(k)) return false - seen.add(k) - return true - }) -} diff --git a/package-lock.json b/package-lock.json index e2ec51c..9b20f71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "clsx": "^2.1.1", "d3-geo": "^3.1.1", "date-fns": "^4.1.0", - "gray-matter": "^4.0.3", + "fast-xml-parser": "^5.10.0", "next": "16.1.6", "react": "19.2.3", "react-dom": "19.2.3", @@ -26,6 +26,7 @@ "devDependencies": { "@playwright/test": "^1.59.0", "@tailwindcss/postcss": "^4", + "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", @@ -37,7 +38,6 @@ "eslint": "^9", "eslint-config-next": "16.1.6", "jsdom": "^28.0.0", - "puppeteer": "^24.37.5", "tailwindcss": "^4", "typescript": "^5", "vitest": "^4.0.18" @@ -1920,6 +1920,18 @@ "node": ">= 10" } }, + "node_modules/@nodable/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1997,41 +2009,6 @@ "node": ">=18" } }, - "node_modules/@puppeteer/browsers": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", - "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.4.3", - "extract-zip": "^2.0.1", - "progress": "^2.0.3", - "proxy-agent": "^6.5.0", - "semver": "^7.7.4", - "tar-fs": "^3.1.1", - "yargs": "^17.7.2" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@puppeteer/browsers/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.3", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", @@ -2635,6 +2612,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", @@ -2695,6 +2732,36 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", @@ -2764,13 +2831,6 @@ "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true, - "license": "MIT" - }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -2782,6 +2842,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2969,17 +3036,6 @@ "@types/react": "*" } }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.54.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", @@ -3726,6 +3782,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3913,19 +3981,6 @@ "node": ">=12" } }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -3979,21 +4034,6 @@ "node": ">= 0.4" } }, - "node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4001,99 +4041,6 @@ "dev": true, "license": "MIT" }, - "node_modules/bare-events": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "bare-abort-controller": "*" - }, - "peerDependenciesMeta": { - "bare-abort-controller": { - "optional": true - } - } - }, - "node_modules/bare-fs": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.5.tgz", - "integrity": "sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-events": "^2.5.4", - "bare-path": "^3.0.0", - "bare-stream": "^2.6.4", - "bare-url": "^2.2.2", - "fast-fifo": "^1.3.2" - }, - "engines": { - "bare": ">=1.16.0" - }, - "peerDependencies": { - "bare-buffer": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - } - } - }, - "node_modules/bare-os": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.7.0.tgz", - "integrity": "sha512-64Rcwj8qlnTZU8Ps6JJEdSmxBEUGgI7g8l+lMtsJLl4IsfTcHMTfJ188u2iGV6P6YPRZrtv72B2kjn+hp+Yv3g==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "bare": ">=1.14.0" - } - }, - "node_modules/bare-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", - "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-os": "^3.0.1" - } - }, - "node_modules/bare-stream": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", - "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "streamx": "^2.21.0", - "teex": "^1.0.1" - }, - "peerDependencies": { - "bare-buffer": "*", - "bare-events": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - }, - "bare-events": { - "optional": true - } - } - }, - "node_modules/bare-url": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", - "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-path": "^3.0.0" - } - }, "node_modules/baseline-browser-mapping": { "version": "2.9.19", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", @@ -4103,16 +4050,6 @@ "baseline-browser-mapping": "dist/cli.js" } }, - "node_modules/basic-ftp": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", - "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/bidi-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", @@ -4181,16 +4118,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -4298,51 +4225,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chromium-bidi": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", - "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "mitt": "^3.0.1", - "zod": "^3.24.1" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/chromium-bidi/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -4392,33 +4280,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cosmiconfig": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", - "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4608,16 +4469,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/data-urls": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", @@ -4764,19 +4615,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/degenerator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, "license": "MIT", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, "engines": { - "node": ">= 14" + "node": ">=6" } }, "node_modules/detect-libc": { @@ -4789,13 +4635,6 @@ "node": ">=8" } }, - "node_modules/devtools-protocol": { - "version": "0.0.1566079", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1566079.tgz", - "integrity": "sha512-MJfAEA1UfVhSs7fbSQOG4czavUp1ajfg6prlAN0+cmfa2zNjaIbvq8VneP7do1WAQQIvgNJWSMeP6UyI90gIlQ==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -4809,6 +4648,13 @@ "node": ">=0.10.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4838,16 +4684,6 @@ "dev": true, "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.19.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", @@ -4875,30 +4711,10 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, "license": "MIT", "dependencies": { @@ -5144,28 +4960,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, "node_modules/eslint": { "version": "9.39.2", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", @@ -5544,19 +5338,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -5613,16 +5394,6 @@ "node": ">=0.10.0" } }, - "node_modules/events-universal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-events": "^2.7.0" - } - }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -5633,39 +5404,6 @@ "node": ">=12.0.0" } }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5673,13 +5411,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -5724,6 +5455,45 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-xml-builder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", + "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.0.tgz", + "integrity": "sha512-SLhnTEqE5QpJHq/6zl9bsmImEP2adv+y6Wy+cJa7nVTRzQh1OZfCe9k29M5xN74LWnu0xa1zrUrq3KnOKl92Fg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.2.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.1", + "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -5734,16 +5504,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -5900,16 +5660,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -5949,22 +5699,6 @@ "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", @@ -5996,21 +5730,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/get-uri": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", - "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6074,43 +5793,6 @@ "dev": true, "license": "ISC" }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/gray-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -6343,16 +6025,6 @@ "node": ">=12" } }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -6371,13 +6043,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, "node_modules/is-async-function": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", @@ -6518,15 +6183,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6553,16 +6209,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-generator-function": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", @@ -6755,6 +6401,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -6922,13 +6580,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6982,15 +6633,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -7286,13 +6928,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7338,6 +6973,16 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -7422,13 +7067,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true, - "license": "MIT" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -7477,16 +7115,6 @@ "dev": true, "license": "MIT" }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/next": { "version": "16.1.6", "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", @@ -7708,16 +7336,6 @@ ], "license": "MIT" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -7786,40 +7404,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", - "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "dev": true, - "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7833,25 +7417,6 @@ "node": ">=6" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -7875,6 +7440,21 @@ "node": ">=8" } }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7899,13 +7479,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -8034,73 +7607,50 @@ "node": ">= 0.8.0" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/proxy-agent": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", - "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.6", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.1.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.5" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 14" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, "license": "MIT" }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "dev": true, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, "node_modules/punycode": { @@ -8113,47 +7663,6 @@ "node": ">=6" } }, - "node_modules/puppeteer": { - "version": "24.37.5", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.37.5.tgz", - "integrity": "sha512-3PAOIQLceyEmn1Fi76GkGO2EVxztv5OtdlB1m8hMUZL3f8KDHnlvXbvCXv+Ls7KzF1R0KdKBqLuT/Hhrok12hQ==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "2.13.0", - "chromium-bidi": "14.0.0", - "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1566079", - "puppeteer-core": "24.37.5", - "typed-query-selector": "^2.12.0" - }, - "bin": { - "puppeteer": "lib/cjs/puppeteer/node/cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/puppeteer-core": { - "version": "24.37.5", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.37.5.tgz", - "integrity": "sha512-ybL7iE78YPN4T6J+sPLO7r0lSByp/0NN6PvfBEql219cOnttoTFzCWKiBOjstXSqi/OKpwae623DWAsL7cn2MQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "2.13.0", - "chromium-bidi": "14.0.0", - "debug": "^4.4.3", - "devtools-protocol": "0.0.1566079", - "typed-query-selector": "^2.12.0", - "webdriver-bidi-protocol": "0.4.1", - "ws": "^8.19.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -8337,16 +7846,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -8552,19 +8051,6 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -8788,58 +8274,6 @@ "dev": true, "license": "ISC" }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8849,12 +8283,6 @@ "node": ">=0.10.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "license": "BSD-3-Clause" - }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -8890,40 +8318,6 @@ "node": ">= 0.4" } }, - "node_modules/streamx": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", - "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -9037,19 +8431,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -9060,15 +8441,6 @@ "node": ">=4" } }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -9095,6 +8467,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -9172,54 +8559,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/tar-fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", - "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0" - } - }, - "node_modules/tar-stream": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", - "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "bare-fs": "^4.5.5", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/teex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "streamx": "^2.12.5" - } - }, - "node_modules/text-decoder": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -9504,13 +8843,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-query-selector": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz", - "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==", - "dev": true, - "license": "MIT" - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -9877,13 +9209,6 @@ "node": ">=18" } }, - "node_modules/webdriver-bidi-protocol": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", - "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/webidl-conversions": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", @@ -10051,53 +9376,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -10108,6 +9386,21 @@ "node": ">=18" } }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", @@ -10115,16 +9408,6 @@ "dev": true, "license": "MIT" }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -10132,46 +9415,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 902ce71..9b5840e 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ "private": true, "scripts": { "dev": "next dev", - "prebuild": "node scripts/sync-career-content.js && node scripts/generate-resume-pdf.js", "build": "next build", "start": "next start", "lint": "eslint", @@ -20,7 +19,7 @@ "clsx": "^2.1.1", "d3-geo": "^3.1.1", "date-fns": "^4.1.0", - "gray-matter": "^4.0.3", + "fast-xml-parser": "^5.10.0", "next": "16.1.6", "react": "19.2.3", "react-dom": "19.2.3", @@ -31,6 +30,7 @@ "devDependencies": { "@playwright/test": "^1.59.0", "@tailwindcss/postcss": "^4", + "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", @@ -42,7 +42,6 @@ "eslint": "^9", "eslint-config-next": "16.1.6", "jsdom": "^28.0.0", - "puppeteer": "^24.37.5", "tailwindcss": "^4", "typescript": "^5", "vitest": "^4.0.18" diff --git a/playwright.config.ts b/playwright.config.ts index fb61d7a..8e7ef4b 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,5 +1,11 @@ import { defineConfig, devices } from "@playwright/test"; +// reuseExistingServer trusts whatever already answers on this port — if another +// project's dev server is up there, the suite silently tests the wrong site. +// Override with PLAYWRIGHT_PORT to get a private one. +const PORT = process.env.PLAYWRIGHT_PORT ?? "3000"; +const BASE_URL = `http://localhost:${PORT}`; + export default defineConfig({ testDir: "./e2e", fullyParallel: true, @@ -8,7 +14,7 @@ export default defineConfig({ workers: process.env.CI ? 1 : undefined, reporter: "list", use: { - baseURL: "http://localhost:3000", + baseURL: BASE_URL, trace: "on-first-retry", }, projects: [ @@ -18,8 +24,8 @@ export default defineConfig({ }, ], webServer: { - command: "npm run dev", - url: "http://localhost:3000", + command: `npm run dev -- -p ${PORT}`, + url: BASE_URL, reuseExistingServer: !process.env.CI, timeout: 120000, }, diff --git a/public/assets/Dominic_Mangonon_Resume.pdf b/public/assets/Dominic_Mangonon_Resume.pdf deleted file mode 100644 index c453e06..0000000 Binary files a/public/assets/Dominic_Mangonon_Resume.pdf and /dev/null differ diff --git a/public/sitemap.xml b/public/sitemap.xml index 82afeba..3ca37bc 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,27 +1,10 @@ + https://dommango.github.io/ + weekly 1.0 - - https://dommango.github.io/career - 0.8 - - - https://dommango.github.io/skills - 0.7 - - - https://dommango.github.io/education - 0.7 - - - https://dommango.github.io/travel - 0.5 - - - https://dommango.github.io/contact - 0.6 - diff --git a/scripts/fetch-substack.js b/scripts/fetch-substack.js new file mode 100644 index 0000000..1e6d15a --- /dev/null +++ b/scripts/fetch-substack.js @@ -0,0 +1,95 @@ +// Fetches the Substack feed and rewrites the POSTS array in +// lib/content/writing.ts. Runs during the build (see .github/workflows/deploy.yml), +// NOT as a cron that commits: pushes from github-actions[bot] with the default +// GITHUB_TOKEN don't trigger workflows, so commit-then-rebuild silently never +// rebuilds. +// +// A fetch failure is not a build failure — it leaves the committed POSTS alone. + +const fs = require('fs') +const path = require('path') +const { parseSubstackFeed } = require('./lib/parse-substack-feed') + +const FEED_URL = 'https://dommangonon.substack.com/feed' +const TARGET = path.join(__dirname, '../lib/content/writing.ts') +const MAX_POSTS = 6 +const MARKER = '// GENERATED — do not edit by hand. See scripts/fetch-substack.js.' +// Anchored on newlines so it can never match inside a generated post title: +// serialize() runs every field through JSON.stringify, which escapes real +// newlines, so no string literal it emits can contain one. +const END_MARKER = '\n// END GENERATED\n' + +const serialize = (posts) => { + if (posts.length === 0) return 'export const POSTS: WritingPost[] = []' + + const entries = posts + .map((post) => { + const fields = [ + ` title: ${JSON.stringify(post.title)},`, + ` url: ${JSON.stringify(post.url)},`, + ` date: ${JSON.stringify(post.date)},`, + ] + if (post.subtitle) fields.push(` subtitle: ${JSON.stringify(post.subtitle)},`) + return ` {\n${fields.join('\n')}\n },` + }) + .join('\n') + + return `export const POSTS: WritingPost[] = [\n${entries}\n]` +} + +async function main() { + let posts = [] + + try { + const response = await fetch(FEED_URL, { + headers: { 'user-agent': 'dommango.github.io build' }, + signal: AbortSignal.timeout(15000), + }) + + if (!response.ok) { + console.warn(`[substack] feed returned ${response.status}; keeping committed posts`) + return + } + + const parsed = parseSubstackFeed(await response.text()) + + // null means the body wasn't a feed — a 200 carrying an interstitial or a + // login page. Writing [] there would silently empty the Writing section on + // a cron build nobody is watching, so treat it like any other outage. + if (parsed === null) { + console.warn('[substack] response was not an RSS feed; keeping committed posts') + return + } + + posts = parsed.slice(0, MAX_POSTS) + } catch (error) { + console.warn(`[substack] fetch failed (${error.message}); keeping committed posts`) + return + } + + const source = fs.readFileSync(TARGET, 'utf8') + const markerIndex = source.indexOf(MARKER) + const endIndex = source.indexOf(END_MARKER) + + // Bail rather than write a half-file: a bare indexOf(...) === -1 would flow + // into slice(-1), which returns the last character instead of throwing and + // would silently truncate writing.ts. + if (markerIndex === -1 || endIndex === -1 || endIndex < markerIndex) { + console.warn('[substack] generated markers missing or out of order in writing.ts; leaving file alone') + return + } + + const head = source.slice(0, markerIndex + MARKER.length) + const tail = source.slice(endIndex) + + fs.writeFileSync(TARGET, `${head}\n${serialize(posts)}${tail}`) + console.log(`[substack] wrote ${posts.length} post(s) to lib/content/writing.ts`) +} + +// An unreadable/unwritable writing.ts is not a "fetch failure" and should fail +// the build — but surface it in the same voice as the warnings above rather +// than as a bare unhandled-rejection stack trace. +main().catch((error) => { + console.error(`[substack] ${error.stack || error.message}`) + process.exit(1) +}) diff --git a/scripts/generate-resume-pdf.js b/scripts/generate-resume-pdf.js deleted file mode 100644 index adee78c..0000000 --- a/scripts/generate-resume-pdf.js +++ /dev/null @@ -1,81 +0,0 @@ -const puppeteer = require('puppeteer') -const fs = require('fs') -const path = require('path') - -const RESUME_HTML_SOURCE = '/home/dom/personal/career/Mangonon_Dominic_Resume.html' -const OUTPUT_DIR = path.join(__dirname, '../public/assets') -const OUTPUT_FILE = 'Dominic_Mangonon_Resume.pdf' - -async function generateResumePDF() { - // Ensure output directory exists - if (!fs.existsSync(OUTPUT_DIR)) { - fs.mkdirSync(OUTPUT_DIR, { recursive: true }) - } - - // Check if resume HTML exists - if (!fs.existsSync(RESUME_HTML_SOURCE)) { - // Check if PDF already exists (e.g., committed to repo) - const pdfPath = path.join(OUTPUT_DIR, OUTPUT_FILE) - if (fs.existsSync(pdfPath)) { - const stats = fs.statSync(pdfPath) - // If PDF is larger than 100KB, it's likely the real resume (not placeholder) - if (stats.size > 100 * 1024) { - console.log(`✓ Resume PDF already exists: ${OUTPUT_FILE} (${(stats.size / 1024).toFixed(0)} KB)`) - console.log(' Skipping generation - PDF is already in repo') - return - } - } - console.warn(`⚠ Resume HTML not found at: ${RESUME_HTML_SOURCE}`) - console.warn(' No PDF will be generated (resume requests handled via email form)') - return - } - - const htmlContent = fs.readFileSync(RESUME_HTML_SOURCE, 'utf-8') - - // Launch headless browser - let browser - try { - browser = await puppeteer.launch({ - headless: 'new', - args: ['--no-sandbox', '--disable-setuid-sandbox'] - }) - } catch (error) { - console.warn('⚠ Puppeteer Chrome binary not available (expected in dev environment)') - console.warn(' PDF will be generated during deployment build') - console.warn(' To test locally, install Chrome/Chromium or use a Docker container') - // Create a placeholder PDF file so build doesn't fail - const placeholderContent = 'PDF generation skipped - Chrome not available in this environment' - fs.writeFileSync(path.join(OUTPUT_DIR, OUTPUT_FILE), placeholderContent) - console.log(`✓ Placeholder created: ${OUTPUT_FILE} (will be generated in production)`) - return - } - - const page = await browser.newPage() - - // Set content and wait for any fonts/styles to load - await page.setContent(htmlContent, { waitUntil: 'networkidle0' }) - - // Generate PDF with print-optimized settings - const pdfBuffer = await page.pdf({ - path: path.join(OUTPUT_DIR, OUTPUT_FILE), - format: 'Letter', - printBackground: true, - margin: { - top: '0.4in', - bottom: '0.4in', - left: '0.5in', - right: '0.5in' - } - }) - - await browser.close() - - console.log(`✓ Resume PDF generated: ${OUTPUT_FILE}`) - console.log(` Location: ${OUTPUT_DIR}/${OUTPUT_FILE}`) - console.log(` Size: ${(pdfBuffer.length / 1024).toFixed(2)} KB`) -} - -generateResumePDF().catch(error => { - console.error('✗ PDF generation failed:', error) - process.exit(1) -}) diff --git a/scripts/lib/parse-substack-feed.js b/scripts/lib/parse-substack-feed.js new file mode 100644 index 0000000..50d096b --- /dev/null +++ b/scripts/lib/parse-substack-feed.js @@ -0,0 +1,88 @@ +// Pure RSS -> posts transform. Kept separate from the fetch so it can be +// tested without network. Never throws. +// +// Two different "no posts" outcomes, and the caller must tell them apart: +// null -> the body isn't an RSS feed at all (HTML interstitial, login +// redirect, maintenance page — all of which arrive as a 200). +// [] -> a real feed that currently has no publishable posts. +// Only the second may overwrite the committed POSTS; collapsing both to [] +// lets a Cloudflare splash page silently empty the Writing section. + +const { XMLParser } = require('fast-xml-parser') + +// Substack seeds every new publication with a "Coming soon" placeholder. +// It isn't a real post and must not light up the Writing section. +const PLACEHOLDER_TITLES = [/^coming soon\.?$/i] + +const isPlaceholder = (title) => PLACEHOLDER_TITLES.some((re) => re.test(title.trim())) + +const toIsoDate = (pubDate) => { + if (!pubDate) return null + const parsed = new Date(pubDate) + return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString() +} + +const text = (value) => { + if (typeof value === 'string') return value.trim() + if (typeof value === 'number') return String(value) + // fast-xml-parser wraps CDATA/attributed nodes in an object. + if (value && typeof value === 'object' && typeof value['#text'] === 'string') { + return value['#text'].trim() + } + return '' +} + +// Substack puts HTML in . React escapes it rather than executing +// it, so the risk isn't XSS — it's a card rendering "

Hello world

" +// as visible tag soup. Only strip things shaped like a tag, so prose such as +// "a < b" survives. +const stripHtml = (value) => + value + .replace(/<\/?[a-zA-Z][^>]*>/g, ' ') + .replace(/ /g, ' ') + .replace(/\s+/g, ' ') + .trim() + +/** + * @param {string} xml Raw RSS feed body. + * @returns {Array<{title: string, url: string, date: string, subtitle?: string}>|null} + * Real posts newest first, [] for a feed with none, or null if the body + * isn't a feed at all. + */ +function parseSubstackFeed(xml) { + if (typeof xml !== 'string' || xml.trim() === '') return null + + let parsed + try { + parsed = new XMLParser({ ignoreAttributes: false, trimValues: true }).parse(xml) + } catch { + return null + } + + // The channel element is what makes this a feed. An HTML error page parses + // fine but lands under `html`, so it can't be mistaken for an empty feed. + const channel = parsed?.rss?.channel + if (!channel) return null + + const rawItems = channel.item + if (!rawItems) return [] + + const items = Array.isArray(rawItems) ? rawItems : [rawItems] + + return items + .map((item) => { + const title = text(item?.title) + const url = text(item?.link) + const date = toIsoDate(text(item?.pubDate)) + const subtitle = stripHtml(text(item?.description)) + + if (!title || !url || !date) return null + if (isPlaceholder(title)) return null + + return subtitle ? { title, url, date, subtitle } : { title, url, date } + }) + .filter(Boolean) + .sort((a, b) => b.date.localeCompare(a.date)) +} + +module.exports = { parseSubstackFeed } diff --git a/scripts/sync-career-content.js b/scripts/sync-career-content.js deleted file mode 100644 index 3ee8169..0000000 --- a/scripts/sync-career-content.js +++ /dev/null @@ -1,28 +0,0 @@ -const fs = require('fs') -const path = require('path') - -const SOURCE = process.env.CAREER_DIR || '/home/dom/personal/career' -const DEST = path.join(__dirname, '../content/career') - -// Skip if source and dest are the same -const resolvedSource = path.resolve(SOURCE) -const resolvedDest = path.resolve(DEST) - -if (resolvedSource === resolvedDest) { - console.log('✓ Career content already in place (source and dest are the same)') - process.exit(0) -} - -// Copy career directory to content/career for builds -if (fs.existsSync(SOURCE)) { - try { - fs.cpSync(SOURCE, DEST, { recursive: true, force: true }) - console.log('✓ Career content synced from', SOURCE) - } catch (error) { - console.error('✗ Failed to sync career content:', error.message) - process.exit(1) - } -} else { - console.error('✗ Career directory not found at', SOURCE) - process.exit(1) -} diff --git a/vitest.config.ts b/vitest.config.ts index c065f69..243e6a2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -8,6 +8,9 @@ export default defineConfig({ globals: true, environment: 'jsdom', setupFiles: ['./vitest.setup.ts'], + // Without this, vitest's default glob also picks up e2e/*.spec.ts and tries + // to run Playwright specs, which fails on the @playwright/test import. + include: ['__tests__/**/*.test.{ts,tsx}'], coverage: { provider: 'v8', reporter: ['text', 'json', 'html'],