- Added a comprehensive Table of Contents to AGENTS.md for improved navigation. - Expanded documentation with new backend and frontend guides, detailing architecture, API contracts, and workflows. - Introduced new documents for backend architecture and requirements, outlining system design and API specifications. - Removed outdated Makefile and setup.sh scripts to streamline project setup. - Deleted yarn.lock to eliminate unnecessary dependency management files. - Updated AGENTS.md to reflect changes in documentation structure and links.
19 KiB
Resume Matcher Design System: Swiss International Style
This project follows a strict Swiss International Style (International Typographic Style) aesthetic. It emphasizes cleanliness, readability, objectivity, and strong grid structures. The design is "Brutalist-Lite" — raw, functional, but polished.
1. Core Philosophy
- Form follows function: content is primary.
- Grid Systems: mathematically consistent layouts.
- High Contrast: Sharp borders, distinct colors.
- Typography: Hierarchy is established through size, weight, and font family mixing (Serif + Mono).
2. Color Palette
The palette is minimal, relying on high contrast between ink and paper.
| Color Name | Hex / Tailwind | Usage |
|---|---|---|
| Canvas Cream | #F0F0E8 |
Main application background. Simulates paper. |
| Panel Grey | #E5E5E0 |
Secondary backgrounds, workspaces, unselected areas. |
| Ink Black | #000000 |
Borders, primary text, grid lines, hard shadows. |
| Hyper Blue | #1D4ED8 (blue-700) |
Primary actions, links, active states, accents. |
| Paper White | #FFFFFF |
Input fields, active cards, resume pages. |
| Signal Green | #15803D (green-700) |
Download actions, live status indicators. |
| Alert Orange | #F97316 (orange-500) |
Reset actions, highlights. |
| Alert Red | #DC2626 (red-600) |
Destructive actions, delete confirmations. |
| Steel Grey | #4B5563 (gray-600) |
Secondary labels like Live Preview text. |
| Muted Text | text-gray-500 |
Metadata, placeholders, descriptions. |
3. Typography
We mix three typefaces to create a distinctive technical document feel.
Headings: Serif
Used for major page titles and section headers. Represents authority and tradition.
- Class:
font-serif - Style: Bold, often Uppercase.
- Tracking: Tight (
tracking-tight) for large headers.
Body: Sans-Serif
Used for long-form text, descriptions, and general readability.
- Class:
font-sans - Style: Regular weight, clean.
Metadata / Technical: Monospace
Used for labels, dates, locations, small details, and "system" text.
- Class:
font-mono - Style: Uppercase, tracking wide (
tracking-wider), small size (text-xsortext-sm). - Prefixes: Often stylized with
//(e.g.,// SELECT MODULE).
4. Components & Shapes
Borders & Radius
- Borders: Always solid, 1px Black (
border border-black). - Radius: Zero.
rounded-none. No soft curves.
Shadows (Hard Drops)
Shadows are solid blocks of color/alpha, not diffuse blurs. They mimic paper cutout layers.
Primary Swiss-Style Shadows (solid black):
- Resume/Large Content:
shadow-[8px_8px_0px_0px_#000000]- Used for resume containers in viewer/builder - Builder Preview:
shadow-[6px_6px_0px_0px_#000000]- Slightly smaller for nested contexts - Buttons (Hover):
shadow-[2px_2px_0px_0px_#000000]- Small offset for interactive elements
Secondary Shadows (semi-transparent):
- Page Containers:
shadow-[8px_8px_0px_0px_rgba(0,0,0,0.1)]- Subtle background containers - Cards / Forms:
shadow-[4px_4px_0px_0px_rgba(0,0,0,0.1)]- Light shadow for cards
Important: Resume components should NOT have internal shadows. The parent container provides the Swiss-style shadow. This prevents double-shadow artifacts.
Buttons
Swiss-style buttons use hard shadows, square corners, and clear semantic colors. The "press" effect is achieved by translating the button and removing the shadow on hover.
Base Styling (All Buttons)
rounded-none /* Square corners - Brutalist */
border border-black /* High contrast border */
shadow-[2px_2px_0px_0px_#000000] /* Hard shadow (no blur) */
font-mono uppercase tracking-wide /* Technical typography */
transition-all duration-150 ease-out /* Smooth interactions */
Hover/Active Behavior
hover:translate-y-[1px] hover:translate-x-[1px] hover:shadow-none /* Press effect */
active:translate-y-[2px] active:translate-x-[2px] /* Deep press */
Button Variants
| Variant | Color | Hex | Use Case | Example |
|---|---|---|---|---|
| default | Hyper Blue | #1D4ED8 (blue-700) |
Primary actions | Save, Submit, Create |
| destructive | Alert Red | #DC2626 (red-600) |
Dangerous actions | Delete, Remove |
| success | Signal Green | #15803D (green-700) |
Positive actions | Download, Confirm |
| warning | Alert Orange | #F97316 (orange-500) |
Caution actions | Reset, Clear, Undo |
| outline | Transparent | Black border | Secondary actions | Cancel, Back |
| secondary | Panel Grey | #E5E5E0 |
Tertiary actions | Toolbar buttons |
| ghost | Transparent | No border/shadow | Subtle actions | Icon buttons |
| link | Hyper Blue text | #1D4ED8 |
Inline links | Text navigation |
Button Sizes
| Size | Height | Padding | Use Case |
|---|---|---|---|
| sm | h-8 |
px-4 py-1 |
Compact UI, toolbars |
| default | h-10 |
px-6 py-2 |
Standard buttons |
| lg | h-12 |
px-8 py-3 |
Hero CTAs, emphasis |
| icon | h-10 w-10 |
p-0 |
Icon-only buttons |
Usage Examples
// Primary action (save, submit)
<Button variant="default">Save Changes</Button>
// Destructive action (delete)
<Button variant="destructive">Delete Resume</Button>
// Success action (download)
<Button variant="success">Download PDF</Button>
// Warning action (reset)
<Button variant="warning">Reset Form</Button>
// Secondary action (cancel, back)
<Button variant="outline">Cancel</Button>
// Tertiary action
<Button variant="secondary">More Options</Button>
// Icon button
<Button variant="ghost" size="icon"><Settings /></Button>
// Text link
<Button variant="link">Learn More</Button>
// Disabled state (automatic)
<Button disabled>Processing...</Button>
Disabled State
All buttons automatically receive:
opacity-50- Reduced visibilitypointer-events-none- No interactions- Maintains variant color for context
Focus State
Sharp blue ring (not soft glow):
focus-visible:ring-2 focus-visible:ring-blue-700 focus-visible:ring-offset-2
DO's and DON'Ts
DO:
- Use semantic variants (destructive for delete, success for download)
- Use
outlinefor cancel/back actions paired with primary buttons - Use
ghostfor icon-only buttons in toolbars - Combine with Lucide icons for clarity
DON'T:
- Add
rounded-*classes (always square) - Use custom colors inline (use variants)
- Mix shadow styles (keep consistent
2pxoffset) - Use soft/blurred shadows
Status Indicators
Swiss-style status indicators are small colored squares that provide at-a-glance system state information. They follow the brutalist aesthetic with solid colors and no rounded corners.
Base Styling
w-3 h-3 /* 12x12px square */
/* No rounded corners - sharp edges */
/* Solid background color */
Indicator Variants
| Color | Tailwind Class | Hex | Use Case |
|---|---|---|---|
| Hyper Blue | bg-blue-700 |
#1D4ED8 |
Active sections, editor mode |
| Signal Green | bg-green-700 |
#15803D |
Ready state, healthy status, success |
| Alert Amber | bg-amber-500 |
#F59E0B |
Warning state, setup required |
| Alert Red | bg-red-600 |
#DC2626 |
Error state, offline, failed |
| Steel Grey | bg-gray-500 |
#6B7280 |
Inactive, disabled, neutral |
Usage Patterns
Section Headers - Indicate the current mode/panel:
<div className="flex items-center gap-2 border-b-2 border-black pb-2">
<div className="w-3 h-3 bg-blue-700"></div>
<h2 className="font-mono text-lg font-bold uppercase tracking-wider">
Editor Panel
</h2>
</div>
Status Footers - Show system readiness with loading/offline states:
<div className="flex items-center gap-2">
{isLoading ? (
<>
<Loader2 className="w-3 h-3 animate-spin text-gray-500" />
<span className="font-mono text-xs text-gray-500">CHECKING...</span>
</>
) : status ? (
<>
<div className={`w-3 h-3 ${status === 'ready' ? 'bg-green-700' : 'bg-amber-500'}`}></div>
<span className={`font-mono text-xs font-bold ${status === 'ready' ? 'text-green-700' : 'text-amber-600'}`}>
{status === 'ready' ? 'STATUS: READY' : 'STATUS: SETUP REQUIRED'}
</span>
</>
) : (
<span className="font-mono text-xs text-gray-500">STATUS: OFFLINE</span>
)}
</div>
Health Cards - Pair with icons for detailed status:
<div className="flex items-center gap-2">
{isHealthy ? (
<CheckCircle2 className="w-5 h-5 text-green-600" />
) : (
<XCircle className="w-5 h-5 text-red-500" />
)}
<span className="font-mono text-sm font-bold">
{isHealthy ? 'HEALTHY' : 'OFFLINE'}
</span>
</div>
Last Fetched Indicator - Shows when cached data was refreshed:
<span className="font-mono text-xs text-gray-400 flex items-center gap-1">
<Clock className="w-3 h-3" />
{formatLastFetched()} {/* "Just now", "5m ago", "1h ago" */}
</span>
Text Color Pairing
When indicators accompany text labels, match the text color for consistency:
| Indicator | Text Class | Use |
|---|---|---|
bg-green-700 |
text-green-700 |
Ready, healthy, success |
bg-amber-500 |
text-amber-600 |
Warning, setup required |
bg-red-600 |
text-red-600 |
Error, offline, failed |
bg-blue-700 |
text-blue-700 |
Active, selected, info |
DO's and DON'Ts
DO:
- Use consistent 12x12px (
w-3 h-3) squares - Pair indicator color with matching text color
- Use uppercase monospace font for status labels
- Add
font-boldto status text for emphasis
DON'T:
- Add rounded corners (
rounded-*) - Use gradients or multiple colors
- Make indicators larger than the text they accompany
- Use different sizes for the same type of indicator
Inputs & Forms
- Background: White or Transparent.
- Borders: Black, square (
rounded-none). - Focus: Sharp blue ring or border color change. No soft glow.
- Labels: Uppercase Monospace (
text-xs font-mono uppercase tracking-wider).
Collapsible Panels
Swiss-style collapsible sections used for settings and controls (e.g., Template & Formatting panel in Builder).
Structure
<div className="border border-black bg-white">
{/* Header - Always Visible */}
<button className="w-full flex items-center justify-between p-3 hover:bg-gray-50">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-blue-700"></div>
<span className="font-mono text-xs font-bold uppercase tracking-wider">
Panel Title
</span>
</div>
<ChevronUp /> {/* or ChevronDown when collapsed */}
</button>
{/* Expandable Content */}
<div className="border-t border-black p-4 space-y-6">
{/* Controls */}
</div>
</div>
Template Thumbnails
Visual representation of resume templates. Used in the Template & Formatting panel.
<button className={`flex flex-col items-center p-2 border-2 transition-all ${
isActive
? 'border-blue-700 bg-blue-50 shadow-[2px_2px_0px_0px_#1D4ED8]'
: 'border-black bg-white hover:bg-gray-50 hover:shadow-[1px_1px_0px_0px_#000]'
}`}>
<div className="w-12 h-16 mb-1.5">{/* Thumbnail preview */}</div>
<span className={`font-mono text-[9px] uppercase tracking-wider font-bold ${
isActive ? 'text-blue-700' : 'text-gray-700'
}`}>
Template Name
</span>
</button>
Toggle Selectors
Used for binary choices like Page Size (A4 / US Letter).
<button className={`flex-1 px-3 py-2 border-2 font-mono text-xs transition-all ${
isSelected
? 'border-blue-700 bg-blue-50 text-blue-700 shadow-[2px_2px_0px_0px_#1D4ED8]'
: 'border-black bg-white text-gray-700 hover:bg-gray-50'
}`}>
<div className="font-bold">A4</div>
<div className="text-[9px] opacity-70">210 × 297 mm</div>
</button>
Spacing Level Selectors
Button groups for selecting spacing/sizing levels (1-5).
<div className="flex gap-1">
{[1, 2, 3, 4, 5].map((level) => (
<button className={`w-6 h-6 font-mono text-xs border transition-all ${
isSelected
? 'bg-blue-700 text-white border-blue-700 shadow-[1px_1px_0px_0px_#000]'
: 'bg-white text-gray-700 border-gray-300 hover:border-black'
}`}>
{level}
</button>
))}
</div>
Margin Sliders
Range inputs styled for Swiss aesthetic.
/* Slider track */
h-1 bg-gray-200 rounded-none appearance-none
/* Slider thumb */
[&::-webkit-slider-thumb]:w-3
[&::-webkit-slider-thumb]:h-3
[&::-webkit-slider-thumb]:bg-blue-700
[&::-webkit-slider-thumb]:border-none
5. Layout Patterns
The "Canvas" Container
Pages are often wrapped in a centered container that floats on the #F0F0E8 background.
<div className="w-full max-w-7xl border border-black bg-[#F0F0E8] shadow-[8px_8px_0px_0px_rgba(0,0,0,0.1)]">
{/* Content */}
</div>
Full-Height Editor Layout
Used for pages like the Resume Builder where equal padding on all sides is required.
{/* Outer wrapper - fixed viewport height with equal padding */}
<div className="h-screen w-full bg-[#F0F0E8] flex justify-center items-center p-4 md:p-8">
{/* Main container - fills available space */}
<div className="w-full h-full max-w-[95%] xl:max-w-[1800px] border border-black flex flex-col">
{/* Header - fixed height */}
<div className="border-b border-black p-6 md:p-8">...</div>
{/* Content grid - fills remaining space */}
<div className="grid grid-cols-1 lg:grid-cols-2 bg-black gap-[1px] flex-1 min-h-0">
<div className="bg-[#F0F0E8] p-6 md:p-8 overflow-y-auto">...</div>
<div className="bg-[#E5E5E0] p-6 md:p-8 overflow-y-auto">...</div>
</div>
{/* Footer - fixed height */}
<div className="p-4 border-t border-black">...</div>
</div>
</div>
Key classes:
h-screen+items-center- Centers content vertically within viewporth-fullon inner container - Fills available space after paddingflex-1 min-h-0on content grid - Allows grid to fill remaining height and enable scrollingoverflow-y-autoon panels - Enables independent scrolling
Grid Lines
Backgrounds often feature a graph-paper pattern to reinforce the engineering/technical theme.
style={{
backgroundImage: 'linear-gradient(rgba(29, 78, 216, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(29, 78, 216, 0.1) 1px, transparent 1px)',
backgroundSize: '40px 40px',
}}
Headers with "Tabs"
Section headers often use a "tab" or "status block" aesthetic on the left or right.
- Solid block of color (Blue or Black).
- Monospace text describing the current mode (e.g.,
LIVE PREVIEW,EDITOR PANEL).
6. Paginated Preview System
The Resume Builder features a WYSIWYG paginated preview that shows exactly what the PDF will look like.
Architecture
components/preview/
├── page-container.tsx # Single page wrapper with margin guides
├── paginated-preview.tsx # Main preview with controls
├── use-pagination.ts # Page break calculation hook
└── index.ts # Barrel exports
lib/constants/
└── page-dimensions.ts # Page size constants and utilities
Page Dimensions
| Page Size | Width | Height | Use Case |
|---|---|---|---|
| A4 | 210mm | 297mm | International standard |
| US Letter | 215.9mm | 279.4mm | North American standard |
PageContainer Component
Renders a single page at exact dimensions with optional margin guides.
<PageContainer
pageSize="A4"
margins={{ top: 10, bottom: 10, left: 10, right: 10 }}
pageNumber={1}
totalPages={2}
scale={0.6}
showMarginGuides={false}
contentOffset={0}
contentEnd={800}
>
<Resume ... />
</PageContainer>
Visual Elements:
- White background with 2px black border
- Swiss-style shadow:
shadow-[6px_6px_0px_0px_#000000] - Optional dashed blue margin guides (toggleable)
- Page number indicator:
Page X of Y(bottom-right, monospace)
Preview Controls
Located in a toolbar above the preview area:
| Control | Icon | Function |
|---|---|---|
| Zoom Out | ZoomOut |
Decrease zoom (min 40%) |
| Zoom Level | Text | Shows current zoom % |
| Zoom In | ZoomIn |
Increase zoom (max 150%) |
| Margins Toggle | Eye/EyeOff |
Show/hide margin guides |
| Page Count | FileText |
Shows total pages |
<div className="flex items-center gap-2">
<Button variant="ghost" size="icon"><ZoomOut /></Button>
<span className="font-mono text-xs w-12 text-center">60%</span>
<Button variant="ghost" size="icon"><ZoomIn /></Button>
<div className="w-px h-5 bg-gray-400 mx-2" />
<Button variant={showMargins ? 'secondary' : 'ghost'} size="sm">
<Eye /> Margins
</Button>
</div>
Page Break Indicators
Visual separator between pages in the preview:
<div className="flex items-center gap-2 py-2">
<div className="h-px w-8 bg-gray-400" />
<span className="font-mono text-[10px] text-gray-500 uppercase tracking-wider">
Page Break
</span>
<div className="h-px w-8 bg-gray-400" />
</div>
Pagination Rules
The preview automatically calculates page breaks with these rules:
- Sections CAN span pages - Experience, Projects, etc. flow naturally
- Individual items stay together - Single job entries, project entries don't split
- 50% minimum fill - Pages must be at least half full before moving an item
- Section titles protected - Titles won't be orphaned at page bottom
CSS Classes for Page Breaks:
/* Individual items stay together */
.resume-body .resume-item {
break-inside: avoid;
page-break-inside: avoid;
}
/* Section titles stay with content */
.resume-body .resume-section-title {
break-after: avoid;
page-break-after: avoid;
}
/* Explicit no-break marker */
.resume-body [data-no-break] {
break-inside: avoid;
}
Margin Guides
When enabled, shows the printable content area:
<div
className="absolute pointer-events-none z-10"
style={{
top: marginTopPx,
left: marginLeftPx,
width: contentWidth,
height: contentHeight,
border: '1px dashed rgba(29, 78, 216, 0.5)',
}}
>
{/* Corner markers */}
<div className="absolute -top-1 -left-1 w-2 h-2 border-t border-l border-blue-500" />
...
</div>
Preview Background
The scrollable preview area uses a subtle grid pattern:
<div
className="flex-1 overflow-auto bg-[#D5D5D0] p-6"
style={{
backgroundImage: 'linear-gradient(rgba(0,0,0,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(0,0,0,0.03) 1px, transparent 1px)',
backgroundSize: '20px 20px',
}}
>
Summary: Make it look like a high-end architectural blueprint or a technical manual. Precise, bordered, and grid-aligned.