Back to Projects

Adou's Space

A personal website that integrates an AI intelligent chat assistant, a backend management system, internationalization support, and a dark mode.

April 1, 2026FeaturedAI Powered
AINext.js
Live Demo

Tech Stack

CategoryTechnology
FrameworkNext.js 16 (App Router, Webpack)
LanguageTypeScript 5
FrontendReact 19
StylingTailwind CSS 4
AnimationsFramer Motion 12
Internationalizationnext-intl 4
Data StorageUpstash Redis
File StorageVercel Blob
AI IntegrationVercel AI SDK 6 (Zhipu/OpenAI/Anthropic)
AuthenticationJWT (jose) + bcryptjs
EmailNodemailer 8
FormsReact Hook Form 7 + Zod 4
Rich TextTiptap 3 (About page)
Markdownreact-markdown + rehype-highlight + remark-gfm (Blog/Projects)
Image ProcessingSharp
PDF Parsingunpdf (Resume text extraction)
PWASerwist 9 (Service Worker)
DeploymentVercel

Features

Frontend Display

  • Hero Section - Dynamic typewriter effect, gradient background animation, tech tag showcase
  • About Me - Personal introduction, quick info cards, hobby showcase
  • Skills Showcase - Dynamically categorized skill cards with custom categories, color themes, sorting, proficiency indicators, highlight badges, and custom icons; skill names support opt-in internationalization (single language by default, descriptive content like soft skills can enable bilingual zh/en switching)
  • Stats - Animated counter showing project count, experience years, etc.
  • Projects Showcase - 3D tilt card effect, thumbnail display, tech stack tags, external links
  • Work Experience - Timeline layout, achievements list
  • Blog Posts - Article list, detail page, table of contents navigation, Markdown rendering, bilingual content (zh/en), on-demand JetBrains Mono font loading
  • Contact Form - Form validation, email/push notifications
  • AI Chat - Floating chat window, full-screen chat page, resume mode/general mode toggle, first-time use guide, accessibility support (aria-live live region), mobile custom pointer drag-to-close, idle-time lazy loading, virtual scrolling message list, stop generation button, compact responsive header layout
  • Dark Mode - System-follow/manual toggle, flicker-free theme load, safe localStorage access, iOS PWA status bar theme auto-sync, immersive status bar (black-translucent)
  • Internationalization - Chinese/English bilingual support with URL path prefix distinction
  • SEO Optimization - Dynamic Metadata, Open Graph, Twitter Card, Sitemap, Robots.txt, JSON-LD
  • Dynamic Favicon - Automatically switches based on dark/light mode
  • Back to Top - Scroll-revealed back-to-top button with jelly scroll mode adaptation
  • Jelly Scroll - Smooth inertial scrolling effect on desktop, automatic device detection, native scroll on mobile, cross-page anchor navigation
  • Responsive Design - Complete mobile adaptation
  • Loading Skeletons - Skeleton loading states for blog/project list and detail pages, section-level skeletons
  • PWA Support - Installable to desktop, with install prompt component, shortcuts (Projects/Blog), iOS status bar theme sync, notch safe area adaptation (immersive status bar)
  • Performance Optimizations - Framer Motion LazyMotion on-demand loading, chat page dynamic imports (next/dynamic lazy loading large components), ISR incremental static generation (300s revalidate), memory cache optimization (300s TTL, 80% Redis query reduction), JWT Token caching (LRU eviction strategy, 30s TTL, max 100 entries), i18n messages caching, Link prefetching (preload target page on hover), scroll session restore (cross-page anchor navigation), custom smooth scroll effect (jellyScrollToElement), server components + Suspense streaming render (Promise.all parallel data fetching, independent section loading for improved first-screen performance), development mode performance logging (data fetch duration monitoring), DNS prefetch optimization (early resolution of external resource domains), Service Worker external image caching (CacheFirst strategy, 30-day expiration), CSS performance optimization (will-change, contain properties), Bundle Analyzer support (ANALYZE=true to analyze bundle size)

Admin Panel

  • Dashboard - Data overview statistics
  • Hero Management - Edit greetings, name, tagline, CTA, etc.
  • About Management - Edit personal intro, quick info, hobbies
  • Skills Management - Add/edit/delete skill items, custom category management (add/edit/delete categories, color themes, sorting), proficiency
  • Projects Management - Full CRUD, Slug format validation, Slug modification warning, thumbnail upload, sorting, image upload
  • Experience Management - Add/edit/delete work experiences
  • Blog Management - Markdown editor, bilingual content editing (zh/en), create/edit
  • Contact Management - Social links, resume upload, availability status
  • Sensitive Words Management - Configure sensitive word mappings for resume redaction (original→replacement), AI assistant auto-replaces
  • Messages Management - View/delete messages, read status
  • Stats Management - Edit displayed statistics numbers
  • Password Change - Secure password change process (8+ chars, must include uppercase, lowercase, and digits), rate limit protection, automatic token cache clearing after change
  • File Upload - Support image and PDF upload to Vercel Blob (magic number validation, filename sanitization, category whitelist, automatic PDF text extraction)

AI Chat System

  • Multiple AI Providers - Support Zhipu AI (GLM-4), OpenAI (GPT-4o-mini), Anthropic (Claude)
  • Dual Mode Toggle - Resume mode (answer personal questions), general mode (answer various questions)
  • Resume Content Integration - Resume mode automatically loads PDF-extracted resume text as important reference context
  • Privacy Protection - User-configurable sensitive word mappings (company names auto-replaced with generic terms), system prompts include mandatory privacy rules prohibiting disclosure of company names
  • Context Management - Token-aware context window management, compressed portfolio context (~60% token reduction), auto-summarization for long conversations, user preference/need extraction
  • Virtual Scrolling - Only renders messages within viewport for smooth scrolling with large message lists
  • Stop Generation - Manually stop AI generation while preserving received content
  • Auto-Retry - Automatic retry on AI request failure, with manual cancel option
  • System Prompt Caching - 30-second TTL memory cache to reduce repeated build overhead
  • Admin Panel Security - System prompts include instructions to never answer admin panel-related questions
  • Streaming Response - Real-time streaming AI replies with error handling and abort support
  • Timeout Handling - AI API 60-second timeout protection, returns 504 status code on timeout
  • Typewriter Animation - Character-by-character display of welcome messages
  • Rate Limiting - Hourly/daily request frequency limits (Redis Lua atomic scripts), rate info returned via response headers
  • Login Intent Detection - Type "login"/"admin" to trigger login modal
  • Markdown Rendering - AI replies support code blocks, bold, lists, etc.

Notification System

  • Email Notification (SMTP) - Send email when new message received
  • Bark Push (iOS) - Push to iPhone via Bark
  • ServerChan Push - Push to WeChat via ServerChan

Project Structure

personal-portfolio/
├── app/                          # Next.js App Router
│   ├── [locale]/                 # Internationalized routes
│   │   ├── page.tsx              # Homepage (sections combined)
│   │   ├── blog/                 # Blog list & detail (with loading skeletons, on-demand JetBrains Mono font)
│   │   ├── chat/                 # Full-screen AI chat page
│   │   ├── projects/             # Project list & detail (with loading skeletons)
│   │   ├── layout.tsx            # Internationalized layout
│   │   ├── error.tsx             # Error page
│   │   ├── loading.tsx           # Loading state
│   │   └── not-found.tsx         # 404 page
│   ├── admin/                    # Admin panel
│   │   ├── layout.tsx            # Admin layout
│   │   ├── about/                # About management
│   │   ├── blog/                 # Blog management
│   │   ├── contact/              # Contact management
│   │   ├── experience/           # Experience management
│   │   ├── hero/                 # Hero management
│   │   ├── messages/             # Messages management
│   │   ├── projects/             # Projects management
│   │   ├── sensitive-words/      # Sensitive words management
│   │   ├── skills/               # Skills management
│   │   ├── stats/                # Stats management
│   │   └── change-password/      # Password change
│   ├── api/                      # API routes
│   │   ├── admin/                # Admin API
│   │   ├── auth/                 # Auth API (login/logout/verify/change password)
│   │   ├── chat/                 # AI chat API
│   │   ├── contact/              # Contact form API
│   │   └── warmup/               # Warmup API (Vercel Cron scheduled calls)
│   ├── sw.ts                     # Serwist Service Worker entry
│   ├── layout.tsx                # Root layout
│   ├── page.tsx                  # Root page (redirect to default language)
│   ├── globals.css               # Global styles entry
│   ├── manifest.ts               # PWA Manifest (shortcuts, adaptive icons)
│   ├── robots.ts                 # Robots.txt generation
│   ├── sitemap.ts                # Sitemap generation
│   ├── error.tsx                 # Global error page
│   └── global-error.tsx          # Global uncaught error page
├── components/
│   ├── admin/                    # Admin components
│   │   ├── AdminErrorBoundary.tsx # Admin error boundary
│   │   ├── AdminHeader.tsx       # Admin header
│   │   ├── AdminSidebar.tsx      # Sidebar navigation
│   │   ├── ConfirmDialog.tsx     # Confirm dialog
│   │   ├── DataTable.tsx         # Data table
│   │   ├── ImageUpload.tsx       # File upload (supports images and PDF)
│   │   ├── MarkdownEditor.tsx    # Markdown editor
│   │   ├── MessageToast.tsx      # Message toast
│   │   ├── RichTextEditor.tsx    # Tiptap rich text editor (About page)
│   │   ├── SensitiveWordsEditor.tsx # Sensitive words editor
│   │   ├── SaveStatus.tsx        # Save status indicator
│   │   └── SortableList.tsx      # Sortable list
│   ├── ai/                       # AI chat components
│   │   ├── ChatInput.tsx         # Chat input (with stop generation support)
│   │   ├── ChatMessage.tsx       # Message bubble
│   │   ├── ChatWidget.tsx        # Floating chat window (mobile drag-to-close)
│   │   ├── ClientChatWidget.tsx  # Client chat entry (idle-time lazy loading)
│   │   ├── LoginModal.tsx        # Login modal
│   │   ├── MarkdownRenderer.tsx  # Markdown renderer
│   │   ├── ModeToggle.tsx        # Mode toggle
│   │   ├── QuickPrompts.tsx      # Quick prompts
│   │   ├── TypingIndicator.tsx   # Typing indicator
│   │   └── VirtualMessageList.tsx # Virtual scrolling message list
│   ├── blog/                     # Blog components
│   │   ├── BlogDetailClient.tsx  # Blog detail client
│   │   ├── BlogListClient.tsx    # Blog list client
│   │   ├── MDXComponents.tsx     # Markdown render & table of contents
│   │   └── PostCard.tsx          # Post card
│   ├── layout/                   # Layout components
│   │   ├── ClientPortfolioWrapper.tsx # Client page wrapper (with jelly scroll)
│   │   ├── ClientProviders.tsx   # Client providers combined
│   │   ├── DynamicFavicon.tsx    # Dynamic favicon
│   │   ├── Footer.tsx            # Footer
│   │   ├── Header.tsx            # Navigation header
│   │   ├── LanguageSwitcher.tsx  # Language switcher
│   │   ├── Navigation.tsx        # Navigation menu
│   │   ├── PWAInstallPrompt.tsx # PWA install prompt component
│   │   ├── PortfolioPageWrapper.tsx # Page wrapper
│   │   ├── ThemeProvider.tsx     # Theme provider
│   │   └── ThemeToggle.tsx       # Theme toggle
│   ├── sections/                 # Homepage section components
│   │   ├── HeroSection.tsx       # Hero section
│   │   ├── HeroSectionWithData.tsx # Hero section (server component, supports Suspense)
│   │   ├── AboutSection.tsx      # About section
│   │   ├── AboutSectionWithData.tsx # About section (server component, supports Suspense)
│   │   ├── SkillsSection.tsx     # Skills section
│   │   ├── SkillsSectionWithData.tsx # Skills section (server component, supports Suspense)
│   │   ├── StatsSection.tsx      # Stats section
│   │   ├── StatsSectionWithData.tsx # Stats section (server component, supports Suspense)
│   │   ├── ProjectsSection.tsx   # Projects section
│   │   ├── ProjectsSectionWithData.tsx # Projects section (server component, supports Suspense)
│   │   ├── ExperienceSection.tsx # Experience section
│   │   ├── ExperienceSectionWithData.tsx # Experience section (server component, supports Suspense)
│   │   ├── BlogSection.tsx       # Blog section
│   │   ├── BlogSectionWithData.tsx # Blog section (server component, supports Suspense)
│   │   ├── ContactSection.tsx    # Contact section
│   │   ├── ContactSectionWithData.tsx # Contact section (server component, supports Suspense)
│   │   ├── ProjectCard.tsx       # Project card
│   │   ├── ProjectDetailContent.tsx # Project detail content
│   │   ├── SectionSkeleton.tsx   # Skeleton loader (Hero, About, Skills, Stats, Projects, Experience, Blog, Contact)
│   │   └── TimelineItem.tsx      # Timeline item
│   ├── seo/                      # SEO components
│   │   └── JsonLd.tsx            # JSON-LD structured data (Person, WebSite, Article, Breadcrumb)
│   └── ui/                       # Common UI components
│       ├── AnimatedCounter.tsx   # Animated counter
│       ├── AnimatedLine.tsx      # Animated line
│       ├── Badge.tsx             # Badge
│       ├── Button.tsx            # Button
│       ├── ContactForm.tsx       # Contact form
│       ├── DatePicker.tsx        # Date picker
│       ├── Dialog.tsx            # Dialog
│       ├── FloatingParticles.tsx # Floating particles
│       ├── Input.tsx             # Input
│       ├── MagneticButton.tsx    # Magnetic button
│       ├── MarkdownRenderer.tsx  # Markdown renderer
│       ├── MouseGlow.tsx         # Mouse glow
│       ├── OptimizedJellyScroll.tsx # Jelly scroll component
│       ├── ScrollToTopButton.tsx # Back to top
│       ├── Select.tsx            # Select
│       ├── Skeleton.tsx          # Skeleton loader
│       ├── Textarea.tsx          # Textarea
│       └── TiltCard.tsx          # 3D tilt card
├── hooks/                        # Custom hooks
│   ├── useChat.ts                # AI chat logic
│   └── usePWAInstall.ts          # PWA install hook
├── i18n/                         # Internationalization
│   ├── zh-CN.json                # Chinese translations
│   ├── en-US.json                # English translations
│   ├── routing.ts                # Routing config
│   ├── navigation.ts             # Navigation utilities
│   ├── request.ts                # Request config (with messages caching)
│   └── server.ts                 # Server-side i18n utilities
├── lib/                          # Utility library
│   ├── ai/                       # AI related
│   │   ├── providers/            # AI provider implementations
│   │   │   ├── zhipu.ts          # Zhipu AI (SSE stream parsing, timeout protection, buffer overflow handling)
│   │   │   ├── openai.ts         # OpenAI
│   │   │   ├── anthropic.ts      # Anthropic
│   │   │   ├── types.ts          # Type definitions
│   │   │   └── index.ts          # Provider registry
│   │   ├── context.ts            # Context building (with resume content integration)
│   │   ├── context-compressor.ts # Context compression (compact format, ~60% token reduction)
│   │   ├── redact.ts            # Resume content redaction (user-configured sensitive word mapping replacement)
│   │   ├── extractor.ts          # User preference/need extraction
│   │   ├── summarizer.ts         # Conversation summarization (auto-compress long conversations)
│   │   ├── tokenizer.ts          # Token estimation and context window management
│   │   ├── utils.ts              # AI utility functions (stream collection, etc.)
│   │   ├── rate-limit.ts         # Rate limiting
│   │   ├── resume-parser.ts      # Resume text retrieval
│   │   └── system-prompts.ts     # System prompts (with 30-second cache, admin panel security warnings)
│   ├── auth/                     # Authentication
│   │   ├── index.ts              # Auth utilities (with withAuth wrapper)
│   │   ├── jwt.ts                # JWT utilities (with token caching, LRU eviction strategy)
│   │   └── middleware.ts         # Auth middleware
│   ├── i18n/                     # i18n utilities
│   │   └── server.ts             # Server-side translation and language parsing
│   ├── api.ts                    # Server-side data fetching layer
│   ├── api-client.ts             # Client-side API request utilities
│   ├── constants.ts              # Shared constants (default skill categories, etc.)
│   ├── data.ts                   # Upstash Redis data read/write (LRU cache, atomic append, development mode performance logging)
│   ├── framer-optimizations.tsx  # Framer Motion performance optimizations (LazyMotion, OptimizedMotionDiv)
│   ├── notification.ts           # Notification push
│   ├── rate-limit.ts             # General rate limiting (Redis Lua atomic scripts)
│   ├── redis.ts                  # Redis singleton (unified connection management)
│   ├── revalidate.ts             # Cache revalidation utilities
│   ├── scroll-session.ts         # Scroll session restore (cross-page anchor navigation, TTL expiration)
│   └── utils.ts                  # Common utilities (getLocaleKey, getClientIp, errorResponse, formatDateTime)
├── types/                        # TypeScript types
│   └── index.ts                  # Global type definitions
├── styles/                       # Styles
│   └── globals.css               # Global styles (CSS variables, animations, scrollbar, etc.)
├── public/                       # Static assets
│   ├── icons/                    # Icons directory (custom icons like UniApp)
│   └── images/                   # Images directory
├── scripts/                      # Scripts
│   └── generate-password-hash.js # Password hash generator
├── next.config.ts                # Next.js config
├── proxy.ts                      # Next.js middleware (i18n routing + admin auth protection)
├── vercel.json                   # Vercel deployment config
├── .env.example                  # Environment variables template
└── package.json                  # Project dependencies

Quick Start

Environment Requirements

  • Node.js 18+
  • pnpm 8+

Installation

# Clone the project
git clone https://github.com/Adou377/personal-portfolio.git
cd personal-portfolio

# Install dependencies
pnpm install

# Copy environment variables
cp .env.example .env.local

# Edit .env.local and fill in actual configuration

Configure Environment Variables

Copy .env.example to .env.local, then fill in according to the following instructions:

Basic Configuration

VariableDescriptionExample
NEXT_PUBLIC_SITE_URLSite domainhttps://trend-flow.top
NEXT_PUBLIC_DEFAULT_LOCALEDefault languagezh-CN

Data Storage Configuration (Required)

VariableDescriptionHow to Get
UPSTASH_REDIS_REST_URLUpstash Redis REST URLUpstash Console
UPSTASH_REDIS_REST_TOKENUpstash Redis TokenUpstash Console
BLOB_READ_WRITE_TOKENVercel Blob read/write tokenVercel Storage

AI Chat Configuration (At least one provider required)

VariableDescription
AI_PROVIDERAI provider: zhipu / openai / anthropic
ZHIPU_API_KEYZhipu AI API Key
ZHIPU_MODELZhipu model name (e.g., glm-4.7-flash)
ZHIPU_BASE_URLZhipu API URL
OPENAI_API_KEYOpenAI API Key
OPENAI_MODELOpenAI model name
ANTHROPIC_API_KEYAnthropic API Key
ANTHROPIC_MODELAnthropic model name

AI Rate Limiting

VariableDescriptionDefault
AI_RATE_LIMIT_HOURLYHourly request limit20
AI_RATE_LIMIT_DAILYDaily request limit100
AI_DAILY_BUDGET_TOKENSDaily token budget100000

Notification Configuration (Optional, skip if not configured)

VariableDescription
SMTP_HOSTSMTP server address
SMTP_PORTSMTP port
SMTP_USERSMTP username
SMTP_PASSSMTP authorization code
CONTACT_EMAILEmail to receive notifications
BARK_SERVER_URLBark push URL
BARK_ICON_URLBark icon URL
BARK_SOUNDBark sound
SERVERCHAN_SENDKEYServerChan SendKey
SERVERCHAN_CHANNELServerChan push channel

Admin Authentication

VariableDescription
ADMIN_PASSWORD_HASHbcrypt hash of admin password
JWT_SECRETJWT signing secret (at least 32 characters)
JWT_EXPIRES_INToken validity (e.g., 24h, 7d)
ADMIN_LOGIN_MAX_ATTEMPTSMax login attempts
ADMIN_LOGIN_LOCKOUT_MINUTESLogin lockout duration (minutes)

File Upload

VariableDescriptionDefault
UPLOAD_MAX_SIZEMax upload file size (MB)5

Generate Admin Password

node scripts/generate-password-hash.js

This will generate a password hash and JWT secret, fill them into .env.local.

Development

pnpm dev

Visit http://localhost:3000 to view the website.

Build

pnpm build

Lint

pnpm lint

Deployment

Vercel Deployment (Recommended)

  1. Push project to GitHub
  2. Import project in Vercel
  3. Create Upstash Redis database
    • Visit Upstash Console
    • Create new database, select same region as Vercel project
    • Copy UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN
  4. Create Vercel Blob Store
    • Visit Vercel Storage
    • Create Blob Store and link to project
    • Copy BLOB_READ_WRITE_TOKEN
  5. Configure environment variables (refer to configuration instructions above)
  6. Deploy

Project already includes vercel.json configuration with security headers (including CSP), Japan region deployment, and Cron scheduled tasks (server warmup every 5 minutes).

Security Headers Configuration

Project configures the following security headers via vercel.json:

  • Cache-Control: public, max-age=0, must-revalidate - HTML pages no-cache
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin
  • Content-Security-Policy - Restricts script, style, image, and connection sources (supports Vercel Blob, SimpleIcons CDN)
  • API routes Cache-Control: no-store
  • Static assets Cache-Control: public, max-age=31536000, immutable

Admin Panel

Visit /admin to access the admin panel, log in with the configured password.

Data Storage

Project uses Upstash Redis for structured data (JSON), and Vercel Blob for uploaded files (images, PDFs, etc.). This architecture is suitable for Serverless deployment environments, with persistent and scalable data storage.

Resume Upload

When uploading a PDF resume, the system automatically extracts text content and stores it in contact.json. The AI chat resume mode prioritizes the extracted resume text as context.

Customization

Modify Theme Colors

Edit CSS variables in styles/globals.css:

:root {
  --primary: #8FB2C9;
  --accent: #E94560;
  --ai-glow: #7C3AED;
  /* ... */
}

.dark {
  --primary: #8FB2C9;
  --accent: #E94560;
  --ai-glow: #A78BFA;
  /* ... */
}

Modify Personal Information

Modify all personal data through the admin panel.

Add Language

  1. Add new language to locales in i18n/routing.ts
  2. Create corresponding translation file (e.g., i18n/ja-JP.json)
  3. Update Locale type in types/index.ts

Tech Stack

Next.jsTypeScriptTailwind CSSVercel AI SDKnext-intl
AINext.js