Personal portfolio and interactive CV built with Angular. The project presents my professional background through dedicated Vietnam and International CV experiences, print-friendly CV pages, downloadable reviewed PDF versions, and an About page.
Portfolio: https://novahoangdev.web.app
- Vietnam and International CV presentations
- Dedicated A4 print views
- Reviewed downloadable PDF CVs
- Responsive portfolio interface
- Dark mode
- SEO and social metadata
- Firebase Hosting deployment
- pnpm-based development workflow
- Angular 22
- TypeScript
- SCSS
- pnpm
- Firebase Hosting
- Vitest
- Node.js version defined in
.nvmrc - pnpm version defined in
package.json
Clone the repository and install dependencies:
git clone <repository-url>
cd portfolio
nvm use
corepack enable
pnpm installStart the local development server:
pnpm startThe application is available at:
http://localhost:3000
# Start the development server
pnpm start
# Run lint checks
pnpm lint
# Run tests
pnpm test
# Create a production build
pnpm buildpnpm build only builds the application. It must not modify approved source assets such as the production CV PDFs under public/documents/.
portfolio/
├── public/
│ └── documents/ # Reviewed production CV PDFs
├── scripts/ # Project utilities and verification scripts
├── src/ # Angular application source
├── AGENTS.md # Instructions for AI coding agents
├── PROFILE.md # Human-readable profile reference
├── angular.json
├── firebase.json
├── package.json
├── pnpm-lock.yaml
└── README.md
Build output is generated under:
dist/portfolio/browser/
The dist/ and node_modules/ directories are generated locally and are not committed.
PROFILE.md provides a human-readable reference for professional profile information used throughout the project.
Application content is maintained in the Angular source. When profile or CV information changes, related website views, print views, and downloadable CV assets should be reviewed together to avoid inconsistencies.
The portfolio provides dedicated print views:
/print/vietnam
/print/international
The PDF files under public/documents/ are reviewed production artifacts used by the website's CV download actions.
They are intentionally not regenerated during pnpm build.
When CV content changes:
- Update the relevant profile/application content.
- Open the corresponding print page.
- Review layout, content, links, spacing, and page breaks.
- Use the browser print dialog to save the approved version as PDF.
- Replace the corresponding PDF under
public/documents/. - Verify the final PDF before committing it.
Automated build, test, lint, and CI tasks must not overwrite files in public/documents/.
The project uses Firebase Hosting for static production deployment.
Firebase serves the Angular production output from:
dist/portfolio/browser
firebase.json contains the Hosting configuration, including the SPA rewrite to index.html.
To deploy manually:
pnpm build
firebase deploy --only hostingA local Firebase login is required for manual deployment.
The intended deployment flow is:
feature branch
↓
pull request
↓
CI checks
↓
manual review
↓
merge to main
↓
production build
↓
Firebase Hosting
Pull requests should pass the repository's lint, test, and build checks before being merged.
Production deployment is triggered from the main branch through GitHub Actions when the deployment workflow is configured.
Firebase credentials must be stored in GitHub Actions secrets and must never be committed to the repository.
This repository uses pnpm.
Use:
pnpm install
pnpm add <package>
pnpm remove <package>Do not generate or commit lockfiles from other package managers:
package-lock.json
yarn.lock
bun.lock
pnpm-lock.yaml is the canonical dependency lockfile and should be committed.
This repository is designed to work with AI coding tools such as Codex, Claude, and GitHub Copilot.
Repository-specific agent instructions are documented in AGENTS.md.
AI tools should respect the existing architecture, package manager, security rules, and approval requirements. In particular, automated tooling must not overwrite approved CV PDFs or perform destructive operations without explicit approval.
This is primarily a personal portfolio, but the source is public for learning, reference, and technical discussion.
For changes:
- Create a dedicated branch.
- Keep commits focused and use Conventional Commits where practical.
- Run the relevant checks locally.
- Open a pull request.
- Review the resulting website before merging.
The source code is available under the MIT License.
Personal CV/profile content, photographs, personal branding, and other personal assets are not licensed for reuse unless explicitly stated otherwise.