Dad Joke Generator (djg)
A minimal React + TypeScript single-page app for generating and sharing dad jokes. Built with Vite using the rolldown bundler and Tailwind CSS 4.1. Google Analytics 4 integration via react-ga4 tracks user feedback on generated jokes. No external joke API is currently integrated — core joke generation is pending implementation.
- GitHub: irishrocker1125/djg
- Port: 3090 (registered in ops-core ports.yaml)
- Status: Early-stage active development (v0.1)
Overview
djg was graduated from lab/Playground experiments into apps/ as a production candidate. The app scaffolding, governance structure, and test infrastructure are in place. The core joke generation feature is the primary outstanding item.
Key characteristics:
- Single-page React app with minimal component structure (App.tsx, Feedback.tsx, main.tsx)
- GA4 event tracking via react-ga4 for user feedback — events follow
{ category, action, label }pattern - Tailwind-first styling — zero custom CSS files beyond Tailwind directives
- TypeScript strict mode with no
anytypes - Local component state only (useState/useEffect) — no Redux or Zustand
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| React | 19.2.0 | UI framework |
| TypeScript | 5.9.3 | Type safety (strict mode) |
| Vite (rolldown-vite) | 7.2.5 | Build tool / dev server (Rust-based bundler) |
| TailwindCSS | 4.1.18 | Utility CSS |
| PostCSS | 8.5.6 | CSS processing |
| react-ga4 | 2.1.0 | Google Analytics 4 |
| Vitest | 4.0.18 | Unit testing |
| ESLint | 9.39.2 (pinned) | Linting |
ESLint is pinned to 9.39.2 because ESLint 10.0.0 is incompatible with the typescript-eslint@8.x ecosystem — an org-wide constraint.
Architecture
src/
├── main.tsx # App entry point, ReactGA initialization, root render
├── App.tsx # Main UI: title, joke display, Feedback form
├── Feedback.tsx # Feedback submission with GA event tracking
└── index.css # Tailwind directives (@tailwind base/components/utilities)
Data flow: User views joke in App.tsx → submits feedback via Feedback.tsx → GA event fires with structured payload → tracked in GA4 dashboard.
Key Decisions
| Decision | Rationale |
|---|---|
| React 19 + TypeScript strict mode | Modern type safety; strict typing prevents common bugs |
| rolldown-vite 7.2 | Rust-based bundler — faster builds vs traditional Vite |
| Tailwind CSS 4.1, no custom CSS | Rapid UI iteration without CSS maintenance overhead |
| No external joke API initially | Defer API complexity until core UI/UX validated |
| Local state only | App is simple enough; no Redux/Zustand overhead warranted |
| Vitest 4.0 with jsdom | Vite-native test runner; test infrastructure built before features |
See also: Vitest setup with react-ga4 mocking — the pattern established in this project for mocking analytics SDKs during tests.
Patterns Established
- GA event tracking via functional component — Feedback.tsx sends structured events; cleanly separates analytics from UI logic. Reusable across any React app with GA4.
- Vitest + react-ga4 mocking — test/setup.ts mocks entire react-ga4 module. Applicable to any React app with analytics SDKs.
- localStorage mock in tests — Vitest setup provides localStorage shim for jsdom. Standard browser API testing pattern.
- TypeScript project references — root tsconfig delegates to tsconfig.app.json + tsconfig.node.json. Vite standard for faster type checking.
- Self-hosted GitHub Actions runners — security.yml targets
[self-hosted, linux, general]. Org-wide pattern from Actions minutes crisis.
Current Status
Phase: Active Development — scaffolding complete, core feature pending.
| Metric | Status | Notes |
|---|---|---|
| CI/CD | Pending review | |
| Dependencies | Current | React + Vite + Tailwind |
| Documentation | Stale | README is default Vite template |
| Test Coverage | N/A | Vitest configured, no tests yet |
Technical Debt
| Item | Priority |
|---|---|
| No actual joke generation functionality | High |
| Replace placeholder GA tracking ID (G-XXXXXXXXXX) | High — must resolve before production |
| Update README.md from Vite boilerplate | Medium |
| Sync USER_TESTING.md with actual features (references removed counter feature) | Medium |
| Add React-specific ESLint rules (react-hooks, react-refresh) | Medium |
| Feedback UI labeled “Report a Bug” but tracks as “Feedback” category | Low |
Lessons Learned
- Test infrastructure before features — full Vitest setup exists despite minimal features; enables TDD and avoids the “add tests later” trap.
- Placeholder tracking IDs ship silently — use env vars for GA tracking IDs (
VITE_GA_TRACKING_ID) to prevent dummy IDs reaching production. - Scaffold READMEs are noise — replace boilerplate READMEs early; default Vite content misleads contributors.
See Also
- AP Ecosystem — djg is an active production app within the Aloysius Productions ecosystem
- DevOps — CI/CD patterns, self-hosted runners, and security scanning used in this project