2026-01-18 10:24:35 +08:00
< template >
< div class = "backend-evolution-demo" >
<!-- Timeline -- >
< div class = "timeline-container" >
< div class = "timeline-track" > < / div >
2026-01-18 12:21:49 +08:00
< button
v-for = "(stage, index) in stages"
2026-01-18 10:24:35 +08:00
:key = "index"
class = "timeline-node"
2026-01-18 12:21:49 +08:00
: class = "{
active: currentStage === index,
passed: currentStage > index
}"
2026-01-18 10:24:35 +08:00
@click ="currentStage = index"
>
< div class = "node-dot" >
< div class = "inner-dot" > < / div >
< / div >
< div class = "node-content" >
< span class = "year-badge" > { { stage . year } } < / span >
< span class = "node-label" > { { stage . label } } < / span >
< / div >
< / button >
< / div >
<!-- Content -- >
< div class = "content-wrapper" >
< transition name = "fade-slide" mode = "out-in" >
< div :key = "currentStage" class = "stage-content" >
< div class = "header-section" >
< h3 >
2026-01-18 12:21:49 +08:00
< span class = "stage-index"
> { { indexToRoman ( currentStage + 1 ) } } . < / s p a n
>
2026-01-18 10:24:35 +08:00
{ { stages [ currentStage ] . title } }
< / h3 >
< p > { { stages [ currentStage ] . desc } } < / p >
< / div >
< div class = "visualization-grid" >
<!-- Architecture Diagram -- >
< div class = "mac-window arch-window" >
< div class = "window-bar" >
< div class = "traffic-lights" >
< span class = "light red" > < / span >
< span class = "light yellow" > < / span >
< span class = "light green" > < / span >
< / div >
< div class = "window-title" > Server Architecture < / div >
< / div >
< div class = "arch-canvas" >
<!-- Stage 0 : CGI / Static -- >
< div v-if = "currentStage === 0" class="arch-static" >
< div class = "server-box" >
< div class = "server-icon" > 🖥 ️ Physical Server < / div >
< div class = "file-system" >
< div class = "file" > index . html < / div >
< div class = "file" > script . pl < / div >
< div class = "file" > image . jpg < / div >
< / div >
< / div >
< div class = "request-arrow" >
< span > GET / index . html < / span >
< span class = "arrow" > ➔ < / span >
< / div >
< / div >
<!-- Stage 1 : Monolith -- >
< div v-if = "currentStage === 1" class="arch-monolith" >
< div class = "server-box big" >
2026-01-18 12:21:49 +08:00
< div class = "server-icon" >
🦍 Monolithic App ( Tomcat / Django )
< / div >
2026-01-18 10:24:35 +08:00
< div class = "modules-grid" >
< div class = "module" > User < / div >
< div class = "module" > Order < / div >
< div class = "module" > Payment < / div >
< div class = "module" > Product < / div >
< / div >
< div class = "db-connection" >
< span > ⬇ SQL < / span >
< div class = "db-icon" > 🗄 ️ Single DB < / div >
< / div >
< / div >
< / div >
<!-- Stage 2 : Microservices -- >
< div v-if = "currentStage === 2" class="arch-micro" >
< div class = "cloud-bg" >
< div class = "service-mesh" >
< div class = "service user" >
< span > User Svc < / span >
< small > Redis < / small >
< / div >
< div class = "service order" >
< span > Order Svc < / span >
< small > MySQL < / small >
< / div >
< div class = "service pay" >
< span > Pay Svc < / span >
< small > Postgres < / small >
< / div >
< / div >
< / div >
< div class = "comm-lines" > HTTP / gRPC < / div >
< / div >
<!-- Stage 3 : Serverless -- >
< div v-if = "currentStage === 3" class="arch-serverless" >
< div class = "function-cloud" >
< div class = "func-node" > λ Login < / div >
< div class = "func-node" > λ Checkout < / div >
< div class = "func-node" > λ ResizeImg < / div >
< / div >
< div class = "baas-layer" >
< span > BaaS ( Auth0 , Supabase , Stripe ) < / span >
< / div >
< / div >
< / div >
< / div >
<!-- Deployment / Ops View -- >
< div class = "mac-window ops-window" >
< div class = "window-bar" >
< div class = "window-title" > Deployment & Ops < / div >
< / div >
< div class = "ops-canvas" >
< div class = "ops-card" >
< div class = "ops-icon" > { { stages [ currentStage ] . opsIcon } } < / div >
2026-01-18 12:21:49 +08:00
< div class = "ops-title" >
{ { stages [ currentStage ] . opsTitle } }
< / div >
2026-01-18 10:24:35 +08:00
< div class = "ops-desc" > { { stages [ currentStage ] . opsDesc } } < / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / transition >
< / div >
< / div >
< / template >
< script setup >
import { ref } from 'vue'
const currentStage = ref ( 0 )
const indexToRoman = ( num ) => {
const map = { 1 : 'I' , 2 : 'II' , 3 : 'III' , 4 : 'IV' }
return map [ num ] || num
}
const stages = [
{
year : '1990s' ,
label : 'CGI / Static' ,
title : 'Physical Servers & Scripts' ,
desc : 'In the beginning, servers were physical machines. We uploaded files via FTP. Backend logic was often simple Perl/CGI scripts executing one by one.' ,
opsIcon : '🐌' ,
opsTitle : 'Manual FTP Upload' ,
2026-01-18 12:21:49 +08:00
opsDesc :
'Development was slow. "It works on my machine" was the common nightmare. Scaling meant buying a bigger physical computer.'
2026-01-18 10:24:35 +08:00
} ,
{
year : '2000s' ,
label : 'Monolith' ,
title : 'The Monolithic Era' ,
desc : 'Frameworks like Java Spring, Rails, Django appeared. All logic (User, Order, Pay) was packed into ONE giant process. Simple to develop, hard to scale.' ,
opsIcon : '🐳' ,
opsTitle : 'Virtual Machines (VM)' ,
2026-01-18 12:21:49 +08:00
opsDesc :
'We started using VMs (AWS EC2). Scaling meant copying the entire giant application to multiple servers behind a Load Balancer.'
2026-01-18 10:24:35 +08:00
} ,
{
year : '2014+' ,
label : 'Microservices' ,
title : 'Microservices & Containers' ,
desc : 'Breaking the monolith! Each function (User, Order) became a separate tiny server. Docker changed the game by packaging dependencies together.' ,
opsIcon : '☸️' ,
opsTitle : 'Kubernetes (K8s)' ,
2026-01-18 12:21:49 +08:00
opsDesc :
'Orchestrating thousands of containers. Complexity exploded, but teams could work independently and scale specific parts (e.g., just the Payment service).'
2026-01-18 10:24:35 +08:00
} ,
{
year : '2020s+' ,
label : 'Serverless' ,
title : 'Serverless & Edge' ,
desc : 'No more managing servers. You just write a function (e.g., "resize image") and upload it. The cloud provider runs it only when needed (Pay-per-use).' ,
opsIcon : '⚡' ,
opsTitle : 'GitOps & Edge' ,
2026-01-18 12:21:49 +08:00
opsDesc :
'Push to Git -> Auto Deploy to global Edge nodes (Vercel, Cloudflare). Backend becomes "Functions + Managed Services (BaaS)".'
2026-01-18 10:24:35 +08:00
}
]
< / script >
< style scoped >
. backend - evolution - demo {
border - radius : 16 px ;
background : var ( -- vp - c - bg ) ;
2026-01-18 12:21:49 +08:00
box - shadow : 0 8 px 30 px rgba ( 0 , 0 , 0 , 0.05 ) ;
2026-01-18 10:24:35 +08:00
border : 1 px solid var ( -- vp - c - divider ) ;
overflow : hidden ;
margin : 2 rem 0 ;
2026-01-18 12:21:49 +08:00
font - family :
- apple - system , BlinkMacSystemFont , 'Segoe UI' , Roboto , Helvetica , Arial ,
sans - serif ;
2026-01-18 10:24:35 +08:00
}
/* Timeline (Reused) */
. timeline - container {
padding : 2 rem 1 rem 1 rem ;
background : linear - gradient ( to bottom , var ( -- vp - c - bg - soft ) , var ( -- vp - c - bg ) ) ;
display : flex ;
justify - content : space - between ;
position : relative ;
border - bottom : 1 px solid var ( -- vp - c - divider ) ;
}
. timeline - track {
position : absolute ;
top : 2.5 rem ;
left : 3 rem ;
right : 3 rem ;
height : 2 px ;
background : var ( -- vp - c - divider ) ;
z - index : 0 ;
}
. timeline - node {
position : relative ;
z - index : 1 ;
background : transparent ;
border : none ;
display : flex ;
flex - direction : column ;
align - items : center ;
cursor : pointer ;
padding : 0 ;
width : 25 % ;
transition : all 0.3 s ease ;
opacity : 0.6 ;
}
2026-01-18 12:21:49 +08:00
. timeline - node : hover {
opacity : 0.9 ;
}
. timeline - node . active ,
. timeline - node . passed {
opacity : 1 ;
}
2026-01-18 10:24:35 +08:00
. node - dot {
width : 16 px ;
height : 16 px ;
border - radius : 50 % ;
background : var ( -- vp - c - bg ) ;
border : 2 px solid var ( -- vp - c - text - 3 ) ;
margin - bottom : 0.8 rem ;
display : flex ;
align - items : center ;
justify - content : center ;
transition : all 0.3 s ;
}
. inner - dot {
width : 0 ;
height : 0 ;
border - radius : 50 % ;
background : var ( -- vp - c - brand ) ;
transition : all 0.3 s ;
}
. timeline - node . active . node - dot {
border - color : var ( -- vp - c - brand ) ;
transform : scale ( 1.3 ) ;
box - shadow : 0 0 0 4 px var ( -- vp - c - bg - soft ) ;
}
2026-01-18 12:21:49 +08:00
. timeline - node . active . inner - dot {
width : 8 px ;
height : 8 px ;
}
. timeline - node . passed . node - dot {
border - color : var ( -- vp - c - brand ) ;
background : var ( -- vp - c - brand ) ;
}
2026-01-18 10:24:35 +08:00
. node - content {
text - align : center ;
display : flex ;
flex - direction : column ;
align - items : center ;
gap : 0.2 rem ;
}
. year - badge {
font - size : 0.75 rem ;
font - family : var ( -- vp - font - family - mono ) ;
background : var ( -- vp - c - bg - alt ) ;
padding : 2 px 6 px ;
border - radius : 4 px ;
color : var ( -- vp - c - text - 2 ) ;
}
. node - label {
font - size : 0.85 rem ;
font - weight : 600 ;
color : var ( -- vp - c - text - 1 ) ;
}
/* Content */
2026-01-18 12:21:49 +08:00
. content - wrapper {
padding : 2 rem ;
min - height : 400 px ;
}
2026-01-18 10:24:35 +08:00
. header - section {
text - align : center ;
margin - bottom : 2 rem ;
max - width : 600 px ;
margin : 0 auto 2 rem ;
}
. header - section h3 {
font - size : 1.5 rem ;
margin - bottom : 0.5 rem ;
2026-01-18 12:21:49 +08:00
background : linear - gradient (
120 deg ,
# f59e0b ,
# ea580c
) ; /* Orange/Amber for Backend */
2026-01-18 10:24:35 +08:00
- webkit - background - clip : text ;
- webkit - text - fill - color : transparent ;
}
2026-01-18 12:21:49 +08:00
. stage - index {
color : var ( -- vp - c - text - 3 ) ;
- webkit - text - fill - color : var ( -- vp - c - text - 3 ) ;
margin - right : 0.5 rem ;
font - weight : normal ;
}
. header - section p {
font - size : 1 rem ;
color : var ( -- vp - c - text - 2 ) ;
line - height : 1.6 ;
}
2026-01-18 10:24:35 +08:00
/* Visualizations */
. visualization - grid {
display : grid ;
grid - template - columns : 1 fr 1 fr ;
gap : 2 rem ;
align - items : stretch ;
}
2026-01-18 12:21:49 +08:00
@ media ( max - width : 768 px ) {
. visualization - grid {
grid - template - columns : 1 fr ;
}
}
2026-01-18 10:24:35 +08:00
. mac - window {
border - radius : 12 px ;
2026-01-18 12:21:49 +08:00
border : 1 px solid rgba ( 0 , 0 , 0 , 0.1 ) ;
box - shadow : 0 10 px 30 px rgba ( 0 , 0 , 0 , 0.05 ) ;
2026-01-18 10:24:35 +08:00
overflow : hidden ;
display : flex ;
flex - direction : column ;
background : white ;
transition : transform 0.3 s ;
}
2026-01-18 12:21:49 +08:00
. mac - window : hover {
transform : translateY ( - 5 px ) ;
}
2026-01-18 10:24:35 +08:00
2026-01-18 12:21:49 +08:00
. arch - window {
background : # f1f5f9 ;
}
. ops - window {
background : white ;
}
2026-01-18 10:24:35 +08:00
. window - bar {
padding : 0.8 rem 1 rem ;
background : white ;
2026-01-18 12:21:49 +08:00
border - bottom : 1 px solid rgba ( 0 , 0 , 0 , 0.05 ) ;
2026-01-18 10:24:35 +08:00
display : flex ;
align - items : center ;
position : relative ;
}
2026-01-18 12:21:49 +08:00
. traffic - lights {
display : flex ;
gap : 6 px ;
}
. light {
width : 10 px ;
height : 10 px ;
border - radius : 50 % ;
}
. light . red {
background : # ff5f56 ;
}
. light . yellow {
background : # ffbd2e ;
}
. light . green {
background : # 27 c93f ;
}
2026-01-18 10:24:35 +08:00
. window - title {
position : absolute ;
left : 0 ;
right : 0 ;
text - align : center ;
font - size : 0.8 rem ;
color : var ( -- vp - c - text - 2 ) ;
font - weight : 600 ;
}
2026-01-18 12:21:49 +08:00
. arch - canvas ,
. ops - canvas {
2026-01-18 10:24:35 +08:00
padding : 2 rem ;
flex : 1 ;
display : flex ;
align - items : center ;
justify - content : center ;
min - height : 250 px ;
}
/* Arch Styles */
. server - box {
background : # cbd5e1 ;
border : 2 px solid # 94 a3b8 ;
2026-02-14 20:23:34 +08:00
padding : 0.75 rem ;
border - radius : 6 px ;
2026-01-18 10:24:35 +08:00
text - align : center ;
}
2026-01-18 12:21:49 +08:00
. file - system {
margin - top : 1 rem ;
background : white ;
padding : 0.5 rem ;
border - radius : 4 px ;
font - family : monospace ;
font - size : 0.8 rem ;
}
. request - arrow {
margin - top : 1 rem ;
display : flex ;
flex - direction : column ;
align - items : center ;
font - size : 0.8 rem ;
color : # 64748 b ;
}
2026-01-18 10:24:35 +08:00
2026-01-18 12:21:49 +08:00
. server - box . big {
background : # dbeafe ;
border - color : # 3 b82f6 ;
width : 100 % ;
max - width : 250 px ;
}
. modules - grid {
display : grid ;
grid - template - columns : 1 fr 1 fr ;
gap : 4 px ;
2026-02-14 20:23:34 +08:00
margin : 0.5 rem 0 ;
2026-01-18 12:21:49 +08:00
}
. module {
background : # bfdbfe ;
padding : 4 px ;
border - radius : 4 px ;
font - size : 0.8 rem ;
color : # 1 e40af ;
}
. db - connection {
font - size : 0.8 rem ;
display : flex ;
flex - direction : column ;
align - items : center ;
}
2026-01-18 10:24:35 +08:00
2026-01-18 12:21:49 +08:00
. cloud - bg {
width : 100 % ;
}
. service - mesh {
display : flex ;
gap : 1 rem ;
justify - content : center ;
}
. service {
background : white ;
border : 1 px solid # e2e8f0 ;
padding : 0.8 rem ;
border - radius : 6 px ;
text - align : center ;
box - shadow : 0 4 px 6 px rgba ( 0 , 0 , 0 , 0.05 ) ;
display : flex ;
flex - direction : column ;
}
. service small {
color : # 64748 b ;
font - size : 0.7 rem ;
margin - top : 4 px ;
}
. comm - lines {
margin - top : 1 rem ;
font - size : 0.8 rem ;
color : # 94 a3b8 ;
text - align : center ;
border - top : 1 px dashed # cbd5e1 ;
width : 80 % ;
padding - top : 4 px ;
}
2026-01-18 10:24:35 +08:00
2026-01-18 12:21:49 +08:00
. function - cloud {
display : flex ;
flex - wrap : wrap ;
gap : 1 rem ;
justify - content : center ;
margin - bottom : 1.5 rem ;
}
. func - node {
background : # fef3c7 ;
border : 1 px solid # f59e0b ;
color : # b45309 ;
padding : 6 px 12 px ;
border - radius : 20 px ;
font - family : monospace ;
font - size : 0.8 rem ;
}
. baas - layer {
width : 100 % ;
background : # e0e7ff ;
padding : 0.5 rem ;
text - align : center ;
border - radius : 6 px ;
font - size : 0.8 rem ;
color : # 4338 ca ;
font - weight : bold ;
}
2026-01-18 10:24:35 +08:00
/* Ops Card */
2026-01-18 12:21:49 +08:00
. ops - card {
text - align : center ;
}
. ops - icon {
font - size : 4 rem ;
margin - bottom : 1 rem ;
}
. ops - title {
font - size : 1.2 rem ;
font - weight : bold ;
margin - bottom : 0.5 rem ;
color : var ( -- vp - c - text - 1 ) ;
}
. ops - desc {
font - size : 0.9 rem ;
color : var ( -- vp - c - text - 2 ) ;
line - height : 1.5 ;
}
2026-01-18 10:24:35 +08:00
/* Transitions */
2026-01-18 12:21:49 +08:00
. fade - slide - enter - active ,
. fade - slide - leave - active {
transition : all 0.4 s ease ;
}
. fade - slide - enter - from {
opacity : 0 ;
transform : translateY ( 20 px ) ;
}
. fade - slide - leave - to {
opacity : 0 ;
transform : translateY ( - 20 px ) ;
}
< / style >