Files
Reactive-Resume/apps/server/package.json
T
Amruth Pillai b404dbd42a Add application tracker (#3220)
* feat(applications): job application tracker with AI copilot

Add an Applications module at /dashboard/applications: pipeline board
(dnd-kit), table view with bulk actions, Insights (fit tiles, funnel,
sources, shareable funnel-flow SVG), campaigns, tags, CSV import, and
Add/Edit/Detail slide-overs. Each application links a live Reactive
Resume.

AI "Application Copilot" (applications.ai.*): job-posting autofill,
resume↔job match score (fit ring), resume tailoring, and cover-letter /
follow-up drafting — via the user's configured provider.

Board cards + table rows get context menus (edit / move / archive /
delete). Charts are CSS/SVG (no new chart dep); adds a UI Checkbox.

Also includes local TanStack devtools setup and toolchain bumps.

Claude-Session: https://claude.ai/code/session_01TEeRHnEayw2MFCShFRyL5f

* feat(applications): close follow-up gaps + squash migrations

Finish the deferred/open items on the applications tracker:

- Cover-letter upload re-enabled. Fix the storage blocker by deriving the
  key extension from content type (buildFileKey/EXTENSION_BY_CONTENT_TYPE)
  instead of hardcoding .jpeg, so PDFs serve correctly and non-JPEG image
  avatars keep working under FLAG_DISABLE_IMAGE_PROCESSING. Add
  coverLetterUrl/coverLetterName columns + Documents-section upload/remove.
- Contacts editor in the detail sheet (add/edit/remove, keyed per app).
- Board caps rendered cards per column (COLUMN_PAGE_SIZE=50 + "Show more").
- Extract new Lingui messages across locales.
- Guard coverLetterUrl to http(s)/relative at the API boundary.

Squash the five branch-only application-table migrations (create -> +tags
-> +cover-letter -> drop -> re-add) into a single clean CREATE TABLE via
drizzle-kit generate.

Claude-Session: https://claude.ai/code/session_01TEeRHnEayw2MFCShFRyL5f

* chore: update dependencies

* fix(web): address React Doctor findings — compiler, purity, query, component structure

prefer-module-scope-pure-function: hoist buildSubtitle, getDecimalPlaces,
handleLocaleChange, onLocaleChange, stop, listContent/groupedListContent to
module scope so they aren't rebuilt on every render.

react-compiler-todo (??=): rewrite draft.metadata.styleRules ??= [] to the
non-assignment form to unblock auto-memoization.

set-state-in-effect: derive updatedAtLabel at render time instead of syncing
it through useState + useEffect.

query-destructure-result: destructure useQuery results at call site in
resume-analysis and resume-thumbnail to follow TanStack Query v5 convention.

only-export-components: extract non-component exports to sibling .ts files so
Fast Refresh can preserve component state:
  - getNextWeights → typography/get-next-weights.ts
  - detectJsonImportType + ImportType → dialogs/resume/import.utils.ts
  - getLocaleOptions → features/locale/locale-options.tsx
  - preview helpers + DEFAULT_PDF_PAGE_SIZE → preview.shared.utils.ts
  - resolveHighlightToolbarState + defaultHighlightColor → rich-input.utils.ts
  - computeDelta + getSparklinePoints → statistics.utils.ts

no-multi-comp: split multi-component files into focused companions:
  - ResumePane + ToolbarButton → routes/agent/-components/resume-pane.tsx
  - DesktopBuilderShell → builder/$resumeId/-components/desktop-builder-shell.tsx
  - MobileBuilderShell + helpers → builder/$resumeId/-components/mobile-builder-shell.tsx
  - setBuilderLayout/getBuilderLayout moved to -store/sidebar.ts

fix(tests): add Resume type import to section-builder mocks and cast partial
mock data as unknown as Resume to satisfy stricter type checking; fix
noExplicitAny Biome errors in the same mocks.

* feat(applications): improve performance

* chore: fix knip issues

* perf(builder): halve per-keystroke render cost

Section-form fields called `form.handleSubmit()` on every keystroke, which
re-validated the whole form and toggled submit state — firing the render
cascade twice per character (~6809 renders/keystroke, FPS dropping to 9).

Persist via a form-level `listeners.onChange` instead and drop the per-field
`handleSubmit()` (basics, custom-fields, design). Narrow header/dock resume
subscriptions to metadata slices so they no longer re-render on content edits.

Cuts renders 6809 -> 3403 per keystroke (50%), 0 frame drops. Save, preview,
and design controls verified working; 449/449 web tests pass.

* perf(home): eliminate hero CLS from unreserved video box

The hero <section> is `flex items-center` (shrink-to-fit), so the video
wrapper's width depended on the video's intrinsic size, which only resolves
after the media loads. aspect-ratio couldn't reserve height without a definite
width, so the video grew from ~190px to ~563px after first paint and shoved the
centered hero text down ~373px (CLS ~0.095).

Give the wrapper a definite width (w-full + mx-auto on the CometCard) and set an
explicit aspect ratio + width/height on the video so its box is reserved before
load. CLS 0.095 -> 0; hero stays visually centered at max-w-4xl.

* docs: add application tracker guides

* chore(db): squash application migrations

* fix(email): import React in auth template for server-side rendering compatibility

* chore(release): v5.2.1

* Refactor resume rendering and builder workflows

* fix: address application tracker review findings
2026-07-05 23:44:04 +02:00

87 lines
2.8 KiB
JSON

{
"name": "server",
"version": "0.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsdown",
"start": "node dist/index.mjs",
"typecheck": "tsgo --noEmit",
"test": "vitest run --passWithNoTests",
"test:coverage": "vitest run --coverage --passWithNoTests",
"test:ci": "vitest run --coverage --reporter=default --reporter=github-actions --reporter=json --reporter=junit --outputFile.json=reports/vitest-results.json --outputFile.junit=reports/vitest-junit.xml --passWithNoTests",
"test:agent": "vitest run --reporter=agent --reporter=json --outputFile.json=reports/vitest-results.json --passWithNoTests"
},
"imports": {
"#react-pdf-renderer": "@react-pdf/renderer"
},
"dependencies": {
"@ai-sdk/anthropic": "^4.0.8",
"@ai-sdk/google": "^4.0.8",
"@ai-sdk/openai": "^4.0.7",
"@ai-sdk/openai-compatible": "^3.0.5",
"@aws-sdk/client-s3": "^3.1079.0",
"@better-auth/api-key": "^1.6.23",
"@better-auth/drizzle-adapter": "^1.6.23",
"@better-auth/infra": "^0.3.4",
"@better-auth/oauth-provider": "^1.6.23",
"@better-auth/passkey": "^1.6.23",
"@hono/node-server": "^2.0.8",
"@modelcontextprotocol/sdk": "^1.29.0",
"@orpc/client": "^1.14.6",
"@orpc/experimental-ratelimit": "^1.14.6",
"@orpc/json-schema": "^1.14.6",
"@orpc/openapi": "^1.14.6",
"@orpc/server": "^1.14.6",
"@orpc/zod": "^1.14.6",
"@react-pdf/renderer": "^4.5.1",
"@reactive-resume/api": "workspace:*",
"@reactive-resume/auth": "workspace:*",
"@reactive-resume/db": "workspace:*",
"@reactive-resume/env": "workspace:*",
"@reactive-resume/mcp": "workspace:*",
"@reactive-resume/schema": "workspace:*",
"@reactive-resume/utils": "workspace:*",
"@sindresorhus/slugify": "^3.0.0",
"@t3-oss/env-core": "^0.13.11",
"@uiw/color-convert": "^2.10.3",
"ai": "^7.0.15",
"bcrypt": "^6.0.0",
"better-auth": "1.6.23",
"cjk-regex": "^3.4.0",
"deepmerge-ts": "^7.1.5",
"drizzle-orm": "1.0.0-rc.4",
"drizzle-zod": "1.0.0-beta.14-a36c63d",
"es-toolkit": "^1.49.0",
"fast-json-patch": "^3.1.1",
"hono": "^4.12.27",
"jsonrepair": "^3.15.0",
"node-html-parser": "^8.0.4",
"nodemailer": "^9.0.3",
"ollama-ai-provider-v2": "^3.6.0",
"pg": "^8.22.0",
"phosphor-icons-react-pdf": "^0.1.3",
"react": "^19.2.7",
"react-email": "^6.6.6",
"react-pdf-html": "^2.1.5",
"resumable-stream": "^2.2.12",
"sharp": "^0.35.3",
"ts-pattern": "^5.9.0",
"unique-names-generator": "^4.7.1",
"uuid": "^14.0.1",
"zod": "^4.4.3"
},
"devDependencies": {
"@reactive-resume/config": "workspace:*",
"@types/node": "^26.1.0",
"@types/pg": "^8.20.0",
"@types/react": "^19.2.17",
"@typescript/native-preview": "7.0.0-dev.20260705.1",
"tsdown": "^0.22.3",
"tsx": "^4.23.0",
"typescript": "^6.0.3",
"vitest": "^4.1.9"
}
}