- MDX 54.3%
- TypeScript 40.3%
- JavaScript 4.1%
- Python 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
CodeQL / Analyze (push) Has been cancelled
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]> |
||
| .changeset | ||
| .ella | ||
| .github | ||
| .husky/_ | ||
| .vscode | ||
| apps | ||
| assets | ||
| packages | ||
| scripts | ||
| .cspell.json | ||
| .editorconfig | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .npmrc | ||
| .nvmrc | ||
| .prettierignore | ||
| commitlint.config.ts | ||
| CREDITS.md | ||
| eslint.config.mjs | ||
| knip.config.ts | ||
| license.md | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| prettier.config.js | ||
| README.md | ||
| TODO.md | ||
| tsconfig.json | ||
| turbo.json | ||
| vercel.json | ||
| vitest.config.ts | ||
| vitest.shared.ts | ||
| vitest.workspace.ts | ||
Notice
Please use your own AI/mascot name, model and provider credentials when adapting this project.
Table of contents
- Project overview
- Features
- Repository layout
- Tech stack
- Local development
- Environment variables
- Localization and translation
- SEO and indexing
- Scripts
- Validation
- Maintenance
- Deployment
- Troubleshooting
- Contributing
- License
- Credits
- Contact
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-evalremoved 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 andllms.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) |
| 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(seepackage.json#engines.nodeand.nvmrc) - pnpm:
12.3.4(seepackage.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
-
Install dependencies
pnpm install -
Create your local env file
cp .env.example .env.local -
Initialize the database (optional, if you need DB features locally)
pnpm db:migrate -
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 Directoryapps/web, servingyuricunha.comwebsite-docs: Root Directoryapps/docs, servingdocs.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.tsand examples live in.env.example. - Vercel builds do not run database migrations. Apply schema changes manually with
pnpm db:migrateafter 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/alertsdaily at 03:00 UTC and/api/cron/data-retentiondaily 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 insideapps/webfails because the project Root Directory isapps/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_CLIENTtypically 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
- Email: [email protected]
- GitHub: https://github.com/isyuricunha
- Website: https://yuricunha.com