Professional portfolio website showcasing QA testing expertise, technical projects, and professional experience. Built with modern web technologies and deployed on Cloudflare's edge network.
Interactive portfolio • Real-time GitHub integration • Edge-powered analytics
🚀 Live Demo • 📖 Documentation • 🐛 Report Issues
|
|
|
|
- Interactive hero section with skills taxonomy
- Experience timeline with domain expertise (Naval Shipping, Payments)
- Project gallery with live demos and GitHub integration
- Professional avatar and branding
- Bento Grid Layout: Widget-based dashboard design
- Location Map: Interactive Leaflet map integration
- GitHub Commits: Real-time activity feed from GitHub API
- Click Counter: Visitor engagement tracking with D1 database
- Statistics Widget: Portfolio analytics and metrics
- Contact Widget: Direct communication channels
- Edge runtime deployment on Cloudflare Workers
- D1 SQLite database for analytics and rate limiting
- Open Graph metadata for social media previews
- Custom branding (favicon, icons, OG images)
- Responsive design across all devices
- Dark mode optimized with Catppuccin theme
Frontend Stack:
- Next.js 15.5 (App Router), React 18, TypeScript 5.6
- Tailwind CSS 3.4 with Catppuccin theming
- shadcn/ui components, Radix UI primitives
- Framer Motion animations, Lucide icons
- Leaflet maps, JetBrains Mono font
Backend & Infrastructure:
- Cloudflare Workers (Edge runtime)
- D1 Database (SQLite at the edge)
- OpenNext (@opennextjs/cloudflare)
- Analytics Engine binding
- GitHub API integration
Build & Deploy:
- Bun package manager
- Wrangler 4 CLI
- Cloudflare Pages deployment pipeline
┌─────────────┐
│ Browser │ React 18 + Next.js 15
│ (Client) │ Tailwind + Framer Motion
└──────┬──────┘
│ HTTPS
▼
┌─────────────────────────────────────────────────────────┐
│ Cloudflare Edge (300+ Global PoPs) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Cloudflare Workers - Edge Runtime │ │
│ │ │ │
│ │ ┌──────────────┐ ┌───────────────┐ │ │
│ │ │ Next.js │──────────│ API Routes │ │ │
│ │ │ Routes │ │ │ │ │
│ │ │ │ │ /counter │ │ │
│ │ │ /, /about │ │ /github/* │ │ │
│ │ │ /projects │ └───────┬───────┘ │ │
│ │ └──────┬───────┘ │ │ │
│ │ │ │ │ │
│ │ └──────────┬───────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────┼──────────┐ │ │
│ │ │ │ │ │ │
│ └─────────┼──────────┼──────────┼───────────────────┘ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ D1 │ │Analytics│ │ Secrets │ │
│ │ Database │ │ Engine │ │ (Env) │ │
│ │ (SQLite) │ │ │ │ │ │
│ └──────────┘ └─────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
│ Fetch
▼
┌──────────────────────┐
│ External Services │
│ • GitHub API │
│ • Leaflet Tiles │
└──────────────────────┘
User Click → BentoGrid Component → /api/counter/increment
↓
Rate Limit Check (D1)
↓
Update Counter (D1)
↓
Log Visitor (D1)
↓
Return New Count → Update UI
Page Load → RecentCommitsWidget → /api/github/commits
↓
GitHub API Request
(with GITHUB_TOKEN)
↓
Parse & Format Data
↓
Cache at Edge (optional)
↓
Return to Component → Render
About Page Load → LocationMapWidget → Leaflet.js Initialization
↓
Fetch Tile Layers (CDN)
↓
Render Interactive Map
↓
Apply Custom Markers
Page Request → app/layout.tsx → Generate Metadata
↓
┌───────────┼───────────┐
▼ ▼ ▼
og:image favicon.ico og:title
│ │ │
└────────────┴────────────┘
▼
Serve from /app static
▼
Social Media Crawlers
User Visit → Middleware → Extract IP/User-Agent
↓
Rate Limit Check (D1)
↓
Log to visitors table
↓
Optional: Analytics Engine binding
↓
Continue to requested page
app/
├── layout.tsx (Root)
│ ├── Navigation (Global)
│ ├── [Page Content]
│ └── Footer (Global)
│
├── page.tsx (Home)
│ ├── PortfolioHero
│ │ └── Skills Display (from lib/data/skills.ts)
│ ├── Experience
│ │ └── Timeline Components
│ ├── PortfolioProjects
│ │ └── Project Cards
│ └── BentoGrid
│ ├── ContactWidget
│ ├── LocationMapWidget (Leaflet)
│ ├── ClickCounterWidget (D1)
│ ├── StatsWidget
│ ├── TestimonialsWidget
│ └── RecentCommitsWidget (GitHub API)
│
├── about/page.tsx
│ └── About
│ ├── Avatar Image (/public/avatar.png)
│ └── Social Links
│
└── projects/page.tsx
└── Projects Showcase
Allowed:
- Fetch API, Web Streams, Web Crypto
- D1 Database bindings
- Analytics Engine bindings
- Environment variables via
process.env
Not Allowed:
- Node.js APIs (fs, path, crypto)
- Server-side only packages
- Long-running processes (10s timeout)
Rate Limiting:
- IP-based tracking in D1
rate_limitstable - Configurable windows (e.g., 60 requests/minute)
- Automatic cleanup of expired entries
Caching Strategy:
- Static assets: CDN cache (immutable)
- API routes: Conditional based on staleness
- Database queries: Edge-optimized D1
Authentication:
- Not required for public portfolio
- Future: Admin panel could use Better Auth pattern
counters: Click tracking (id, count, last_updated)
rate_limits: API throttling (ip, endpoint, count, window_start)
visitors: Analytics (id, ip, user_agent, visited_at)
- Bun 1.0+
- Cloudflare account
- GitHub personal access token (optional, for commits widget)
git clone https://github.com/ionutcnu/Portfolio.git
cd Portfolio
bun installnpx wrangler d1 create portfolio-counter
# Update wrangler.toml with database ID
npx wrangler d1 execute portfolio-counter --file=schema.sqlCreate .env.local:
GITHUB_TOKEN=your_github_token
GITHUB_USERNAME=ionutcnubun run dev # Start dev server (localhost:3000)
bun run build # Production build
bun run deploy # Deploy to Cloudflare
bun run preview # Local Cloudflare previewPortfolio/
├── app/ # Next.js App Router
│ ├── about/ # About page
│ ├── projects/ # Projects showcase
│ ├── api/ # API routes (Edge runtime)
│ ├── layout.tsx # Root layout + metadata
│ ├── page.tsx # Home page
│ ├── icon.png # Site favicon
│ ├── favicon.ico # Legacy browser icon
│ └── opengraph-image.png # Social preview
├── components/
│ ├── bento/ # Widget components
│ ├── sections/ # Page sections
│ ├── layout/ # Navigation, Footer
│ └── ui/ # shadcn/ui components
├── lib/
│ ├── data/ # Static content
│ └── utils/ # Helper functions
├── public/ # Static assets
│ └── avatar.png # Professional avatar
├── types/ # TypeScript definitions
├── wrangler.toml # Cloudflare config
└── open-next.config.ts # OpenNext adapter
| Endpoint | Method | Purpose |
|---|---|---|
/api/counter/increment |
POST | Increment click counter |
/api/github/commits |
GET | Fetch recent commits |
/api/github/stats |
GET | GitHub profile stats |
Cloudflare Bindings:
DB: D1 database (portfolio-counter)ANALYTICS: Analytics Engine
Secrets (Wrangler):
wrangler secret put GITHUB_TOKENMetadata:
- Domain:
lonut.dev - OG Image: 1920x1080px
- Favicon: Multiple sizes (16-512px)
- Edge Response: <50ms global latency
- Bundle Size: Optimized chunks
- Lighthouse Score: 95+ performance
- Database: SQLite at edge (D1)
- CDN: 300+ global locations
API Testing: Postman, REST APIs Databases: PostgreSQL, SQL scripting Cloud & DevOps: AWS S3, Azure, Kubernetes, Kibana Messaging: Apache Kafka Automation: Cypress, Selenium AI & Integration: Prompt Engineering, Claude API, MCP Servers Other: JSON, Microservices, Git
Cloudflare Pages (Recommended):
bun run build
bun run deployManual Wrangler:
npx wrangler pages deploy .open-next/worker --project-name=portfolioGitHub Actions:
Automated deployment via .github/workflows/deploy.yml
Contributions welcome. Follow standard fork-branch-PR workflow. Ensure TypeScript checks pass and test on Cloudflare Workers before submitting.
MIT License - Free to use as template
Built with Next.js, Tailwind CSS, and Cloudflare Workers