An Nx monorepo powering dalenguyen.me — built with AnalogJS (Angular 20) and NestJS.
- Main site — https://dalenguyen.me (blog-app on Vercel): home, blog, resume, learn, bucket list
- Blog SSR — the same app runs as a Nitro node-server on Cloud Run for on-demand SSR + API routes
- Nx 21 workspace (with Nx Cloud) managed with pnpm 10
- AnalogJS 2 (Vite + Vitest) — the main site/blog, Angular 20 + Angular Material + Tailwind CSS
- NestJS 10 for the API
- Blog content authored as static markdown in
apps/blog-app/src/content/ - Node
>=20
apps/
blog-app AnalogJS — the main site (dalenguyen.me): home, blog (static md),
resume, learn, bucket list. SSG on Vercel + SSR/API on Cloud Run.
api-nest NestJS API (deployed as a Google Cloud Function)
saas Angular SaaS app
libs/
portfolio home / shell / resume / shared UI libraries (consumed by blog-app)
angular Shared Angular UI + utilities
api-nest NestJS domains / shell / infrastructure / usecases
openai OpenAI helper library
saas-libs Shared SaaS libraries
shared Framework-agnostic shared code (e.g. shared/ui)
See docs/project-structure.md for the library boundary conventions.
pnpm installnpm start serves the default project (blog-app).
nx serve blog-app # http://localhost:3000 (AnalogJS — the main site)
nx serve api-nest
nx serve saasnx build <app> # e.g. nx build blog-appnx test <project> # unit tests (Jest / Vitest)
nx lint <project>
nx e2e <app>-e2e # Cypress / Playwright
nx storybook <project> # StorybookUse nx affected -t build|test|lint to run only what changed against origin/dev.
The dev branch is the production branch. Pushing to dev deploys to Vercel
via its Git integration (static SSG — every route prerendered), serving dalenguyen.me.
Deploy the blog's SSR node-server to Cloud Run manually:
nx run blog-app:deploy # build-server → gcloud builds submit → gcloud run deploySee apps/blog-app/CLAUDE.md for the dual-deploy (Vercel SSG + Cloud Run SSR) details.
Posts are markdown files in apps/blog-app/src/content/. Frontmatter fields: title,
slug, date, draft (optional). A route is prerendered only if its path is listed in
prerender.routes in apps/blog-app/vite.config.ts — posts are added there automatically
from the content directory.
nx generate @nx/angular:library my-lib --buildable --publishable
nx generate @nx/nest:app my-api
# NestJS building blocks
nx g @nx/nest:module path/module-name
nx g @nx/nest:service path/service-name
# Publishable npm package
nx generate @nx/node:library name --importPath @dalenguyen/name --publishableContributions are welcome. Please read the contribution guideline.