้ข่ฎก้
่ฏปๆถ้ด๏ผ19 ๅ้
๐ ่ถ
ๅ็งๆๆไธชไบบๅๅฎข โ ๅๅ็ซฏๅ็ฆปๆถๆ่ฎพ่ฎก
ไธใๆดไฝๆถๆๆฆ่ง
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CDN / ่ด่ฝฝๅ่กก โ
โ Cloudflare / Nginx โ
โโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโผโโโโโ โโโโโโโโผโโโโโโโ โโโโโโผโโโโโ
โ ๅ็ซฏ SPA โ โ ๅ็ซฏ API โ โ ็ฎก็ๅๅฐ โ
โ React + โ HTTP/RESTโ NestJS โ โ React โ
โ Vite โ โโโโโโโโโโบ โ + WebSocket โ โ Admin โ
โ โ โ โ โ โ
โโโโโโโโโโโโ โโโโโโโโฌโโโโโโโโ โโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโผโโโโโโ โโโโโโผโโโโโ โโโโโโโโผโโโโโโโ
โ PostgreSQL โ โ Redis โ โ MinIO/S3 โ
โ ไธปๆฐๆฎๅบ โ โ ็ผๅญ โ โ ๅฏน่ฑกๅญๅจ โ
โโโโโโโโโโโโโ โโโโโโโโโโโ โ (ๅพ็/ๆไปถ) โ
โโโโโโโโโโโโโโโ
| ๅฑ็บง |
ๆๆฏ้ๅ |
ไฝ็จ |
| ๅ็ซฏ |
React 19 + Vite + TypeScript |
็จๆท็้ข๏ผSSR ๅฏ้ |
| ๅ็ซฏ |
NestJS + TypeScript |
RESTful API + WebSocket |
| ๆฐๆฎๅบ |
PostgreSQL 16 |
ไธปๆฐๆฎๅญๅจ |
| ็ผๅญ |
Redis 7 |
ไผ่ฏ็ผๅญใๆ็ซ ็ผๅญใ้ๅ |
| ๅญๅจ |
MinIO / ้ฟ้ไบOSS |
ๅพ็ใ้ไปถใ้ๆ่ตๆบ |
| ็ฝๅ
ณ |
Nginx / Cloudflare |
ๅๅไปฃ็ใ้ๆตใSSL |
ไบใ้กถ็บง้กน็ฎ็ปๆ๏ผMonorepo๏ผ
blog/
โโโ packages/ # ๅ
ฑไบซๅ
โ โโโ shared/ # ๅ
ฑไบซ็ฑปๅใDTOใๅธธ้
โ โ โโโ src/
โ โ โ โโโ types/ # ๅ
ฑ็จ TS ็ฑปๅ (IArticle, IUser ็ญ)
โ โ โ โโโ dto/ # ่ฏทๆฑ/ๅๅบ DTO
โ โ โ โโโ enums/ # ๆไธพๅธธ้
โ โ โ โโโ utils/ # ๅ
ฑไบซๅทฅๅ
ทๅฝๆฐ
โ โ โโโ package.json
โ โ
โ โโโ eslint-config/ # ็ปไธ ESLint ้
็ฝฎ
โ
โโโ apps/
โ โโโ client/ # ===== ๅ็ซฏ (SPA) =====
โ โ โโโ public/
โ โ โ โโโ fonts/ # ่ชๅฎไนๅญไฝ
โ โ โ โโโ images/ # ้ๆๅพ็
โ โ โ โโโ models/ # 3D ๆจกๅๆไปถ
โ โ โ
โ โ โโโ src/
โ โ โ โโโ main.tsx # ๅ
ฅๅฃ
โ โ โ โโโ App.tsx # ๆ น็ปไปถ๏ผ่ทฏ็ฑ + ๅ
จๅฑ Provider๏ผ
โ โ โ โ
โ โ โ โโโ pages/ # ่ทฏ็ฑ้กต้ข
โ โ โ โ โโโ Home/ # ้ฆ้กต๏ผTerminal ๅ
ฅๅฃ + ๆๆฐๆ็ซ ๏ผ
โ โ โ โ โโโ Posts/ # ๆ็ซ ๅ่กจ + ่ฏฆๆ
โ โ โ โ โโโ Projects/ # ้กน็ฎๅฑ็คบๅข
โ โ โ โ โโโ About/ # ๅ
ณไบ้กต + ๆ่ฝๆ็
โ โ โ โ โโโ Guestbook/ # ็่จๆฟ
โ โ โ โ โโโ Snippets/ # ไปฃ็ ็ๆฎต
โ โ โ โ โโโ NotFound/ # 404 ๆ
้้ฃ
โ โ โ โ
โ โ โ โโโ components/ # UI ็ปไปถ็ฎๅฝ
โ โ โ โ โโโ ui/ # ๅบ็ก็ปไปถ๏ผButton, Card, Input...๏ผ
โ โ โ โ โ โโโ Button.tsx # ้่นๅ
ๆๆ้ฎ
โ โ โ โ โ โโโ Card.tsx # ็ป็ๆๅก็
โ โ โ โ โ โโโ Input.tsx # ๅๅ
่พๅ
ฅๆก
โ โ โ โ โ โโโ Badge.tsx # ๅ
จๆฏๆ ็ญพ
โ โ โ โ โ โโโ Modal.tsx # ๆฏ็ป็ๆจกๆๆก
โ โ โ โ โ โโโ Toast.tsx # ๆตๅจๅ
ๆ็คบ
โ โ โ โ โ
โ โ โ โ โโโ layout/ # ๅธๅฑ็ปไปถ
โ โ โ โ โ โโโ Navbar.tsx # ๆฌๆตฎๅฏผ่ช๏ผๆป่ฝฎๅ่ฒ๏ผ
โ โ โ โ โ โโโ Footer.tsx # ๅบ้จๆๅบง่ฟ็บฟ
โ โ โ โ โ โโโ Sidebar.tsx # ไพง่พนๆ ็ฎๅฝ
โ โ โ โ โ โโโ MobileNav.tsx # ็งปๅจ็ซฏๆฝๅฑ
โ โ โ โ โ
โ โ โ โ โโโ effects/ # ็นๆ็ปไปถ
โ โ โ โ โ โโโ ParticleBackground.tsx # Three.js ็ฒๅญ
โ โ โ โ โ โโโ GridGlow.tsx # ็ฝๆ ผๅ
ๆ
โ โ โ โ โ โโโ GlitchText.tsx # ๆ
้ๆๅญ
โ โ โ โ โ โโโ TypeWriter.tsx # ๆๅญๆบ
โ โ โ โ โ โโโ ScanLine.tsx # CRT ๆซๆ็บฟ
โ โ โ โ โ โโโ Aurora.tsx # ๆๅ
ๅจๆ่ๆฏ
โ โ โ โ โ
โ โ โ โ โโโ blog/ # ๅๅฎข็ปไปถ
โ โ โ โ โ โโโ PostCard.tsx # 3D ๅพๆๅก็
โ โ โ โ โ โโโ PostHeader.tsx # ๆ็ซ ๅคด้จ
โ โ โ โ โ โโโ TableOfContents.tsx # ๆฌๆตฎ็ฎๅฝ
โ โ โ โ โ โโโ ReadingProgress.tsx # ๅ
ๆ่ฟๅบฆๆก
โ โ โ โ โ โโโ CodeBlock.tsx # ้่นไปฃ็ ๅ
โ โ โ โ โ โโโ CommentSection.tsx # ่ฏ่ฎบๅบ
โ โ โ โ โ
โ โ โ โ โโโ home/ # ้ฆ้กต็ปไปถ
โ โ โ โ โโโ HeroSection.tsx # 3D ๆฌข่ฟๅบ
โ โ โ โ โโโ TerminalIntro.tsx # Terminal ไบคไบ
โ โ โ โ โโโ FeaturedPosts.tsx # ็ฒพ้่ฝฎๆญ
โ โ โ โ โโโ StatsBoard.tsx # ๆฐๆฎ้ขๆฟ
โ โ โ โ
โ โ โ โโโ hooks/ # ่ชๅฎไน Hooks
โ โ โ โ โโโ useMousePosition.ts
โ โ โ โ โโโ useScrollProgress.ts
โ โ โ โ โโโ useIntersectionObserver.ts
โ โ โ โ โโโ useApi.ts # ๅฐ่ฃ
API ่ฏทๆฑ
โ โ โ โ
โ โ โ โโโ services/ # API ่ฐ็จๅฑ
โ โ โ โ โโโ http.ts # Axios ๅฎไพ๏ผๆฆๆชๅจ๏ผ
โ โ โ โ โโโ postService.ts # ๆ็ซ ๆจกๅ API
โ โ โ โ โโโ projectService.ts # ้กน็ฎๆจกๅ API
โ โ โ โ โโโ commentService.ts # ่ฏ่ฎบๆจกๅ API
โ โ โ โ โโโ authService.ts # ่ฎค่ฏๆจกๅ API
โ โ โ โ โโโ guestbookService.ts # ็่จๆจกๅ API
โ โ โ โ
โ โ โ โโโ stores/ # ็ถๆ็ฎก็๏ผZustand๏ผ
โ โ โ โ โโโ useThemeStore.ts # ไธป้ข็ถๆ
โ โ โ โ โโโ useUserStore.ts # ็จๆท็ถๆ
โ โ โ โ โโโ useUIStore.ts # UI ็ถๆ๏ผไพง่พนๆ ใๅผน็ช๏ผ
โ โ โ โ
โ โ โ โโโ styles/ # ๆ ทๅผ
โ โ โ โ โโโ globals.css # ๅ
จๅฑๆ ทๅผ + CSS ๅ้
โ โ โ โ โโโ animations.css # ๅ
ณ้ฎๅธงๅจ็ป
โ โ โ โ โโโ markdown.css # ๆ็ซ ๅ
ๅฎนๆ ทๅผ
โ โ โ โ
โ โ โ โโโ utils/ # ๅทฅๅ
ทๅฝๆฐ
โ โ โ โโโ cn.ts # classNames ๅๅนถ
โ โ โ
โ โ โโโ index.html
โ โ โโโ vite.config.ts
โ โ โโโ tailwind.config.ts
โ โ โโโ tsconfig.json
โ โ โโโ package.json
โ โ
โ โโโ server/ # ===== ๅ็ซฏ API (NestJS) =====
โ โ โโโ src/
โ โ โ โโโ main.ts # ๅ
ฅๅฃ๏ผๅฏๅจ HTTP + WebSocket๏ผ
โ โ โ โโโ app.module.ts # ๆ นๆจกๅ
โ โ โ โ
โ โ โ โโโ common/ # ๅ
ฌๅ
ฑๆจกๅ
โ โ โ โ โโโ decorators/ # ่ชๅฎไน่ฃ
้ฅฐๅจ
โ โ โ โ โโโ filters/ # ๅผๅธธ่ฟๆปคๅจ
โ โ โ โ โโโ guards/ # ๅฎๅซ๏ผJWT Auth Guard๏ผ
โ โ โ โ โโโ interceptors/ # ๆฆๆชๅจ๏ผๆฅๅฟใๅๅบๆ ผๅผ๏ผ
โ โ โ โ โโโ pipes/ # ็ฎก้๏ผๅๆฐๆ ก้ช๏ผ
โ โ โ โ โโโ middleware/ # ไธญ้ดไปถ๏ผ้ๆตใCORS๏ผ
โ โ โ โ โโโ constants/ # ๅ
จๅฑๅธธ้
โ โ โ โ
โ โ โ โโโ modules/ # ไธๅกๆจกๅ
โ โ โ โ โโโ posts/ # ๆ็ซ ๆจกๅ
โ โ โ โ โ โโโ posts.module.ts
โ โ โ โ โ โโโ posts.controller.ts # REST ่ทฏ็ฑ
โ โ โ โ โ โโโ posts.service.ts # ไธๅก้ป่พ
โ โ โ โ โ โโโ posts.gateway.ts # WebSocket ็ฝๅ
ณ
โ โ โ โ โ โโโ dto/ # ่ฏทๆฑ DTO
โ โ โ โ โ โโโ entities/ # ๅฎไฝ/ๆจกๅ
โ โ โ โ โ โโโ posts.controller.spec.ts
โ โ โ โ โ
โ โ โ โ โโโ projects/ # ้กน็ฎๆจกๅ
โ โ โ โ โโโ comments/ # ่ฏ่ฎบๆจกๅ
โ โ โ โ โโโ guestbook/ # ็่จๆฟๆจกๅ
โ โ โ โ โโโ snippets/ # ไปฃ็ ็ๆฎตๆจกๅ
โ โ โ โ โโโ auth/ # ่ฎค่ฏๆจกๅ๏ผJWT + OAuth๏ผ
โ โ โ โ โโโ users/ # ็จๆทๆจกๅ
โ โ โ โ โโโ tags/ # ๆ ็ญพๆจกๅ
โ โ โ โ โโโ analytics/ # ๆฐๆฎ็ป่ฎกๆจกๅ
โ โ โ โ โโโ upload/ # ๆไปถไธไผ ๆจกๅ
โ โ โ โ โโโ search/ # ๆ็ดขๆจกๅ
โ โ โ โ
โ โ โ โโโ config/ # ้
็ฝฎๆจกๅ
โ โ โ โโโ database.config.ts # ๆฐๆฎๅบ้
็ฝฎ
โ โ โ โโโ redis.config.ts # Redis ้
็ฝฎ
โ โ โ โโโ jwt.config.ts # JWT ้
็ฝฎ
โ โ โ โโโ cors.config.ts # CORS ้
็ฝฎ
โ โ โ
โ โ โโโ prisma/ # Prisma ORM
โ โ โ โโโ schema.prisma # ๆฐๆฎๅบๆจกๅๅฎไน
โ โ โ โโโ seed.ts # ็งๅญๆฐๆฎ
โ โ โ
โ โ โโโ test/ # ็ซฏๅฐ็ซฏๆต่ฏ
โ โ โโโ nest-cli.json
โ โ โโโ tsconfig.json
โ โ โโโ package.json
โ โ
โ โโโ admin/ # ===== ็ฎก็ๅๅฐ =====
โ โโโ src/
โ โ โโโ pages/ # ๅๅฐ้กต้ข
โ โ โ โโโ Dashboard/ # ไปช่กจ็
โ โ โ โโโ Posts/ # ๆ็ซ ็ฎก็๏ผMarkdown ็ผ่พๅจ๏ผ
โ โ โ โโโ Comments/ # ่ฏ่ฎบๅฎกๆ ธ
โ โ โ โโโ Users/ # ็จๆท็ฎก็
โ โ โ โโโ Settings/ # ็ซ็น่ฎพ็ฝฎ
โ โ โ โโโ Analytics/ # ๆฐๆฎ็ๆฟ
โ โ โ
โ โ โโโ components/ # ๅๅฐ็ปไปถ
โ โ โ โโโ RichEditor.tsx # ๅฏๆๆฌ/Markdown ็ผ่พๅจ
โ โ โ โโโ ImageUploader.tsx
โ โ โ โโโ DataTable.tsx
โ โ โ
โ โ โโโ services/ # API ่ฐ็จ
โ โ โโโ hooks/
โ โ
โ โโโ vite.config.ts
โ โโโ package.json
โ
โโโ docker/ # Docker ็ผๆ
โ โโโ docker-compose.yml # ๅ
จๆ ไธ้ฎๅฏๅจ
โ โโโ Dockerfile.client
โ โโโ Dockerfile.server
โ โโโ nginx/
โ โโโ nginx.conf # ๅๅไปฃ็้
็ฝฎ
โ โโโ ssl/ # SSL ่ฏไนฆ
โ
โโโ scripts/ # ๅผๅ/้จ็ฝฒ่ๆฌ
โ โโโ dev.sh # ๆฌๅฐๅผๅๅฏๅจ
โ โโโ seed.sh # ๆฐๆฎๅๅงๅ
โ โโโ deploy.sh # ้จ็ฝฒ่ๆฌ
โ
โโโ .github/ # CI/CD
โ โโโ workflows/
โ โโโ ci.yml # PR ่ชๅจๆต่ฏ
โ โโโ deploy.yml # ่ชๅจ้จ็ฝฒ
โ
โโโ .env.example # ็ฏๅขๅ้ๆจกๆฟ
โโโ .gitignore
โโโ package.json # ๆ น Monorepo ้
็ฝฎ
โโโ pnpm-workspace.yaml # pnpm workspace
โโโ turbo.json # Turborepo ๆๅปบ็ผๅญ
โโโ README.md
ไธใๆฐๆฎๅบ่ฎพ่ฎก (Prisma Schema)
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ---- ็จๆท ----
model User {
id String @id @default(cuid())
username String @unique
email String @unique
password String
avatar String?
bio String?
role Role @default(USER) // USER | ADMIN
githubId String? @unique // OAuth ็ปๅฎ
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[]
comments Comment[]
guestbooks Guestbook[]
likes Like[]
sessions Session[]
}
// ---- ๆ็ซ ----
model Post {
id String @id @default(cuid())
title String
slug String @unique
excerpt String? // ๆ็ซ ๆ่ฆ
content String // Markdown ๆญฃๆ
coverImage String? // ๅฐ้ขๅพ
published Boolean @default(false)
pinned Boolean @default(false) // ๆฏๅฆ็ฝฎ้กถ
views Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
publishedAt DateTime?
authorId String
author User @relation(fields: [authorId], references: [id])
tags TagRelation[]
comments Comment[]
likes Like[]
}
// ---- ๆ ็ญพ ----
model Tag {
id String @id @default(cuid())
name String @unique
color String? // ๆ ็ญพ้ข่ฒ๏ผ็จไบ UI๏ผ
posts TagRelation[]
}
model TagRelation {
postId String
tagId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([postId, tagId])
}
// ---- ้กน็ฎ ----
model Project {
id String @id @default(cuid())
title String
slug String @unique
description String
content String? // ่ฏฆ็ปไป็ป๏ผMarkdown๏ผ
coverImage String?
techStack String[] // ["React", "Three.js", "Go"]
liveUrl String? // ็บฟไธๅฐๅ
githubUrl String? // ๆบ็ ๅฐๅ
featured Boolean @default(false)
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ---- ่ฏ่ฎบ ----
model Comment {
id String @id @default(cuid())
content String
postId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
authorId String
author User @relation(fields: [authorId], references: [id])
parentId String? // ๅๅคๆๆก่ฏ่ฎบ๏ผๅตๅฅ่ฏ่ฎบ๏ผ
parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
replies Comment[] @relation("CommentReplies")
likes Int @default(0)
createdAt DateTime @default(now())
}
// ---- ็่จๆฟ ----
model Guestbook {
id String @id @default(cuid())
content String
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
}
// ---- ็น่ต ----
model Like {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
postId String?
post Post? @relation(fields: [postId], references: [id], onDelete: Cascade)
commentId String?
comment Comment? @relation(fields: [commentId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@unique([userId, postId]) // ไธ็ฏๆ็ซ ไธไธช็จๆทๅช่ฝ็นไธๆฌก่ต
}
// ---- ็ซ็น็ป่ฎก ----
model SiteStats {
id String @id @default("main")
totalViews Int @default(0)
totalPosts Int @default(0)
totalUsers Int @default(0)
updatedAt DateTime @updatedAt
}
// ---- ไผ่ฏ ----
model Session {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
token String @unique
expiresAt DateTime
createdAt DateTime @default(now())
}
enum Role {
USER
ADMIN
}
ๅใAPI ๆฅๅฃ่ฎพ่ฎก (RESTful)
4.1 ๆ็ซ ๆจกๅ /api/v1/posts
| ๆนๆณ |
่ทฏๅพ |
่ฏดๆ |
ๆ้ |
| GET |
/posts |
ๆ็ซ ๅ่กจ๏ผๅ้กต+็ญ้+ๆๅบ๏ผ |
ๅ
ฌๅผ |
| GET |
/posts/:slug |
ๆ็ซ ่ฏฆๆ
|
ๅ
ฌๅผ |
| POST |
/posts |
ๅๅปบๆ็ซ |
ADMIN |
| PUT |
/posts/:id |
ๆดๆฐๆ็ซ |
ADMIN |
| DELETE |
/posts/:id |
ๅ ้คๆ็ซ |
ADMIN |
| POST |
/posts/:id/views |
้
่ฏป้ +1 |
ๅ
ฌๅผ |
| POST |
/posts/:id/like |
็น่ต/ๅๆถ |
USER |
4.2 ๅ
ถไปๆจกๅ
| ๆนๆณ |
่ทฏๅพ |
่ฏดๆ |
| GET/POST |
/api/v1/comments |
่ฏ่ฎบๅ่กจ / ๅ่กจ่ฏ่ฎบ |
| GET/POST |
/api/v1/guestbook |
็่จๅ่กจ / ๅ่กจ็่จ |
| GET/POST |
/api/v1/projects |
้กน็ฎๅ่กจ / CRUD |
| POST |
/api/v1/auth/login |
็ปๅฝ๏ผJWT๏ผ |
| POST |
/api/v1/auth/register |
ๆณจๅ |
| POST |
/api/v1/auth/github |
GitHub OAuth |
| GET |
/api/v1/search?q=xxx |
ๅ
จ็ซๆ็ดข |
| POST |
/api/v1/upload |
ๆไปถไธไผ |
| GET |
/api/v1/analytics |
็ป่ฎกๆฐๆฎ |
4.3 WebSocket ไบไปถ
| ไบไปถ |
ๆนๅ |
่ฏดๆ |
post:view |
Client โ Server |
ๅฎๆถ้
่ฏป้ๆจ้ |
post:updated |
Server โ Client |
ๆ็ซ ๆดๆฐ้็ฅ |
comment:new |
Server โ Client |
ๆฐ่ฏ่ฎบ้็ฅ |
online:count |
Server โ Client |
ๅฎๆถๅจ็บฟไบบๆฐ |
ไบใๆฐๆฎๆต่ฎพ่ฎก
โโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโ
โ ็จๆทๆไฝ โ โโโโ ๅ็ซฏ Service โ โโโโ NestJS API โ โโโโ DB โ
โ (็นๅป/่พๅ
ฅ)โ โ (Axios) โ โ (Controller) โ โ Prisma โ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโฌโโโโโโโ โโโโโโโโโโโโ
โ
โโโโโโโโผโโโโโโโ โโโโโโโโโโโโ
โ Redis ็ผๅญ โ โโโโ ็ผๅญ็ญ็ฅ โ
โ โ โ โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโ
็ผๅญ็ญ็ฅ:
Cache-Aside: ่ฏป: ๅ
ๆฅ Redis โ ๆชๅฝไธญ โ ๆฅ DB โ ๅๅ Redis
ๅ: ๆดๆฐ DB โ ๅ ้ค็ผๅญ โ ไธๆฌก่ฏป้ๅปบ
TTL: ๆ็ซ ่ฏฆๆ
: 1h / ๆ็ซ ๅ่กจ: 30min / ๆ ็ญพ: 1h
Cache Key: blog:post:{slug} / blog:posts:page:{n} / blog:tags
ๅ
ญใไบคไบ่ฎพ่ฎก๏ผๅฎขๆท็ซฏๆธฒๆๆต็จ๏ผ
้กต้ขๅ ่ฝฝ
โ
โโโ 1. ๅๅงๅ Three.js ็ฒๅญ่ๆฏ
โ ๏ผไฝไผๅ
็บง๏ผไธๅฝฑๅ้ฆๅฑ๏ผ
โ
โโโ 2. ่ทๅ็ซ็นๅ
ๆฐๆฎ
โ GET /api/v1/site-meta
โ โ ็ซ็นๅใๅคดๅใๆ ่ฏญใๆ ็ญพไบ
โ
โโโ 3. ้ฆ้กต โ ๅนถๅ่ฏทๆฑ
โ โโโ GET /api/v1/posts?page=1&limit=6 (ๆๆฐๆ็ซ )
โ โโโ GET /api/v1/projects?featured=true (็ฒพ้้กน็ฎ)
โ โโโ GET /api/v1/analytics (็ป่ฎกๆฐๆฎ)
โ
โโโ 4. ๆ็ซ ้กต โ ็ๅธ่ฏทๆฑ
โโโ GET /api/v1/posts/:slug (ๆ็ซ ๅ
ๅฎน)
โโโ GET /api/v1/comments?postId=xxx (่ฏ่ฎบๅ่กจ)
โโโ WebSocket connect (ๅฎๆถๅจ็บฟ)
ไธใ็ฏๅข้
็ฝฎ & ้จ็ฝฒ
7.1 ็ฏๅขๅ้ (.env)
# ๆฐๆฎๅบ
DATABASE_URL="postgresql://user:pass@localhost:5432/blog"
REDIS_URL="redis://localhost:6379"
# JWT
JWT_SECRET="your-secret-key"
JWT_EXPIRES_IN="7d"
# OAuth
GITHUB_CLIENT_ID="xxx"
GITHUB_CLIENT_SECRET="xxx"
# ๅฏน่ฑกๅญๅจ
OSS_ENDPOINT="https://oss-cn-hangzhou.aliyuncs.com"
OSS_ACCESS_KEY="xxx"
OSS_SECRET_KEY="xxx"
OSS_BUCKET="blog-assets"
# ๅ็ซฏ
VITE_API_BASE_URL="https://api.blog.com/api/v1"
VITE_WS_URL="wss://api.blog.com"
7.2 docker-compose.yml
version: "3.8"
services:
client:
build:
context: ./apps/client
dockerfile: ../../docker/Dockerfile.client
ports:
- "3000:80"
depends_on:
- server
server:
build:
context: ./apps/server
dockerfile: ../../docker/Dockerfile.server
ports:
- "4000:4000"
env_file: .env
depends_on:
- postgres
- redis
admin:
build:
context: ./apps/admin
dockerfile: ../../docker/Dockerfile.client
ports:
- "3001:80"
depends_on:
- server
postgres:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: blog
POSTGRES_USER: blog
POSTGRES_PASSWORD: ${DB_PASSWORD}
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
command: redis-server --requirepass ${REDIS_PASSWORD}
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/ssl:/etc/nginx/ssl
depends_on:
- client
- server
- admin
volumes:
pgdata:
redisdata:
7.3 ้จ็ฝฒๆถๆ
Cloudflare
โ
โโโโโโโโโโผโโโโโโโโโ
โ Nginx ็ฝๅ
ณ โ
โ โ SSL ็ปๆญข โ
โ โ ้ๆต / WAF โ
โ โ ่ทฏ็ฑๅๅ โ
โโโโโฌโโโโโฌโโโโโฌโโโโ
โ โ โ
โโโโโโผโ โโผโโโโ โโผโโโโ
โๅ็ซฏ โ โๅ็ซฏ โ โๅๅฐ โ
โ:80 โ โ:4000โ โ:80 โ
โโโโโโโ โโโโโโ โโโโโโ
โ โ
โโโโโโผโ โโโโโโผโโโโโ
โCDN โ โPostgreSQLโ
โ้ๆ โ โ+ Redis โ
โ็ผๅญ โ โโโโโโโโโโโ
โโโโโโโ
้จ็ฝฒๆนๆก้้กน:
ๆนๆก A: ๅๆบ Docker Compose๏ผๆจ่่ตทๆญฅ๏ผ
ๆนๆก B: K8s ้็พค๏ผ้ซๆต้ๆถ่ฟ็งป๏ผ
ๆนๆก C: ไบ็ซฏๆ็ฎก๏ผVercel ๅ็ซฏ + Railway ๅ็ซฏ + Neon DB๏ผ
ๅ
ซใ่ง่ง่ฏญ่จ็ณป็ป๏ผ็งๆๆ UI๏ผ
8.1 ่ฒๅฝฉไฝ็ณป
:root {
/* ่ๆฏๅฑ็บง */
--bg-deep: #06060c; /* ๆๆทฑ็ฉบ่ๆฏ */
--bg-primary: #0a0a12; /* ไธป่ๆฏ */
--bg-secondary: #11111a; /* ๅก็/ๅบๅ่ๆฏ */
--bg-glass: rgba(255, 255, 255, 0.03); /* ็ป็่ๆฏ */
/* ๅ
ๆ่ฒๅฝฉ */
--accent-cyan: #00e5ff;
--accent-purple: #b388ff;
--accent-pink: #ff2d95;
--accent-gold: #ffd54f;
/* ๆๅญ */
--text-primary: #e8eaed;
--text-secondary: #9aa0a6;
--text-dim: #5f6368;
/* ่พๅ
*/
--glow-cyan: 0 0 15px #00e5ff, 0 0 30px rgba(0, 229, 255, 0.3);
--glow-purple: 0 0 15px #b388ff, 0 0 30px rgba(179, 136, 255, 0.3);
/* ่พนๆก */
--border-glass: 1px solid rgba(255, 255, 255, 0.06);
--border-glow: 1px solid rgba(0, 229, 255, 0.3);
}
8.2 ๅญไฝไฝ็ณป
| ็จ้ |
ๅญไฝ |
ๆฅๆบ |
| Logo / ๅคงๆ ้ข |
Orbitron 700-900 |
Google Fonts |
| ๆญฃๆๆ ้ข |
Syne 600-700 |
Google Fonts |
| ๆญฃๆ |
Inter 300-500 |
Google Fonts |
| ไปฃ็ |
JetBrains Mono 400-600 |
ๆฌๅฐๅญไฝ |
| ่ฃ
้ฅฐๆๅญ |
Major Mono Display |
Google Fonts |
8.3 ็งๆๆ UI ๅ
็ด ๆธ
ๅ
| ๅ
็ด |
ๆๆฏๆนๆก |
ๆๆๆ่ฟฐ |
| ๅ
จๅฑ็ฒๅญ่ๆฏ |
Three.js + R3F |
ๅจๆ็ฒๅญๆต๏ผ้ผ ๆ ไบคไบไบง็ๆณข็บน |
| ็ฝๆ ผๅ
ๆ |
Canvas 2D / CSS |
็งๆ็ฝๆ ผ + ๆธๅๅ
ๆ |
| CRT ๆซๆ็บฟ |
CSS pseudo-element |
ๅคๅคๅฑๅนๅ ๅฑ๏ผๅฏ้ๅผๅ
ณ |
| ็ป็ๅก็ |
backdrop-filter: blur |
ๆฏ็ป็ + ่พนๆกๅๅ
|
| ๆ
้ๆๅญ |
CSS @keyframes clip |
ๆๅญ้ไฝ + ้ข่ฒๅ็งป้ช็ |
| ๆๅญๆบๆๆ |
JS cursor + setInterval |
Terminal ้ฃๆ ผ้ๅญ่พๅบ |
| ้่นๆ้ฎ |
box-shadow + filter |
ๆฌๆตฎๆถๅฝฉ่ฒ่พๅ
ๆฉๆฃ |
| 3D ๅพๆๅก็ |
useMousePosition + transform |
้ผ ๆ ็งปๅจๆถๅก็ 3D ๆ่ฝฌ |
| ๆปๅจ่ฟๅบฆๆก |
CSS linear-gradient + JS |
ๅบๅฎๅจ้กถ้จ็ๅ
ๆ่ฟๅบฆๆก |
| ๅ ่ฝฝ้ชจๆถๅฑ |
CSS pulse ๅจ็ป |
ๅ
ๅฎนๅ ่ฝฝๆถ็็งๆ่ฝฎๅปๅ ไฝ |
ไนใๅ
ณ้ฎ npm ๅ
ๆธ
ๅ
9.1 ๅ็ซฏ (apps/client)
{
"dependencies": {
"react": "^19.x",
"react-dom": "^19.x",
"react-router-dom": "^7.x",
"framer-motion": "^11.x",
"three": "^0.170.x",
"@react-three/fiber": "^8.x",
"@react-three/postprocessing": "^2.x",
"axios": "^1.x",
"zustand": "^5.x",
"dayjs": "^1.x",
"clsx": "^2.x",
"tailwind-merge": "^2.x",
"react-markdown": "^9.x",
"react-syntax-highlighter": "^15.x",
"react-helmet-async": "^2.x",
"swr": "^2.x"
},
"devDependencies": {
"typescript": "^5.x",
"vite": "^6.x",
"tailwindcss": "^4.x",
"@tailwindcss/typography": "^0.5.x",
"postcss": "^8.x",
"autoprefixer": "^10.x",
"eslint": "^9.x",
"prettier": "^3.x"
}
}
9.2 ๅ็ซฏ (apps/server)
{
"dependencies": {
"@nestjs/core": "^11.x",
"@nestjs/common": "^11.x",
"@nestjs/platform-express": "^11.x",
"@nestjs/websockets": "^11.x",
"@nestjs/jwt": "^11.x",
"@nestjs/passport": "^11.x",
"@nestjs/throttler": "^6.x",
"@nestjs/serve-static": "^5.x",
"@prisma/client": "^6.x",
"passport": "^0.7.x",
"passport-jwt": "^5.x",
"passport-github2": "^0.1.x",
"bcrypt": "^5.x",
"class-validator": "^0.14.x",
"class-transformer": "^0.5.x",
"redis": "^4.x",
"ioredis": "^5.x",
"socket.io": "^4.x",
"sharp": "^0.33.x",
"minio": "^8.x",
"helmet": "^8.x",
"reflect-metadata": "^0.2.x",
"rxjs": "^7.x"
},
"devDependencies": {
"@nestjs/cli": "^11.x",
"@nestjs/testing": "^11.x",
"@types/node": "^22.x",
"prisma": "^6.x",
"ts-node": "^10.x",
"ts-loader": "^9.x",
"typescript": "^5.x",
"jest": "^29.x",
"supertest": "^7.x"
}
}
ๅใๅผๅ่ทฏ็บฟๅพ
Phase 1 โ Monorepo ้ชจๆถ๏ผDay 1-2๏ผ
โก ๅๅงๅ pnpm workspace + Turborepo
โก ๆญๅปบ apps/client (Vite + React + TS)
โก ๆญๅปบ apps/server (NestJS + Prisma)
โก ๆญๅปบ packages/shared
โก ้
็ฝฎ ESLint + Prettier ็ปไธ่งๅ
Phase 2 โ ๆฐๆฎๅบ + API๏ผDay 3-6๏ผ
โก ็ผๅ Prisma Schema โ ็ๆ่ฟ็งป
โก ๅฎ็ฐ User / Auth ๆจกๅ๏ผJWT + GitHub OAuth๏ผ
โก ๅฎ็ฐ Post CRUD + ๅ้กต + ็ญ้
โก ๅฎ็ฐ CommentใGuestbookใProject ๆจกๅ
โก ๆทปๅ Redis ็ผๅญๅฑ
Phase 3 โ ๅ็ซฏๅบ็ก UI๏ผDay 7-12๏ผ
โก ็งๆๆ่ฒๅฝฉ็ณป็ป + ๅ
จๅฑๆ ทๅผ
โก ๅธๅฑ็ปไปถ๏ผNavbar / Footer / Sidebar๏ผ
โก ็นๆ็ปไปถ๏ผ็ฒๅญ่ๆฏ / ็ฝๆ ผๅ
ๆ / ๆ
้ๆๅญ๏ผ
โก ๅบ็ก UI ็ปไปถ๏ผButton / Card / Input / Modal๏ผ
โก ไธป้ขๅๆข๏ผๆ้ป / ่ตๅ / ๆต
่ฒ๏ผ
Phase 4 โ ๅ็ซฏไบคไบ๏ผDay 13-18๏ผ
โก API Service ๅฑ + Zustand ็ถๆ็ฎก็
โก ้ฆ้กต๏ผTerminal ไบคไบ + ็ฒพ้ๅ
ๅฎน๏ผ
โก ๆ็ซ ๅ่กจ้กต๏ผ็ฝๆ ผ/ๆถ้ด่ฝดๅๆข + 3D ๅก็๏ผ
โก ๆ็ซ ่ฏฆๆ
้กต๏ผไปฃ็ ้ซไบฎ + TOC + ่ฟๅบฆๆก๏ผ
โก ้กน็ฎๅฑ็คบๅข + ๅ
ณไบ้กต
Phase 5 โ ๅจๆๅ่ฝ๏ผDay 19-22๏ผ
โก ่ฏ่ฎบ็ณป็ป๏ผๅตๅฅๅๅค + @ๆๅ๏ผ
โก ็่จๆฟ๏ผ็ฒๅญๅขๅจๆ๏ผ
โก ๅ
จ็ซๆ็ดข + ๆ ็ญพไบ
โก WebSocket ๅฎๆถๅจ็บฟ + ้
่ฏป้
Phase 6 โ Admin ๅๅฐ๏ผDay 23-26๏ผ
โก ๅๅฐไปช่กจ็
โก Markdown ็ผ่พๅจ๏ผๆ็ซ ๅๅธ๏ผ
โก ๅพ็ไธไผ + ๆไปถ็ฎก็
โก ่ฏ่ฎบๅฎกๆ ธ + ๆฐๆฎ็ๆฟ
Phase 7 โ ้จ็ฝฒไธ็บฟ๏ผDay 27-30๏ผ
โก Docker Compose ๅ
จๆ ็ผๆ
โก Nginx ๅๅไปฃ็ + SSL
โก CI/CD ๆตๆฐด็บฟ๏ผGitHub Actions๏ผ
โก ๆง่ฝไผๅ + Lighthouse 90+
โก ่ชๅฎไนๅๅ + CDN
ๅไธใๆง่ฝ็ญ็ฅ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๆง่ฝไผๅ็ญ็ฅ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ ๅ็ซฏไผๅ โ
โ โโโโโโโโ โ
โ โข ไปฃ็ ๅๅฒ: React.lazy + Suspense ๆ่ทฏ็ฑๅๅฒ โ
โ โข ๅพ็ไผๅ: ๅปถ่ฟๅ ่ฝฝ + WebP/AVIF ๆ ผๅผ + ๆจก็ณๅ ไฝ โ
โ โข ๅญไฝไผๅ: preload + font-display: swap + ๅญ้ๅ โ
โ โข 3D ไผๅ: ็งปๅจ็ซฏ้ไฝ็ฒๅญๆฐ (2000โ500) โ
โ โข ๅจ็ปไผๅ: ไป
็จ transform/opacity, avoid ้ๆ โ
โ โข ่ฏทๆฑไผๅ: SWR ็ผๅญ + ไน่งๆดๆฐ + ้ฒๆ โ
โ โข ๆๅปบไผๅ: Vite ๆๆ + ๆ้ polyfill โ
โ โ
โ ๅ็ซฏไผๅ โ
โ โโโโโโโโ โ
โ โข ๆฐๆฎๅบ: ็ดขๅผ่ฆ็ + ๆฅ่ฏขไผๅ + ่ฟๆฅๆฑ โ
โ โข ็ผๅญ: Redis Cache-Aside + ็ผๅญ้ข็ญ โ
โ โข ้ๆต: @nestjs/throttler ้ฒๆญขๅทๆฅๅฃ โ
โ โข ๅ็ผฉ: ๅๅบ Gzip/Brotli ๅ็ผฉ โ
โ โข ่ฟๆฅๆฑ : Prisma ่ฟๆฅๆฑ + ๅ็ max_connections โ
โ โ
โ ้จ็ฝฒไผๅ โ
โ โโโโโโโโ โ
โ โข CDN: ้ๆ่ตๆบๅ
จ้็ผๅญๅฐ Cloudflare โ
โ โข Nginx: ้ๆๆไปถ็ดๆฅๅๅบ๏ผไธ็ป่ฟ Node โ
โ โข ๆฐดๅนณๆฉๅฑ: ๅ็ซฏๆ ็ถๆ่ฎพ่ฎก๏ผๅฏๅคๅฎไพ้จ็ฝฒ โ
โ โข ่ชๅจๅคไปฝ: ๆฏๆฅๆฐๆฎๅบ + ๆไปถๅฟซ็
ง โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ๆฌๆ็ฑ admin ๅๅ๏ผ่ฝฌ่ฝฝ่ฏทๆณจๆๅบๅคใ
่ฏ่ฎบ
0