跪拜 Guibai
← Back to the summary

Why Vue3 + NestJS + TypeScript Is the Fastest Path to AI Agents for Frontend Devs

1.png Follow the public account: 糖墨夕

Nine out of ten AI Agent tutorials on the market use Python. This is not a problem in itself; the Python ecosystem is indeed the most mature in the AI field — frameworks like LangChain, LlamaIndex, and AutoGen were all originally Python versions. But the problem is — you are a frontend developer, and your strongest language is JavaScript/TypeScript, not Python.

If you try to learn Agent development, Python, Python's web frameworks (FastAPI, Flask), Python's asynchronous programming (asyncio), Python's type system (Pydantic), and Python's deployment methods (Gunicorn, Uvicorn) all at the same time... the learning curve is as steep as a cliff. And after learning it, the Python code is disconnected from your existing frontend projects — you can't use TypeScript for the frontend and Python for the backend in the same project, or rather you can, but the maintenance cost is too high, requiring two sets of type definitions.

So in this booklet, we have chosen a most frontend-friendly tech stack:

Frontend: Vue3 (Composition API + TypeScript + Pinia) └── You are already using it, no extra learning needed, just use the tools you are familiar with Backend: NestJS (Node.js enterprise-level framework) └── Uses TypeScript, the same language as the frontend, decorator style similar to Vue3's <script setup> AI Layer: LangChain.js + OpenAI SDK / Vercel AI SDK └── Native TypeScript support, API almost identical to the Python version, no need to switch languages Global: TypeScript └── Shared types across frontend and backend, one set of interface definitions used on both sides, type errors caught at compile time

This combination has several hardcore advantages, let's break them down one by one:

Advantage 1: Full-stack TypeScript, Type Safety Throughout

Have you ever encountered this scenario: the backend changes the return format of an API, the frontend doesn't follow suit, and after going live, the frontend throws a bunch of undefined is not a function errors, and after troubleshooting for half a day, you find out a field name changed? This is the cost of inconsistent types between frontend and backend.

With full-stack TypeScript, you can extract type definitions into a shared package:

// shared/types.ts —— Shared type definitions for frontend and backend
// Put in a separate package, imported by both frontend and backend

/** Chat message */
export interface ChatMessage {
  id: string
  role: 'user' | 'assistant' | 'system' | 'tool'
  content: string
  toolCalls?: ToolCall[]
  createdAt: string
}

/** Tool call record */
export interface ToolCall {
  id: string
  name: string
  arguments: Record<string, any>
  result?: string
  status: 'pending' | 'running' | 'done' | 'error'
}

/** Agent configuration */
export interface AgentConfig {
  model: string                      // Model used
  temperature: number                // 0-2, controls randomness
  maxTokens: number                  // Maximum output tokens
  systemPrompt: string               // System prompt
  tools: ToolDefinition[]            // List of available tools
}

/** Tool definition */
export interface ToolDefinition {
  name: string
  description: string
  parameters: Record<string, any>
}

/** Agent response (streaming) */
export interface AgentStreamChunk {
  type: 'text' | 'tool_call' | 'tool_result' | 'error' | 'done'
  content?: string
  toolCall?: ToolCall
  error?: string
}

The frontend uses ChatMessage to render the message list, and the backend uses ChatMessage to build LLM requests. If the backend changes a field in ChatMessage, the frontend compilation will fail immediately; you won't wait until going live to discover it. Type safety ensures frontend-backend consistency right from the development stage.

Advantage 2: NestJS's Modularity, Naturally Suited for Agent Architecture

NestJS is a Node.js framework written in TypeScript, designed with inspiration from Angular's dependency injection and modularity concepts. Its core concepts are Module, Controller, Provider, which perfectly correspond to the various components of an Agent:

NestJS Concept Agent Component Responsibility Description
AgentModule Agent Main Control Coordinates LLM, tools, memory, the main entry point for handling user requests
LlmModule Brain (LLM) Encapsulates calls to models like OpenAI / Claude / DeepSeek, providing a unified interface
ToolModule Tools Registers and manages tools the Agent can call, supports dynamic registration
MemoryModule Memory Conversation history storage, vector database integration, long-term memory management
ChatModule Chat Interface Provides SSE streaming interface, WebSocket, REST API

Each module has its own responsibility and does not interfere with others. Need to add a new feature? Just create a new Module. Moreover, NestJS's dependency injection allows you to easily swap implementations — for example, switching from OpenAI to DeepSeek only requires changing the Provider in LlmModule, with no changes needed elsewhere. This design philosophy is the same as Vue3's "Composition API, separation of concerns."

Let's look at what an actual NestJS Agent module looks like:

// ─── agent.module.ts ───
// Entry point for the Agent module, declares dependencies
import { Module } from '@nestjs/common'
import { AgentController } from './agent.controller'
import { AgentService } from './agent.service'
import { LlmModule } from '../llm/llm.module'
import { ToolModule } from '../tool/tool.module'
import { MemoryModule } from '../memory/memory.module'

@Module({
  imports: [LlmModule, ToolModule, MemoryModule],
  controllers: [AgentController],
  providers: [AgentService],
  exports: [AgentService]
})
export class AgentModule {}

// ─── agent.controller.ts ───
// Externally exposed API interface
import { Controller, Post, Body, Sse } from '@nestjs/common'
import { AgentService } from './agent.service'
import { Observable } from 'rxjs'

@Controller('api/agent')
export class AgentController {
  constructor(private readonly agent: AgentService) {}

  // SSE streaming interface —— frontend consumes with EventSource or fetch
  @Sse('chat')
  chat(@Body() body: { message: string; sessionId: string }): Observable<any> {
    return this.agent.chatStream(body.message, body.sessionId)
  }

  // Regular REST interface (non-streaming)
  @Post('chat/sync')
  async chatSync(@Body() body: { message: string; sessionId: string }) {
    return { reply: await this.agent.chat(body.message, body.sessionId) }
  }
}

// ─── agent.service.ts ───
// Agent core logic
import { Injectable } from '@nestjs/common'
import { LlmService } from '../llm/llm.service'
import { ToolService } from '../tool/tool.service'
import { MemoryService } from '../memory/memory.service'
import { Observable } from 'rxjs'

@Injectable()
export class AgentService {
  constructor(
    private readonly llm: LlmService,
    private readonly tool: ToolService,
    private readonly memory: MemoryService
  ) {}

  // Non-streaming conversation
  async chat(userMessage: string, sessionId: string): Promise<string> {
    // 1. Load history memory
    const history = await this.memory.getHistory(sessionId)

    // 2. Let LLM decide: should it call a tool?
    const decision = await this.llm.decide(userMessage, history, this.tool.getDefinitions())

    // 3. If a tool is needed, execute the tool call
    if (decision.needsTool) {
      const toolResult = await this.tool.execute(decision.toolCall)

      // Save tool call record to memory
      await this.memory.saveToolCall(sessionId, decision.toolCall, toolResult)

      // Send tool result to LLM to generate final response
      return this.llm.generateFinalResponse(userMessage, toolResult, history)
    }

    // 4. No tool needed, return LLM's response directly
    await this.memory.saveMessage(sessionId, { role: 'user', content: userMessage })
    await this.memory.saveMessage(sessionId, { role: 'assistant', content: decision.content })
    return decision.content
  }

  // Streaming conversation (SSE)
  chatStream(userMessage: string, sessionId: string): Observable<any> {
    // Returns an Observable, NestJS automatically handles SSE format
    return new Observable((subscriber) => {
      this.llm.streamDecide(userMessage, this.tool.getDefinitions())
        .subscribe({
          next: (chunk) => subscriber.next({ data: chunk }),
          error: (err) => subscriber.error(err),
          complete: () => subscriber.complete()
        })
    })
  }
}

The structure is clear, and responsibilities are distinct. Vue3 frontend developers will understand it at a glance — isn't this just "componentization" for the backend? A Module is a component, a Provider is a Composable, and a Controller is a route. Each component manages its own affairs and collaborates through dependency injection (similar to Vue's inject).

Advantage 3: Low Learning Cost, One Tech Stack Rules Them All

Let's do the math and compare the learning costs of the two routes:

What to Learn Python Route TypeScript Route (This Booklet)
Programming Language Python syntax, decorators, context managers, generators Already known
Web Framework FastAPI or Flask, routing, middleware, dependency injection NestJS (learn one new framework, but concepts align with Vue3)
Async Programming asyncio, async/await (Python's async model differs from JS) Already known (JS's async/await)
Type System Pydantic, Type Hints Already known (TypeScript)
Package Management pip, poetry, virtual environments Already known (npm/pnpm)
Deployment Gunicorn + Uvicorn + Nginx PM2 / Docker + Nginx (same as Node.js deployment)
AI Framework LangChain (Python) LangChain.js (API almost identical, just different language)

With the TypeScript route, you only need to learn one new thing: NestJS. You already know Vue3, you already know TypeScript, and you are already very familiar with the Node.js ecosystem (npm, ESLint, Prettier, Vite, Vitest). In other words, 80% of your learning effort is spent on Agent development itself, not on learning a new language + new framework + new ecosystem.

Think about it from another angle: if you learn Agent with Python now, your daily time allocation would roughly be:

Time allocation for the Python route: 30% learning Python syntax and ecosystem (pip, venv, asyncio, Pydantic) 25% learning the FastAPI framework (routing, middleware, dependency injection) 25% learning Agent itself (tool calling, memory, RAG, workflows) 20% troubleshooting (bugs caused by thinking differences between Python and TypeScript)

Time allocation for the TypeScript route: 15% learning NestJS (one framework, but concepts align with Vue3) 65% learning Agent itself (tool calling, memory, RAG, workflows) 20% troubleshooting (Agent development pitfalls, language-agnostic)

It's clear at a glance — with the TypeScript route, you spend 65% of your time learning Agent itself, not languages and frameworks. For a time-pressed frontend developer, this is crucial. You still have to work during the day and can only study at night and on weekends; every minute counts.

And there's a hidden advantage: the process of learning NestJS is itself a training in "backend thinking." Previously, you might have only written frontend code and were unfamiliar with concepts like backend dependency injection, middleware, and database ORMs. But after learning NestJS, you'll not only know how to write Agents but also how to write backends — it's like a buy-one-get-one-free deal: learn one skill, gain two.

A real learning comparison

Suppose you want to learn the "Agent calling tools" feature.

With the Python route, you need to: first learn Python's async/await (different model from JS, easy to stumble), then learn how FastAPI defines routes and dependency injection, then learn how Pydantic defines parameter validation models, then learn how asyncio handles concurrent calls. Just these prerequisites might take one or two weeks.

With the NestJS route, you only need to: write a @Post() decorator in NestJS's Controller, write async/await in the Service (exactly the same as API calls in Vue3), and declare dependencies in the Module. You can write a working Agent API on the very first day.

This isn't because NestJS is so great, but because you are already familiar enough with the TypeScript ecosystem; you just need to migrate your existing knowledge to a new scenario.

Bonus: The AI SDK Ecosystem is Increasingly Friendly to TypeScript

From 2024 to 2026, the TypeScript/JavaScript AI ecosystem has developed very rapidly. Previously, many AI tools only had Python versions; now, almost all have TypeScript versions:

Frankly, the TypeScript AI ecosystem is mature enough; you absolutely don't need to learn Python to do AI development. Use your most familiar language to do cutting-edge things — this is the core design philosophy of this booklet.

Of course, if you're interested later, learning Python isn't a bad thing. Python is indeed stronger than TypeScript in data processing, model training, and scientific computing. But that's for "advanced" stages, not something to consider when "getting started." First, master the TypeScript route; once you have a complete understanding of Agent development, learning Python will be the icing on the cake, not a timely help.

What will this booklet guide you to build? — Roadmap Overview

This booklet has a total of 15 chapters, divided into four phases. Each chapter revolves around a core concept, with code, analogies, pitfall records, and real experiences of "how long I got stuck here." I won't pile up a bunch of theory but will guide you from start to finish, step-by-step, to build a working AI Agent application.

Here is the complete roadmap:

Phase 1: Laying the Foundation (Chapters 1-3)

In this phase, we won't write complex code yet but will clarify the concepts. Many people jump straight into coding without understanding what an LLM or a Token is, get stuck halfway, and find themselves in a dilemma. Sharpening the axe does not delay the work of cutting wood; these three chapters are the "sharpening."

Chapter Content What you will understand
Chapter 1 (current) Why you should learn AI Agent? The advantages of frontend in the AI era, tech stack selection, a panoramic view of the learning path
Chapter 2 What exactly is an AI Agent? Using everyday scenarios like food delivery, cooking, and flight booking to clearly explain the four core concepts of an Agent (Brain, Tools, Memory, Planning), guaranteed you can explain it to a friend after reading
Chapter 3 Large Language Models: The Agent's "Brain" Concepts like Token, Temperature, Context Window, System Prompt, run through with TypeScript code to thoroughly understand the "temperament" of an LLM

Phase 2: Core Skills (Chapters 4-7)

This phase is the "internal strength" of Agent development. After completing these four chapters, you will have mastered all the core routines of Agent development and can build a fully functional Agent on your own.

Chapter Content What you will write
Chapter 4 Prompt Engineering: How to talk to AI properly A reusable Prompt template system, supporting role setting, anti-injection, dynamic parameters, Few-shot examples
Chapter 5 Tool Calling: The Agent's "Hands" A tool registry where the Agent can automatically discover and call tools, supporting weather checks, web searches, email sending, database operations
Chapter 6 Memory System: The Agent's "Brain" Conversation history management + vector database integration (Chroma/Pinecone), the Agent can remember what you said and maintain memory across sessions
Chapter 7 RAG: Connecting your knowledge base to the Agent A document Q&A system, feeding PDFs/documents/web pages to the Agent so it can answer professional questions only known within your company

"Milestone" after completing Phase 2

By the end of Chapter 7, you will be able to write an "intelligent customer service that can look up information, call tools, and has memory." Although the interface might still be relatively simple, the core logic will be complete. This demo, as your project experience, will definitely be a plus on your resume.

Phase 3: Practical Advanced (Chapters 8-11)

This phase ramps up the intensity, using LangChain.js and LangGraph to build real production-grade Agents. After these four chapters, your Agent will no longer be a "toy" but a "tool" capable of handling complex business logic.

Chapter Content What you will build
Chapter 8 Introduction to LangChain.js Use LangChain.js's Chain and Agent abstractions to quickly build Agent prototypes and understand why a framework is needed
Chapter 9 Building an Agent Backend with NestJS A complete NestJS Agent API service, supporting streaming SSE responses, JWT authentication, rate limiting, and logging
Chapter 10 LangGraph Workflow Orchestration Orchestrate complex Agent tasks in a "graph" manner, supporting conditional branching, loops, pause/resume, and human-machine collaboration
Chapter 11 Multi-Agent Collaboration Multiple Agents working together: one for searching, one for analyzing, one for writing reports, as efficient as a team

Phase 4: Full-Stack Closure (Chapters 12-15)

The final step is to package the Agent into a complete full-stack application, connecting the entire chain from development to deployment.

Chapter Content What you will accomplish
Chapter 12 MCP Protocol: The USB-C of the AI World Unify tool calling standards, hand-write an MCP Server, allowing the Agent to connect to any MCP-compatible tool ecosystem
Chapter 13 Vue3 Full-Stack Practice: Frontend-Backend Integration A complete AI chat interface, SSE streaming response, real-time display of Agent's thinking process, tool calls, Markdown rendering
Chapter 14 Deployment: Running the Agent in Production Docker containerization, Redis caching, Nginx reverse proxy, API cost control, log monitoring, canary releases
Chapter 15 Where to go next? 2026 AI Agent trends, advanced learning paths, recommended resources, open-source projects, communities

The entire roadmap, from concept to code, from standalone to production, has corresponding TypeScript code at every step. You don't need to learn Python, don't need to read papers, don't need to read obscure academic articles. Follow along and type the code, and you can master AI Agent development from zero to one.

How to read this booklet most efficiently?

Here are a few practical tips to help you avoid detours:

Additionally, this booklet will contain many "pitfall records" — these are all pitfalls I have genuinely stepped into during actual development. For example, "Why isn't the LLM calling my tools?" "Why are the RAG search results irrelevant?" "Why is token consumption so fast?" When you see these pitfall records, don't skip them — each pitfall can save you at least half a day. Moreover, pitfall records usually include both "why this happens" and "how to solve it"; understanding the "why" allows you to troubleshoot similar problems yourself in the future.

One more small suggestion: find a study buddy. If you have a colleague or friend also learning AI Agent, team up with them. Two people urging each other on and answering each other's questions can double the learning efficiency. If you really can't find a buddy, you can ask questions in the GitHub repository's Issues section or find fellow learners in relevant tech communities. One person goes fast, a group goes far — this saying is especially applicable when learning new technology.

What will you be able to do after finishing this booklet?

After completing the 15 chapters, you will no longer be a "frontend developer who only writes pages" but a full-stack engineer capable of independently developing AI applications. Specifically, you will be able to handle the following real-world scenarios:

Scenario 1: Intelligent Customer Service System

This is the most classic AI Agent application and what most companies are currently building. Feed all your product documentation, FAQs, historical tickets, and customer service scripts to the Agent, and it can automatically answer user questions. When it encounters a problem it cannot solve, it automatically transfers to a human agent and sends the conversation summary along, ensuring a seamless handoff.

And because it has memory, it can remember what the user previously asked, not answering each time like an amnesiac goldfish. For example, if a user says, "Where is the logistics for that order I asked about last time?", the Agent can trace back to the previous conversation, find the order number, and then check the logistics.

Technical points: RAG knowledge base + Tool calling (check order status, check logistics) + Multi-turn conversation memory + Human-machine collaboration.

Scenario 2: Data Analysis Assistant

"Help me analyze last month's sales data, find the three categories with the most severe sales decline, and then give some improvement suggestions." — The user says one sentence, and the Agent automatically queries the database, generates charts, and writes an analysis report, a one-stop service.

This scenario is particularly suitable for internal tools. Previously, a data analyst would spend half a day writing SQL, making charts, and writing reports; now, it's done with one sentence. And the Agent can also ask follow-up questions — "What do you think might be the reason for the decline? Do you want me to further analyze competitor data?"

Technical points: Tool calling (SQL queries, chart generation) + Multi-step workflow orchestration + LangGraph.

Scenario 3: Code Review Assistant

Connect a Git repository to the Agent. Every time a PR is submitted, the Agent automatically reviews the code, points out potential issues, gives optimization suggestions, checks code style, and can even automatically generate unit tests. Frontend developers understand frontend code pain points best — the Agent you write will definitely understand the actual needs of frontend better than general-purpose tools.

For example, the Agent can identify that "this watch is missing immediate: true, which might cause state inconsistency on the first render," or "this Pinia Store's action directly manipulates the DOM and should be extracted into a component." These are frontend-specific pitfalls that general AI tools might not recognize.

Technical points: Tool calling (Git API, static code analysis) + Custom Prompt templates + Knowledge base (team coding standards).

Scenario 4: Personal Knowledge Butler

Feed all your saved articles, written notes, reading excerpts, and meeting minutes to the Agent, and it becomes your exclusive "second brain." You ask, "Where is that article I saw last time about Vue3's reactivity principle? It was roughly about Proxy and Reflect?" — The Agent responds instantly, faster than you searching through your bookmarks and notes yourself.

Going further, you can ask the Agent to summarize — "Help me summarize all the articles I've read about AI in the last three months and extract 5 key trends." — The Agent automatically searches your knowledge base and makes a summary.

Technical points: RAG + Vector database + Long-term memory management + Document parsing.

Scenario 5: Automated Workflow

"Every morning at 9 AM, help me summarize yesterday's user feedback, sort by urgency, and then send it to the team group." — The Agent executes on a schedule, automatically calling multiple tools, reading the feedback database, using the LLM to analyze urgency, formatting it into a message, and sending it to Feishu/DingTalk/WeCom.

The key to this scenario is "reliability" — the Agent cannot make mistakes; if it fails to send one day, you must receive an alert. So error handling, retry mechanisms, and status monitoring need to be added.

Technical points: Scheduled tasks (Cron) + Workflow orchestration + Multi-tool chaining + Error handling + Monitoring and alerting.

Besides these five scenarios, there are many more possibilities. For example, making an "AI interviewer" to help HR screen resumes, making an "AI tutor" to help students with questions, making an "AI ops" to automatically handle server alerts. Once you master the core routines of Agent development, any scenario that requires "understanding natural language + executing operations" can be solved with an Agent. This is the charm of Agent development — it's not a specific technology, but a brand new "way of solving problems."

More importantly, these scenarios are not things that "will happen in the future." Right now, in 2026, a large number of companies are already implementing these applications. E-commerce is using intelligent customer service, finance is using data analysis assistants, education is using AI tutors, and healthcare is using AI consultations. After finishing this booklet, you can directly participate in these projects. And if you don't learn, five years from now you might still be writing CRUD pages, while your peers are already leading AI product teams.

And these scenarios are not "only achievable after finishing 15 chapters"

Starting from Chapter 5, after each chapter, you can write a small working demo. For example, after Chapter 5 (Tool Calling), you can write an "Agent that checks the weather for you." After Chapter 7 (RAG), you can write an "Agent that answers questions about your documents." After Chapter 9 (NestJS), you can package this Agent into an API service. It's not that you can only start after 15 chapters, but rather learn and build simultaneously, with output at each chapter, and each output can be directly added to your resume.

What do you need to prepare before starting?

Just three things, which you should already have:

If you have absolutely zero foundation in NestJS, don't worry. Chapter 9 will specifically cover the basics of NestJS, from routing, middleware, Guards, Interceptors to dependency injection, ensuring you can keep up. And because you already know Vue3, many concepts in NestJS align with Vue3:

Additionally, you need an account that can call LLM APIs. It is recommended to use OpenAI (GPT-4o or GPT-4o-mini) or DeepSeek (much cheaper, and the results are also very good, especially for Chinese scenarios). If you really don't want to spend money, you can also use local Ollama to run open-source models (like Llama 3, Qwen 2.5); Chapter 3 will teach you how to configure it. Don't worry about API call costs — using the cheapest model during the development phase is enough, just a few bucks a month.

Finally, one more thing: the code repository for this booklet. The complete code for each chapter can be found on GitHub; you don't need to create a new project from scratch, just clone it and run it. If you get stuck in a certain chapter, or a certain code example doesn't run, go to the repository, find the code for the corresponding chapter, and compare it to find the problem. The repository address is on the first page of this book.

Additionally, for all code examples in this booklet, I have tried my best to keep them "independently runnable." That is, you can copy a code block, slightly modify the API Key and configuration, and run it directly. You don't need to understand the content of the previous 5 chapters to understand the code in Chapter 6 — the code examples in each chapter are self-contained. Of course, conceptually, it is still recommended to read in order, as later concepts build on earlier ones.

Development Environment Suggestions

Although I said above "you only need three things," I still want to share my own preferred development environment configuration for your reference:

You don't need to install these tools in advance; I will remind you in the corresponding chapters when they are needed. Writing them here in advance is to give you a heads-up: the toolchain for Agent development highly overlaps with the toolchain you usually use for Vue3 projects; nothing is completely unfamiliar.

A few sincere words about AI anxiety

I know many frontend developers have been anxious recently — "Will AI replace frontend developers?" "Should I switch careers?" "Is there no future for frontend?"

My view is: AI will not replace frontend developers, but frontend developers who use AI will replace those who don't. This is not fear-mongering; it's a fact. Just like ten years ago, people who could do mobile development replaced those who could only do PC development; five years ago, people who could use Vue/React replaced those who could only use jQuery. With every technological wave, what gets eliminated is not a profession, but a certain outdated combination of skills.

Learning Agent now is not a "career change" but an upgrade to your skill tree. You are still a frontend developer, just with a powerful new weapon called "AI Agent" in your arsenal. This weapon allows you to evolve from "implementing requirements" to "creating products," from a "page slicer" to a "full-stack engineer capable of independently delivering AI applications." In the job market, the competitiveness between a "frontend developer who can write AI Agents" and a "frontend developer who can only write CRUD pages" is worlds apart.

Moreover, the AI Agent development track is still in its early stages. The earlier you enter, the easier it is to establish an advantage. If you wait until everyone starts learning in a year or two, it will be too late. Many companies are now shifting from "should we use AI" to "how to use AI well," and this process requires a large number of AI application developers — and these people are currently very scarce.

So, relax, but don't be lazy. Every chapter of this booklet will accompany you, and every step has code you can copy and run. You just need to follow along; after 15 chapters, you will be that "frontend developer who uses AI."

Comments

Top 3 of 4 from juejin.cn, machine-translated. The original thread is authoritative.

clarence1026

Learning Python isn't that hard for frontend devs either; you can pick up Python syntax gradually while building things.

糖墨夕

Only if you learn it deeply enough. Ideally the syntax should complement frontend skills, so NestJS and Node are a better fit.

Carrey493

Which booklet is it? Drop a link.

廾匸22

[Like]