Version: 0.1.0 (MVP) | Status: Active Development | License: Private
A full-stack TypeScript/Next.js web application that serves as both an interactive personal portfolio and an educational design pattern playground. The system demonstrates all 23 Gang of Four (GoF) design patterns implemented within a production-grade architecture, targeting CS students, recruiters, and software engineering educators.
Welcome! This repository powers the live portfolio and interactive pattern playground.
- Live Demo: [Will be added soon]
- Core Features:
- Interactive portfolio showcasing Projects, Blog, Resume, and Podcasts.
- Command palette (Ctrl+K) for navigation and theme switching.
- 23 GoF Design Patterns implemented and observable in the UI.
- Multi-theme support (Dark/Light, Modern/Minimal/Future/Academic).
If you want to run this project locally, experiment with the design patterns, or contribute to the codebase, follow these quick steps:
# 1. Clone the repository & install dependencies
git clone <repository-url> && cd personal-profile-prototype
bun install
# 2. Configure environment & start Database
cp .env.example .env
bun run db:up
# 3. Apply migrations & seed data
bunx prisma migrate dev
bun run prisma:seed
# 4. Start development server
bun run devbun run dev # Start Webpack dev server
bun run dev:turbo # Start Turbopack dev server
bun run build # Type-check + Next.js production build
bun run start # Start production server
bun run lint # ESLint
bun run db:up # docker compose up -d (PostgreSQL)
bun run db:down # docker compose down
bun run db:logs # Follow PostgreSQL container logs
bun run prisma:generate # Generate Prisma client
bun run prisma:migrate:dev # Apply migrations (dev)
bun run prisma:seed # Seed database via Bun
bun run integration:auth-db # Auth + database integration test
bun run integration:http-crud # HTTP CRUD integration test
bun run integration:http-admin-users # Admin users integration testFor full deployment instructions, see the SDLC Documentation below.
This project was built following a strict SDLC process to serve as an educational reference. Below is the full engineering documentation.
Traditional developer portfolios are static, single-purpose pages that fail to demonstrate depth of software engineering knowledge. Simultaneously, CS curricula often teach design patterns in isolation — without grounding them in real, working systems. This project resolves both problems by merging portfolio functionality with a living, interactive pattern showcase.
| Objective | Description |
|---|---|
| Portfolio Showcase | Present projects, blog posts, resume, articles, and podcast content in a unified, dynamic interface |
| Pattern Playground | Implement all 23 GoF design patterns as first-class, observable features of the running application |
| Educational Reference | Provide a production-grade codebase that CS students and educators can study and extend |
| Future AI Integration | Architect the system to support LLM-powered content generation and intelligent assistants |
| Layer | Technology | Rationale |
|---|---|---|
| Frontend Framework | Next.js 16 + React 19 | App Router support, SSR/CSR flexibility, API routes co-location |
| Language | TypeScript 5.9 (strict) | Type safety essential for pattern demonstrations; generics power Strategy/Iterator/Composite |
| Styling | Tailwind CSS 4 + PostCSS | Utility-first enables rapid theme switching; supports Abstract Factory theme families |
| Runtime Scripting | Bun | Canonical package management and script execution for seeding, integration tests, and container builds |
| ORM | Prisma 7 | Type-safe database access; migration management for schema evolution |
| Database | PostgreSQL 16 | ACID compliance; relational model suits User→Post ownership graph |
| Authentication | Auth.js / NextAuth v5 beta | Pluggable OAuth providers; JWT session strategy with role augmentation |
| Containerization | Docker + Docker Compose | Environment parity; isolates PostgreSQL; supports SSH-based production deployment |
| CI/CD | GitHub Actions | Builds a GHCR image and deploys it over SSH with production Docker Compose |
- All 23 GoF patterns implemented in
src/patterns/with 140+ test cases - Functional portfolio sections: Projects, Blog, Resume, Articles, Podcast, Contact, Dashboard
- Working authentication (Google OAuth + test credentials)
- Theme customization (dark/light, 4 style families, 2 font families, EN/TH i18n)
- Guided tour system with iterator-driven step navigation
- Command palette (Ctrl+K) with undo/redo history
- Docker-containerized development and production environments
- GitHub Actions deployment workflow for GCP and Azure hosts
- Performance benchmarks (FCP < 2.5s, LCP < 4.0s) — In Progress
- Full WCAG 2.1 AA accessibility audit — In Progress
| ID | Feature | Priority | Status |
|---|---|---|---|
| FR-1 | Portfolio Content Management (Composite tree, multi-layout) | Critical | ✅ Implemented |
| FR-2 | Unified Feed with Filter Chain + Sort Strategy | High | ✅ Implemented |
| FR-3 | Role-Based Authentication (Google OAuth + Credentials) | Critical | ✅ Implemented |
| FR-4 | Runtime Theme & Localization System (Abstract Factory) | High | ✅ Implemented |
| FR-5 | Guided Tour System (Iterator + State Machine) | Medium | ✅ Implemented |
| FR-6 | Command Palette with Undo/Redo (Command + Memento) | Medium | ✅ Implemented |
| FR-7 | Podcast Player (Finite State Machine) | Low | ✅ Implemented |
| FR-8 | Contact Form with Mediator Validation | Medium | ✅ Implemented |
| FR-9 | Admin Dashboard (Visitor analytics, Prototype cloning) | High | ✅ Implemented |
| FR-10 | REST API for Posts CRUD | High | ✅ Implemented |
| FR-11 | Full CRUD for Projects, Articles, Podcasts | Medium | Planned |
| FR-12 | AI/LLM Content Generation | Low | Planned |
| Requirement | Target | Status |
|---|---|---|
| First Contentful Paint (FCP) | < 2.5s | To be defined |
| Largest Contentful Paint (LCP) | < 4.0s | To be defined |
| Accessibility (WCAG) | 2.1 AA | To be defined |
| Browser Support | Chrome, Firefox, Safari, Edge (latest 2) | Partial |
| Mobile Responsiveness | 320px – 2560px | Partial |
| Uptime Target | ≥ 99.5% | To be defined |
| API Error Rate | < 0.1% | To be defined |
| TypeScript Strict Mode | 100% | ✅ Enforced |
| Role | Capabilities |
|---|---|
| Guest | View public portfolio sections, browse content feed |
| Viewer | All guest permissions + filter/sort feed, access guided tour, use command palette |
| Admin | All viewer permissions + create/delete posts, clone project templates, view dashboard analytics |
The system follows a Pattern-Driven UI Monolith with a Layered Architecture within a single Next.js application:
block-beta
columns 1
block:client["Client (Browser)"]
columns 1
ui["️ UI Layer — React Components\nNavigationShell · Sections · Feed · System Controls"]
domain["⚙️ Domain Layer — Models & Services\nTheme · Command · Feed · Content · Tour"]
facade["️ Application Facade\nAppSystemFacade (Bootstrap)"]
end
arrow["HTTP / JSON"]
block:server["Server (Next.js)"]
columns 1
api[" Server Layer — Next.js API Routes\n/api/auth · /api/posts · Auth Middleware"]
dal[" Data Access Layer — Prisma ORM"]
db["️ Database — PostgreSQL 16\nusers · posts · future models"]
end
ui --> domain
domain --> facade
facade --> arrow
arrow --> api
api --> dal
dal --> db
All 23 Gang of Four patterns are implemented and observable in the running application.
| Pattern | Implementation | Location |
|---|---|---|
| Singleton | NotificationService, ToastEventEmitter, CommandHistory |
app/services/system/ |
| Factory Method | LocalizationFactory — creates EN/TH locale objects |
app/models/theme/ |
| Abstract Factory | StyleFactory — creates Modern/Minimal/Future/Academic theme families |
app/models/theme/ |
| Builder | ContentBuilder — fluent API for constructing nested content trees |
app/models/ |
| Prototype | ProjectTemplate + ProjectTemplateRegistry — admin template cloning |
app/models/template/ |
| Pattern | Implementation | Location |
|---|---|---|
| Adapter | adaptBlogToUnified, adaptProjectToUnified — normalize diverse content types |
app/services/content/ |
| Bridge | NotificationService + INotificationChannel — decouple notification logic from delivery |
app/services/system/ |
| Composite | LayoutNode / CompositeNode / LeafNode — recursive content tree |
app/interfaces/content-tree.ts |
| Decorator | ContentDecorator — dynamically adds badges/overlays to feed cards |
app/components/feed/ |
| Facade | AppSystemFacade — single entry point for app bootstrap and initialization |
app/services/system/ |
| Flyweight | ParticleFactory — shared intrinsic state for animated background particles |
app/components/system/ |
| Proxy | AccessControlProxy — gate premium/admin content behind session checks |
app/models/ |
| Pattern | Implementation | Location |
|---|---|---|
| Chain of Responsibility | FilterHandler pipeline — Type → Tag → Search filters |
app/services/feed/ |
| Command | ICommand + NavigateCommand, ToggleThemeCommand, etc. |
app/models/command/ |
| Iterator | TourIterator — sequential step traversal for guided tour |
app/models/tour/ |
| Observer | ToastEventEmitter — event-driven toast notification dispatch |
app/services/system/ |
| Strategy | FeedSortStrategy — DateSortStrategy, TitleSortStrategy, LengthSortStrategy |
app/models/feed/ |
| State | AudioPlayerContext with StoppedState, PlayingState, PausedState |
app/models/podcast/ |
| Template Method | Content export algorithm with pluggable format steps | src/patterns/ |
| Mediator | ContactFormMediator — orchestrates form validation and submission |
app/services/contact/ |
| Memento | FeedStateMemento + FeedStateCaretaker — snapshot/restore filter state |
app/models/feed/ |
| Interpreter | Grammar evaluator for expression parsing | src/patterns/ |
| Visitor | MetricsVisitor, TagsVisitor — analytics traversal of content trees |
app/components/dashboard/ |
erDiagram
USER {
string id PK "cuid"
string email UK
string name
string image
string role
string provider
string providerAccountId
datetime createdAt
datetime updatedAt
}
POST {
string id PK "cuid"
string title
string content
boolean published
string authorId FK
datetime createdAt
datetime updatedAt
}
USER ||--o{ POST : "authors"
| Entity | Fields | Notes |
|---|---|---|
User |
id (cuid PK), email (unique), name, image, role, provider, providerAccountId, createdAt, updatedAt |
Composite unique on [provider, providerAccountId] |
Post |
id (cuid PK), title, content, published, authorId (FK → User), createdAt, updatedAt |
Index on authorId |
Planned models: Project, Article, Podcast, Blog, Template, Tag, Category
flowchart TD
A([" Login"]) --> B{"Choose Provider"}
B -- "Google OAuth" --> C["NextAuth OAuth Callback"]
B -- "Credentials" --> D["Credential Validation"]
C --> E["Upsert User in PostgreSQL"]
D --> E
E --> F["Generate JWT\n(userId + role)"]
F --> G["Session Callback\naugments session object"]
G --> H{"Access Protected Route?"}
H -- "Yes" --> I["requireAdminSession()"]
H -- "No" --> K["Render Viewer UI"]
I -- "Admin role" --> J["Render Admin UI"]
I -- "Insufficient role" --> L(["401 Unauthorized"])
personal-profile-prototype/
├── app/ # Next.js App Router root
│ ├── api/ # Server-side API route handlers
│ │ ├── auth/ # NextAuth.js endpoints
│ │ ├── posts/ # Posts CRUD (GET, POST, DELETE)
│ │ └── users/ # User management [planned]
│ ├── components/ # Reusable React UI components
│ │ ├── content/ # Content node renderers
│ │ ├── dashboard/ # Metrics, tag cloud, analytics
│ │ ├── feed/ # Feed cards, filters, sort bar
│ │ ├── layout/ # Navigation shell, page structure
│ │ ├── section/ # Section primitive wrappers
│ │ └── system/ # Theme controls, tour, command palette, particles
│ ├── features/ # Feature-level compositions
│ │ ├── composition/ # Root app assembly (PersonalWebsiteApp)
│ │ └── sections/ # Full section implementations
│ ├── interfaces/ # TypeScript interface contracts
│ │ ├── content-tree.ts # IContentNode, IVisitor, IComponent
│ │ └── feed.ts # IFeedItem, IFeedState, ISortStrategy
│ ├── lib/ # Server-side utilities
│ │ ├── auth.ts # NextAuth configuration
│ │ ├── prisma.ts # Prisma singleton client
│ │ └── require-admin-session.ts # Auth middleware helper
│ ├── models/ # Domain model implementations
│ │ ├── command/ # ICommand + concrete commands
│ │ ├── feed/ # Sort strategies, Memento, FilterHandler
│ │ ├── podcast/ # AudioPlayerContext + State classes
│ │ ├── template/ # ProjectTemplate, registry (Prototype)
│ │ ├── theme/ # Style/Font/Locale factories
│ │ └── tour/ # TourIterator, tour steps
│ ├── services/ # Business logic & orchestration
│ │ ├── contact/ # ContactFormMediator
│ │ ├── content/ # Content adapters, decorators
│ │ ├── feed/ # Feed operations
│ │ └── system/ # AppSystemFacade, NotificationService
│ ├── data/ # Static/mock data
│ │ ├── content.ts # Portfolio content seed
│ │ └── resume.ts # Resume data model
│ ├── [tab]/ # Dynamic tab routing
│ ├── globals.css # Global base styles
│ ├── layout.tsx # Root layout (Geist fonts, Providers)
│ ├── page.tsx # Root entry point
│ └── providers.tsx # React context providers (NextAuth SessionProvider)
├── src/ # Standalone pattern library
│ ├── patterns/ # All 23 GoF patterns (standalone TypeScript)
│ │ ├── 01_singleton_notifications.ts
│ │ ├── ...
│ │ ├── 24_visitor_operations.ts
│ │ ├── TESTS.ts # 30+ creational tests (Bun:test)
│ │ ├── STRUCTURAL_TESTS.ts # 50+ structural tests
│ │ ├── BEHAVIORAL_TESTS.ts # 60+ behavioral tests
│ │ └── index.ts # Central pattern exports
│ ├── main.ts # Pattern library entry
│ ├── interface.ts # Shared type contracts
│ └── data.ts # Shared mock data
├── prisma/
│ ├── schema.prisma # Prisma data model
│ └── migrations/ # Versioned schema migrations
├── scripts/
│ ├── integration-auth-db.ts # Auth + DB integration test
│ ├── integration-http-crud.ts # HTTP CRUD integration test
│ ├── integration-http-admin-users.ts # Admin endpoint integration test
│ ├── prisma-crud-example.ts # Prisma CRUD reference
│ ├── deploy-gcp.sh # Manual GCP deploy script
│ └── setup-docker-dev.sh # Docker dev environment setup
├── lib/
│ └── prisma.ts # Root Prisma singleton (for scripts)
├── .github/workflows/
│ └── deploy.yml # Build GHCR image → SSH deploy to GCP and Azure hosts
├── Dockerfile # Multi-stage production build
├── docker-compose.yml # Dev: PostgreSQL + Next.js app
├── docker-compose.prod.yml # Production compose configuration
└── package.json # Dependencies + Bun scripts
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/auth/session |
Public | Check active session |
POST |
/api/auth/signin |
Public | NextAuth sign-in |
POST |
/api/auth/signout |
Session | Sign out |
GET |
/api/posts |
Session | List all posts |
POST |
/api/posts |
Admin | Create a new post |
GET |
/api/posts/[id] |
Session | Get single post |
DELETE |
/api/posts/[id] |
Admin | Delete a post |
| Construct | Convention | Example |
|---|---|---|
| React Components | PascalCase | UnifiedFeedSection, CommandPalette |
| Files | kebab-case | feed-item-card.tsx |
| Interfaces | PascalCase (prefixed I) |
ICommand, IVisitor |
| Services | PascalCase + Service suffix |
NotificationService |
| Constants | UPPER_SNAKE_CASE | MOCK_PROJECTS, LOCALES |
| Types | PascalCase | DecorationType, LayoutStyleType |
- React Context API is used for global state (theme, language, admin role) rather than a third-party store — keeping the pattern surface visible without framework magic.
- Singleton services are instantiated once at module load, ensuring pattern correctness is observable at runtime.
- Bun is the canonical package manager and script runner for dependency installation, seeding, integration tests, image builds, and container runtime commands. Node.js remains the Docker base image for Next.js compatibility.
- Static mock data (
app/data/) drives the portfolio sections in the MVP; the REST API layer is designed to replace this data source as database models are added.
| Layer | Framework | Status |
|---|---|---|
| Pattern Unit Tests | Bun (bun:test) |
✅ 140+ test cases across all 23 patterns |
| Integration — Auth + DB | Bun script (scripts/integration-auth-db.ts) |
✅ Available locally; not run by the current deployment workflow |
| Integration — HTTP CRUD | Bun script (scripts/integration-http-crud.ts) |
✅ Available locally; not run by the current deployment workflow |
| Integration — Admin Users | Bun script (scripts/integration-http-admin-users.ts) |
✅ Available locally; not run by the current deployment workflow |
| Unit Tests — React Components | Jest / React Testing Library | To be defined |
| E2E Tests | Playwright | To be defined |
# Creational patterns
bun test src/patterns/TESTS.ts
# Structural patterns
bun test src/patterns/STRUCTURAL_TESTS.ts
# Behavioral patterns
bun test src/patterns/BEHAVIORAL_TESTS.ts
# All patterns
bun test src/patterns/# Prerequisites: database running and migrations applied
bun run db:up
bunx prisma migrate deploy
# Auth + database
bun run integration:auth-db
# HTTP CRUD endpoints
bun run integration:http-crud
# Admin user management
bun run integration:http-admin-usersUnit Tests (Jest + RTL)
├── ContentBuilder.test.ts
├── FeedStateMemento.test.ts
├── AudioPlayerStateMachine.test.ts
├── NotificationService.test.ts
└── Adapters (adaptBlogToUnified, etc.)
E2E Tests (Playwright)
├── Portfolio viewing flow
├── Feed filter → sort → display
├── Theme switching (dark/light, styles)
├── Authentication + admin feature gates
└── Contact form submission
Target coverage: 80% for critical paths, 60% overall.
- Node.js 20.19+ (the Docker image uses
node:20.19-alpine) - Docker & Docker Compose
- Bun (canonical package manager and script runner)
- Google Cloud SDK (optional, for manual GCP tooling)
# 1. Clone the repository
git clone <repository-url>
cd personal-profile-prototype
# 2. Install dependencies
bun install
# 3. Configure environment
cp .env.example .env
# 4. Start PostgreSQL
bun run db:up # docker compose up -d
# 5. Apply database migrations
bunx prisma migrate dev
# 6. Seed the database
bun run prisma:seed
# 7. Start development server
bun run dev # Webpack dev server → http://localhost:3000
# or: bun run dev:turbo # Turbopack (faster, experimental)The Compose files use different variable names for local development and production deployment. Configure the appropriate environment file for the selected runtime and do not commit secret values.
# Local docker-compose.yml
DATABASE_URL=postgresql://user:password@localhost:5432/personal_profile_prototype
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=<random-256-bit-secret>
GITHUB_ID=<optional-github-client-id>
GITHUB_SECRET=<optional-github-client-secret>
GOOGLE_ID=<optional-google-client-id>
GOOGLE_SECRET=<optional-google-client-secret>
NODE_ENV=development
NEXT_PUBLIC_API_URL=http://localhost:3000docker-compose.prod.yml uses DATABASE_URL, NODE_ENV, and NEXT_PUBLIC_API_URL, and also expects production values for AUTH_SECRET, AUTH_URL, AUTH_TRUST_HOST, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, ADMIN_TEST_EMAIL, ADMIN_TEST_PASSWORD, VIEWER_TEST_PASSWORD, OWNER_EMAIL, and SERVER_NODE.
# Build image
docker build -t personal-profile:0.1.0 .
# Run with production env
docker run -p 3000:3000 --env-file .env.production personal-profile:0.1.0
# Or use production compose
docker compose -f docker-compose.prod.yml up -dThe Dockerfile uses a multi-stage build:
- Stage 1 (builder):
node:20.19-alpine— bootstraps Bun, installs dependencies frombun.lock, generates the Prisma client, and builds Next.js - Stage 2 (runner):
node:20.19-alpine— bootstraps Bun, copies the built application assets, runs as the non-rootnodeuser, and starts the app withbun run start
docker-compose.prod.yml pulls ghcr.io/taichi112/personal-profile-app:latest and runs the app alongside Nginx and Certbot.
flowchart TD
A(["Push to main"]) --> B["deploy.yml: check out repository"]
B --> C["Log in to GitHub Container Registry"]
C --> D["Build Docker image from Dockerfile"]
D --> E["Push ghcr.io/taichi112/personal-profile-app:latest"]
E --> F["deploy-gcp: SSH to GCP host"]
E --> G["deploy-azure: validate SSH key and connect to Azure host"]
F --> H["Reset checkout to origin/main"]
G --> I["Reset checkout to origin/main"]
H --> J["Pull app image and restart docker-compose.prod.yml"]
I --> K["Pull app image and restart docker-compose.prod.yml"]
J --> L(["GCP Docker Compose deployment running"])
K --> M(["Azure Docker Compose deployment running"])
| Environment | Platform | Trigger |
|---|---|---|
| Development | Local Docker Compose | Manual |
| Production — GCP host | Docker Compose over SSH | Push to main |
| Production — Azure host | Docker Compose over SSH | Push to main |
- Horizontal scaling: The current SSH-based Docker Compose deployment runs on individual hosts. Horizontal scaling would require an orchestration or load-balancing layer.
- Database scaling: Migrate from single PostgreSQL container to GCP Cloud SQL with read replicas as traffic grows.
- Content volume: The Composite tree and Adapter pattern ensure new content types can be added without modifying existing rendering logic.
| Area | Current | Planned |
|---|---|---|
| Client errors | console.log + Toast notifications |
Sentry / GCP Error Reporting |
| Server errors | Next.js default | Structured JSON logs → GCP Cloud Logging |
| Performance | Manual | Core Web Vitals via Vercel Analytics or GCP |
| Uptime | None | StatusPage.io / GCP Uptime Checks |
| Analytics | AnalyticsSystem singleton (client-side) |
Google Analytics / Plausible |
| Cadence | Task |
|---|---|
| Weekly | Review CI failures; check error logs for patterns |
| Monthly | bun audit + dependency security patches; analyze failed API requests |
| Quarterly | Major framework version upgrades; security audit; load testing; DR drill |
| Metric | Target |
|---|---|
| RTO (Recovery Time Objective) | 4 hours |
| RPO (Recovery Point Objective) | 1 hour |
| Backup Strategy | Daily automated PostgreSQL snapshots; weekly offsite |
| Rollback | Manual: deploy a known-good GHCR image tag and restart the production Docker Compose services |
- AI-Native Content Generation: Integrate an LLM API to auto-generate blog post drafts, project descriptions, and resume bullet points
- Database-backed portfolio: Migrate static
data/content.tsto Prisma-managedProject,Article,Podcast, andTemplatemodels - Full-text search: Add PostgreSQL full-text search or Algolia for the content feed
- Accessibility audit: Complete WCAG 2.1 AA remediation and add automated axe-core checks to CI
- Progressive Web App (PWA): Add service worker and offline support via
next-pwa - Kubernetes manifests: Add Helm chart for multi-region, production-scale deployment
Generated from codebase analysis · April 2026 · Personal Profile Prototype v0.1.0