System Architecture & Design Patterns
Resume Constructor is a production-grade, zero-bootstrap resume generator built on React 19, TypeScript (strict), SCSS with BEM, custom webpack 5 and the Bun runtime. It implements the formatting, typography and content standards defined in The Tech Resume Inside Out book by Gergely Orosz.
The codebase is engineered around strict boundaries between presentation, form state, document rendering and accessibility infrastructure.
flowchart TD
App["src/App/App.tsx<br/>(Master Orchestrator)"]
App --> UseAppState["src/hooks/useAppState.ts<br/>(UI, Tabs, Modals, A11y Announcements)"]
App --> UseResumeData["src/hooks/useResumeData/<br/>(Document Model, Immer Mutations)"]
App --> AppLayout["src/components/AppLayout/<br/>(Macro Shell, Sidebar, Appbar, Main)"]
AppLayout --> Sidebar["Sidebar<br/>(Toolbar, Navbar Tabs)"]
AppLayout --> FormView["Main: Form Editor<br/>(Personal, Education, Experience...)"]
Sidebar --> PreviewModal["Preview Modal<br/>(React-PDF Blob + PDF.js Canvas)"]
Architectural Principles
Section titled “Architectural Principles”1. Zero-Bootstrap Philosophy
Section titled “1. Zero-Bootstrap Philosophy”The application avoids heavy UI component libraries (such as Material UI, Tailwind or Chakra). Every UI element — from buttons and modal dialogs to sortable lists and form controls — is built from first principles using semantic HTML, CSS custom properties, BEM methodology and WAI-ARIA authoring practices. This ensures:
- Zero styling abstraction leaks.
- Total control over DOM hierarchy and keyboard focus trapping.
- Minimal bundle footprint and instantaneous startup.
2. Component Colocation
Section titled “2. Component Colocation”Every UI component and page feature is self-contained in its own directory following a strict four-file colocation pattern:
src/components/Button/├── Button.tsx # Component implementation and prop types├── Button.scss # Scoped BEM styles├── Button.test.tsx # Jest + React Testing Library suite└── index.tsx # Clean public barrel export3. Deep Immutability Pattern (ReadonlyExcept)
Section titled “3. Deep Immutability Pattern (ReadonlyExcept)”Component prop interfaces enforce deep immutability across component boundaries using the custom ReadonlyExcept utility type:
import type { MouseEvent, ReactNode, RefCallback, RefObject } from 'react';
import type { ReadonlyExcept } from '@/types/ReadonlyExcept';
export interface ButtonProps { children: ReactNode; disabled?: boolean; onClick?: (event: MouseEvent<HTMLButtonElement>) => void; ref?: RefCallback<HTMLButtonElement> | RefObject<HTMLButtonElement | null>; variant?: 'icon' | 'primary' | 'secondary';}
export function Button({ children, ref, variant = 'primary', ...rest}: ReadonlyExcept<ButtonProps, 'ref'>) { /** * Props are deeply immutable; ref remains accessible as a * first-class React 19 prop. */ return ( <button ref={ref} {...rest}> {children} </button> );}This prevents accidental prop mutation and enforces pure functional component contracts.
State Management Architecture
Section titled “State Management Architecture”State is decoupled into two primary custom hooks coordinated by App.tsx:
1. Document Data Model (useResumeData)
Section titled “1. Document Data Model (useResumeData)”Manages the structured content of the resume (Personal, Education, Experience, Projects, Skills, Certifications, Links).
- Utilises
use-immerto perform safe, deeply nested draft mutations. - Provides atomic action creators (
updateName,addDegree,deleteJob,reorderSkills) ensuring consumer components never manipulate state shape directly. - Encapsulates bulk operations (
clearAll,fillAll,clearSection).
2. UI & Interaction State (useAppState)
Section titled “2. UI & Interaction State (useAppState)”Manages ephemeral shell state and section orchestration:
- Active Section IDs: The ordered collection of enabled resume sections (
activeSectionIds). - Opened Section ID: The currently opened section tab displayed in the form editor (
openedSectionId). - Editor Mode: Section management mode in the navbar (
editorMode) enabling drag-and-drop section reordering and one-click section removal. - Screen Reader Live Announcements: Centralised string (
screenReaderAnnouncement) announcing section additions, deletions and reordering viaaria-live="polite". - Section Operations: Callbacks to add, delete, open and reorder sections.
Modal dialog visibility is managed locally within each respective shell component rather than in useAppState:
Navbarmanages the<AddSections>popup dialog (isAddSectionsPopupShown).Toolbarmanages the full-screen<Preview>modal dialog (isPreviewModalShown).- Toolbar operations such as “Clear All” (
deleteAll) and “Fill All” (fillAll) trigger state resets immediately without modal popups.
Zero Redundant Effects
Section titled “Zero Redundant Effects”In strict compliance with eslint-plugin-react-you-might-not-need-an-effect:
- No
useEffectis used for state synchronisation or data transformation. - Derived values (e.g. can a section be deleted, is the active tab still valid) are computed synchronously during render.
- Focus restoration and side effects are executed inside explicit user event callbacks.
Directory Organisation
Section titled “Directory Organisation”resume-constructor/├── docs/ # Astro Starlight documentation portal├── src/│ ├── App/ # Application shell and font initialisation│ ├── assets/ # Static icons and graphic assets│ ├── components/ # Reusable, domain-agnostic UI primitives│ │ ├── AddSections/ # Section selection modal dialog│ │ ├── AppbarIconButton/ # Responsive appbar action buttons│ │ ├── AppLayout/ # Macro shell (Sidebar, Navbar, Toolbar, Main)│ │ ├── BulletPoints/ # Dynamic sortable accomplishment lists│ │ ├── Button/ # Base button primitive│ │ ├── Popup/ # Modal dialog wrapper with focus trap│ │ └── Preview/ # PDF rendering & canvas rasterization│ ├── hooks/ # Custom React hooks (state, layout, a11y)│ ├── pages/ # Feature form sections (Personal, Education...)│ ├── styles/ # Global SCSS, custom properties, BEM base│ ├── types/ # TypeScript domain interfaces and utility types│ └── utils/ # Pure helper functions (capitalize, neverReached)├── webpack.common.cjs # Shared webpack 5 build configuration├── webpack.dev.cjs # Development server configuration└── webpack.prod.cjs # Production optimization pipeline