evgeniiperminov.dev is my personal website, portfolio, and living CV. It collects my professional experience, technology history, current learning, technical writing, and contact details in one place.
The site uses a terminal-inspired interface and is built as a Next.js App Router application.
- Home (
/) — a short introduction and links to the main sections. - Career — three CVs based on the same professional history:
- Hand-crafted CV — the complete version.
- Full-stack Engineer CV — focused on TypeScript, Node.js, backend, and full-stack work.
- AI Engineer CV — focused on applied AI, retrieval, and supporting backend experience.
- Tech Stack — a timeline of technologies and where they were used.
- Learning (
/learning) — a searchable, filterable log of books, courses, articles, and videos that are queued, in progress, completed, or dropped. - Blog (
/blog) — technical articles hosted on this site and links to multi-part series published elsewhere. - Contacts (
/contacts) — direct contact links and a Formspree-backed message form.
The repository also publishes downloadable PDF versions of every CV,
sitemap.xml, robots.txt, and llms.txt/llms-full.txt for machine-readable
discovery.
- Next.js 15 and React 19
- TypeScript
- Tailwind CSS 3
- Puppeteer Core for CV PDF generation
- Google Analytics with consent gating
- Vercel Speed Insights
- Node.js 22.12 or newer
- npm
Google Chrome is only required when generating CV PDFs. The website itself does not require local environment variables.
npm ci
npm run devOpen http://localhost:3000.
| Command | Purpose |
|---|---|
npm run dev |
Start the local development server. |
npm run build |
Create a production build. |
npm run start |
Serve the production build. |
npm run lint |
Run the project’s ESLint checks. |
npm run cv:pdf |
Regenerate all downloadable CV PDFs. |
There is currently no automated test suite; linting and a production build are the main project checks.
.
├── public/
│ ├── files/cv/ # Generated, downloadable CV PDFs
│ ├── files/design/ # Photos and visual assets
│ ├── llms.txt # Concise machine-readable profile
│ └── llms-full.txt # Extended machine-readable profile
├── scripts/
│ └── generate-cv-pdfs.mjs # CV-to-PDF generator
└── src/
├── app/ # Pages, metadata, sitemap, and robots rules
├── components/
│ ├── career/ # CVs and technology timeline
│ ├── learning/ # Learning data, filters, and views
│ ├── blog/ # Blog navigation
│ ├── contacts/ # Contact form and transfer-status UI
│ └── header/ # Multi-level site navigation
└── routing/ # Shared route definitions
Most content is stored as typed data close to the component that renders it:
- Learning log: edit
src/components/learning/learning.data.ts. Medium pages, navigation entries, and sitemap entries are derived from this configuration. Seesrc/components/learning/SPEC.mdfor the data model and editing rules. - Blog: add locally hosted articles under
src/app/blog/, register them insrc/app/blog/articles.ts, and maintain externally hosted series insrc/app/blog/series.ts. - CVs: the complete CV lives under
src/components/career/cv/; the role-focused versions live undersrc/components/career/cv-v2/andsrc/components/career/cv-v3/. - Routes and navigation: shared routes are in
src/routing/routing.tsx, while the visible top-level navigation is configured insrc/components/header/config.ts. - Search and crawler metadata: update
src/app/metadata.ts, page-level metadata,src/app/sitemap.ts, andsrc/app/crawl-policy.tswhen public content changes. Keeppublic/llms.txtandpublic/llms-full.txtcurrent as well.
The web CVs are laid out as fixed-size sheets. The generator opens those same pages in headless Chrome so the downloadable files match the website.
After changing CV content or layout, run:
npm run cv:pdfThe generator reuses a server at http://localhost:3000 when one is available;
otherwise, it starts and stops a development server for the run. It writes:
public/files/cv/CV_Evgenii_Perminov.pdfpublic/files/cv/CV_Evgenii_Perminov_Full_Stack.pdfpublic/files/cv/CV_Evgenii_Perminov_AI_Engineer.pdf
On macOS, the script uses the standard Google Chrome location. Elsewhere, or when Chrome is installed in a different location, provide its executable path:
CHROME_PATH="/path/to/chrome" npm run cv:pdfTo render from another running instance, set CV_PDF_BASE_URL:
CV_PDF_BASE_URL="http://localhost:3001" npm run cv:pdfReview all three generated PDFs before committing them.
The production site is deployed on Vercel. Any platform that supports a
standard Next.js server can use npm run build followed by npm run start.