My personal website and blog. https://yuricunha.com
  • MDX 54.3%
  • TypeScript 40.3%
  • JavaScript 4.1%
  • Python 1.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Yuri Cunha ecfd3b9fc3
Some checks failed
CodeQL / Analyze (push) Has been cancelled
refactor(blog): rename post slug to english and swap cover
URLs follow english slugs across all locales, and the post now uses the
black 'real eyes, realize, real lies' cover.

Co-authored-by: Ella Mizuki <[email protected]>
2026-10-30 18:36:01 -03:00
.changeset chore: rename workspace scope to isyuricunha 2025-12-13 02:06:11 -03:00
.ella chore(ci): add my own ella agent 2026-06-05 01:00:09 -03:00
.github fix: resolve deep-audit findings across backend, content and infra 2026-10-10 00:26:41 +00:00
.husky/_ chore: unblock lint-staged and update env 2025-12-12 17:53:16 -03:00
.vscode chore: remove prettier vscode extension recommendation 2026-01-08 12:37:45 +00:00
apps refactor(blog): rename post slug to english and swap cover 2026-10-30 18:36:01 -03:00
assets Initialize monorepo with docs and web apps 2025-12-09 15:50:38 -03:00
packages fix(db): add better-auth 1.7.7 columns to users and session 2026-10-12 13:50:48 -03:00
scripts fix: resolve deep-audit findings across backend, content and infra 2026-10-10 00:26:41 +00:00
.cspell.json chore(release): rename tszhong0411 references to isyuricunha 2025-12-13 05:26:31 -03:00
.editorconfig Initialize monorepo with docs and web apps 2025-12-09 15:50:38 -03:00
.env.example fix: resolve deep-audit findings across backend, content and infra 2026-10-10 00:26:41 +00:00
.gitattributes chore: add gitattributes for lf 2025-12-12 21:24:57 -03:00
.gitignore revert: track the verify manifest (documented upstream pattern) 2026-10-04 12:06:04 -03:00
.npmrc Initialize monorepo with docs and web apps 2025-12-09 15:50:38 -03:00
.nvmrc feat(web): add runtime AI settings 2026-08-01 12:24:00 -03:00
.prettierignore Initialize monorepo with docs and web apps 2025-12-09 15:50:38 -03:00
commitlint.config.ts feat(commitlint): add body-max-line-length rule 2026-01-04 05:34:05 +00:00
CREDITS.md Initialize monorepo with docs and web apps 2025-12-09 15:50:38 -03:00
eslint.config.mjs chore(web): add vercel ignore command 2025-12-13 05:36:51 -03:00
knip.config.ts fix: resolve deep-audit findings across backend, content and infra 2026-10-10 00:26:41 +00:00
license.md fix: mdx parsing and formatting 2025-12-23 18:36:40 +00:00
package.json fix(deps): bump all packages to latest stable and clear audit advisories 2026-10-10 13:15:19 -03:00
pnpm-lock.yaml fix(theme): lift the shiki comment colour to AA and bump yutheme 0.2.1 2026-10-14 10:03:54 -03:00
pnpm-workspace.yaml fix(theme): lift the shiki comment colour to AA and bump yutheme 0.2.1 2026-10-14 10:03:54 -03:00
prettier.config.js chore(release): rename tszhong0411 references to isyuricunha 2025-12-13 05:26:31 -03:00
README.md docs: correct git mirrors section, GitHub is the primary source 2026-10-26 18:42:18 +00:00
TODO.md feat: add AI chat cancellation, quick prompts, status endpoint, and provider abstraction 2026-06-13 07:05:58 -03:00
tsconfig.json fix(tsconfig): use relative extends paths 2025-12-16 07:20:45 +00:00
turbo.json fix(build): order build:mdx after dependency builds and clear audit 2026-10-10 13:33:06 -03:00
vercel.json feat: hash analytics IPs and add data-retention cron (#153) 2026-09-05 20:31:27 -03:00
vitest.config.ts test(web): stabilize trpc router tests 2026-05-20 12:38:36 -03:00
vitest.shared.ts test(vitest): inline @isyuricunha/yutheme so Node resolves optional peers 2026-10-09 10:25:02 -03:00
vitest.workspace.ts fix: preserve technical frontmatter during translation 2026-05-26 22:33:19 -03:00

yuricunha.com

Personal website, documentation site and shared package workspace.

License Node pnpm Next.js TypeScript Vercel

Website · Docs

Notice

Please use your own AI/mascot name, model and provider credentials when adapting this project.

Table of contents

Project overview

This is the source code for my personal website, docs app and shared package workspace.

The repository is organized as a monorepo (Turbo + pnpm) so that the main app and internal packages can evolve together.

Features

  • Localized portfolio, blog, projects, snippets, about, music, contact and sitemap pages.
  • Rolling 12-month recap page aggregating Last.fm, WakaTime and site stats.
  • Authenticated admin area covering content, users, security, monitoring, communication and operational workflows.
  • Layered abuse protection: platform-trusted client IP extraction, fail-closed Upstash rate limiting, server-side Turnstile verification and newsletter double opt-in.
  • Hardened Content-Security-Policy in report-only mode, with unsafe-eval removed from the policy.
  • Cursor-inspired warm visual system shared between the website and docs app.
  • MDX content collections for blog posts, project pages, snippets and docs.
  • SEO surfaces for search engines and LLM crawlers: sitemap.xml, robots.txt, rss.xml, locale RSS feeds and llms.txt.
  • Dev-only OpenAI-compatible translation generator for adding new locales locally.

Repository layout

apps/
  web/        main website (Next.js App Router)
  docs/       documentation site (docs.yuricunha.com)
packages/
  db/         database access (Drizzle)
  emails/     email templates (React Email)
  env/        validated environment variables
  eslint-config/  shared ESLint config
  i18n/       internationalization
  kv/         Upstash Redis client, rate limiters and fail-closed wrapper
  mdx-plugins/  rehype/remark MDX plugins and the shared Shiki theme
  prettier-config/  shared Prettier config
  prettier-plugin-package-json/  Prettier plugin for package.json files
  shared/     shared constants and helpers
  tsconfig/   shared TypeScript config
  utils/      shared utilities
scripts/
  translate-site.mjs  OpenAI-compatible locale translation generator
  vercel-ignore.js    Vercel ignore command
  clean-cache.mjs     Turborepo cache cleaner

Reusable UI primitives live in apps/web/src/components; the warm visual system comes from the published @isyuricunha/yutheme package.

Tech stack

Layer Technology
Monorepo Turborepo + pnpm
Web Next.js App Router, React, TypeScript
API tRPC
Database PostgreSQL, Drizzle ORM
Auth better-auth
Rate limiting Upstash Redis sliding windows with a fail-closed wrapper (@isyuricunha/kv)
Email React Email, Resend
i18n next-intl (localized routes under apps/web/src/app/[locale])
Content content-collections + MDX
Styling Tailwind CSS v4 + shared Cursor-inspired UI preset
Testing Vitest (unit), Playwright (e2e)
Hosting Vercel

Versions

Core tooling:

  • Node.js: >=24 (see package.json#engines.node and .nvmrc)
  • pnpm: 12.3.4 (see package.json#packageManager)
  • TypeScript: ^6.0.3
  • Turbo: ^2.11.7
  • Vitest: ^5.0.3
  • ESLint: ^10.12.0
  • Prettier: ^3.9.9

Web apps:

  • Next.js: 16.4.0
  • React: 19.3.0
  • Zod: 4.6.5
  • tRPC: 11.19.0
  • TanStack React Query: ^5.104.1
  • better-auth: 1.7.7
  • TailwindCSS: ^4.3.3

To list all installed versions in the workspace:

pnpm -r list --depth 0

Local development

Prerequisites

  • Node.js (aligned with .nvmrc)
  • pnpm
  • PostgreSQL (or a compatible managed provider)

Setup

  1. Install dependencies

    pnpm install
    
  2. Create your local env file

    cp .env.example .env.local
    
  3. Initialize the database (optional, if you need DB features locally)

    pnpm db:migrate
    
  4. Start the dev servers

    pnpm dev
    

Environment variables

Environment variables are documented in .env.example.

The canonical schema is defined in packages/env/src/index.ts.

For production URLs (used in emails, canonical links, etc.), set:

NEXT_PUBLIC_WEBSITE_URL="https://yuricunha.com"

Localization and translation

Supported locales are defined in packages/i18n/src/config.ts. Message files live in packages/i18n/src/messages.

The local translation generator can create a new locale from an OpenAI-compatible endpoint. It is designed for developer machines and refuses production/Vercel environments.

Required local variables:

OPENAI_COMPATIBLE_BASE_URL="https://provider.example/v1"
OPENAI_COMPATIBLE_API_KEY="..."
OPENAI_COMPATIBLE_MODEL="model-name"

Plan a translation without writing files:

pnpm translate:site -- --target es --dry-run

Use smaller batches for slower or timeout-prone models:

pnpm translate:site -- --target es --batch-size small
pnpm translate:site -- --target es --batch-size medium
pnpm translate:site -- --target es --batch-size large

jp resolves to ja; cn and zh resolve to zh-CN.

SEO and indexing

The site exposes:

/sitemap.xml
/robots.txt
/rss.xml
/llms.txt
/<locale>/rss.xml

Admin, API and password-reset surfaces are marked as non-indexable. Public content pages provide canonical metadata, locale alternates, Open Graph/Twitter data and structured data where applicable.

Scripts

Task Command
Dev servers pnpm dev
Web app only pnpm dev:web
Docs app only pnpm dev:docs
Build everything pnpm build
Build MDX content pnpm build:mdx
Lint pnpm lint
Type check pnpm type-check
Format check / write pnpm format:check / pnpm format:write
Unit tests pnpm test:unit
E2E tests pnpm test:e2e
Unused exports check pnpm check:knip
Full check (lint + types + format + knip) pnpm check:all
Translation generator pnpm translate:site -- --target es --dry-run

Database tasks:

pnpm db:check
pnpm db:generate
pnpm db:migrate
pnpm db:push
pnpm db:seed
pnpm db:studio

Validation

Run this sequence before committing:

pnpm build:mdx
pnpm check
pnpm test:unit

For full verification:

pnpm check:knip
pnpm --filter @isyuricunha/web build
pnpm --filter @isyuricunha/docs build

Maintenance

This repository is actively maintained and dependencies across all apps and packages are updated regularly.

Recommended upgrade workflow:

pnpm -r up --latest
pnpm install
pnpm build:mdx
pnpm check
pnpm test:unit
pnpm check:knip
pnpm --filter @isyuricunha/web build
pnpm --filter @isyuricunha/docs build

If upgrades introduce runtime issues, prefer debugging in development mode (pnpm dev:web) to get non-minified React errors.

Deployment

The project deploys on Vercel as two monorepo-aware projects with Node.js 24.x:

  • website-web: Root Directory apps/web, serving yuricunha.com
  • website-docs: Root Directory apps/docs, serving docs.yuricunha.com

The repository is mirrored across three git sources. GitHub is the primary source, where GitHub Actions CI runs; GitLab is the deploy source connected to Vercel's Git integration:

  • GitHub: github.com/isyuricunha/website (primary source; GitHub Actions CI)
  • GitLab: gitlab.com:isyuricunha/website (deploy source for Vercel)
  • YuGit/Forgejo: self-hosted mirror at ssh.git.yuricunha.com

Push to all three:

git push gitlab main
git push origin main
git push yugit main

Notes:

  • Ensure all required environment variables are set; the canonical schema is packages/env/src/index.ts and examples live in .env.example.
  • Vercel builds do not run database migrations. Apply schema changes manually with pnpm db:migrate after merging; run the production preflight checklist from the Drizzle recipe (apps/docs/src/content/recipes/drizzle.mdx) first.
  • Two Vercel cron jobs are defined in vercel.json: /api/cron/alerts daily at 03:00 UTC and /api/cron/data-retention daily at 03:30 UTC.
  • If a push does not trigger a deploy, run a manual production deploy from the repository root: pnpm exec vercel deploy --prod --yes. Deploying from inside apps/web fails because the project Root Directory is apps/web.
  • Verify the serving revision with endpoint probes and response headers rather than dashboard status alone.

More recipes for operating this workspace live in the docs app: website architecture, abuse protection, Vercel deploy, SEO, translation and validation.

Troubleshooting

Common browser console messages:

  • Failed to load resource: net::ERR_BLOCKED_BY_CLIENT typically indicates a browser extension (ad blocker/privacy tooling) is blocking a request.
  • Minified React errors in production builds are best debugged by reproducing the issue in development mode.

Contributing

This is primarily a personal project.

If you want to contribute:

  • Open an issue describing the change.
  • Keep changes small and focused.
  • Prefer tests for non-trivial logic.

License

Distributed under the GNU AGPL-3.0. See license.md for the full text.

Credits

This project began as an adaptation inspired by Nelson Lai's website and has evolved significantly since then.

Thank you to Nelson for the original inspiration.

Contact