Trong bối cảnh công nghệ phát triển không ngừng, nhu cầu về các công cụ tạo form linh hoạt và hiệu quả ngày càng tăng cao. Mặc dù Google Forms là một công cụ phổ biến, nhưng đôi khi quá trình tạo form thủ công có thể tốn thời gian và cảm thấy lỗi thời. Vậy điều gì sẽ xảy ra nếu bạn có thể tạo form bằng cách trò chuyện với AI và đưa chúng vào hoạt động ngay lập tức?
Chúng tôi tự hào giới thiệu một giải pháp thay thế Google Forms hoàn toàn mới, được xây dựng với một điểm khác biệt lớn: khả năng tự lưu trữ và tính năng mã nguồn mở. Thay vì kéo và thả hoặc nhập liệu thủ công, bạn chỉ cần mô tả form mình muốn bằng ngôn ngữ tự nhiên, và hệ thống sẽ biến ý tưởng của bạn thành một form trực tuyến sẵn sàng nhận phản hồi.
Giải pháp này được xây dựng trên nền tảng công nghệ hiện đại, bao gồm Next.js, kết hợp với sức mạnh của mô hình ngôn ngữ lớn (LLM) thông qua C1 của Thesys và lưu trữ dữ liệu trên MongoDB. Đây không chỉ là một công cụ tiện lợi mà còn là một dự án mã nguồn mở, cho phép cộng đồng phát triển và tùy chỉnh theo nhu cầu riêng.
Bài viết này sẽ đi sâu vào kiến trúc, công nghệ và cách thức hoạt động của công cụ tạo form thông minh này, cung cấp cái nhìn toàn diện về quá trình phát triển và những lợi ích mà nó mang lại. Bạn có thể khám phá mã nguồn tại Kho lưu trữ GitHub.

Mục lục
Tầm Nhìn Đằng Sau Dự Án: Tạo Form Dễ Dàng Như Trò Chuyện
Ý tưởng cho dự án này nảy sinh từ nhận thức rằng việc tạo form thủ công, ngay cả với các công cụ phổ biến như Google Forms, vẫn còn khá rườm rà. Tại sao chúng ta không thể tạo một form đăng ký, khảo sát hay phản hồi chỉ bằng cách mô tả nó? Ví dụ, bạn chỉ cần nói: “Tôi muốn một form đăng ký với tên, email, mật khẩu và một ô nhập phản hồi.”
Mục tiêu là tạo ra một hệ thống nơi AI sẽ tiếp nhận mô tả này, tự động tạo ra đặc tả giao diện người dùng (UI spec) và hiển thị form ngay lập tức trên trình duyệt. Mỗi form sau đó sẽ có một URL riêng biệt để thu thập phản hồi, cùng với hệ thống xác thực dựa trên cookie đơn giản để đảm bảo chỉ quản trị viên mới có thể tạo, xem danh sách form và các phản hồi.
Điểm mấu chốt để hiện thực hóa tầm nhìn này là Thesys và API C1 của họ. C1 API giúp chuyển đổi mô tả ngôn ngữ tự nhiên thành các thành phần UI có cấu trúc một cách dễ dàng, mở ra khả năng xây dựng giao diện người dùng tạo sinh (Generative UI) theo thời gian thực.

Một ưu điểm vượt trội của giải pháp này so với các công cụ tạo form thương mại khác là khả năng tự lưu trữ (self-hosted). Điều này có nghĩa là toàn bộ dữ liệu form và các phản hồi của bạn sẽ nằm trong cơ sở dữ liệu riêng của bạn, mang lại quyền kiểm soát tối đa về quyền riêng tư và bảo mật.
Dự án ban đầu không nhằm giải quyết một vấn đề lớn mà tập trung vào việc thử nghiệm và tìm hiểu sâu hơn về cách các ứng dụng dựa trên trò chuyện và hệ thống Generative UI hoạt động. Nó chứng minh một phương pháp tiếp cận mới trong việc xây dựng ứng dụng, nơi sự tương tác trực quan với AI có thể thay đổi cách chúng ta tạo ra các công cụ số.
Cách Sử Dụng Ứng Dụng
Để bắt đầu với ứng dụng tạo form tự lưu trữ này, bạn chỉ cần thực hiện vài bước đơn giản:
- Fork kho lưu trữ: Truy cập kho lưu trữ GitHub và fork nó.
- Cấu hình biến môi trường: Đặt mật khẩu quản trị và các thông tin xác thực khác trong tệp
.envcủa bạn (tham khảo định dạng dưới đây). - Triển khai ứng dụng: Triển khai lên bất kỳ nhà cung cấp dịch vụ hosting nào (Vercel, Netlify, Render) hoặc máy chủ riêng của bạn.
- Đăng nhập: Truy cập đường dẫn
/loginvà nhập mật khẩu quản trị của bạn. - Tạo form: Sau khi đăng nhập thành công, bạn sẽ được chuyển hướng đến giao diện trò chuyện tại
/, nơi bạn có thể bắt đầu tạo form bằng cách mô tả chúng.
Bạn có thể sao chép tệp .env.example trong repo và cập nhật các biến môi trường:
THESYS_API_KEY=<khóa-api-thesys-của-bạn>
MONGODB_URI=<uri-mongodb-của-bạn>
THESYS_MODEL=c1/anthropic/claude-sonnet-4/v-20250930
ADMIN_PASSWORD=<mật-khẩu-quản-trị-của-bạn>
Nếu bạn muốn sử dụng các mô hình khác, bạn có thể tìm danh sách các mô hình ổn định được khuyến nghị cho môi trường production và cách tính phí trong tài liệu của Thesys.
Thiết Lập Thesys để Khởi Tạo UI
Cách dễ nhất để bắt đầu với Thesys là sử dụng CLI của họ, giúp thiết lập khóa API và tạo một template Next.js sẵn sàng sử dụng C1:
npx create-c1-app


Để hiểu rõ hơn về cách Thesys hoạt động (nền tảng cốt lõi của dự án):
- Cấu hình Client OpenAI: Cập nhật cấu hình client OpenAI để trỏ tới Thesys bằng cách đặt
baseURLlàapi.thesys.devvà cung cấpTHESYS_API_KEYcủa bạn. Bạn sẽ có một giao diện tương thích với OpenAI nhưng được hỗ trợ bởi Thesys. - Gọi Streaming Chat Completion: Đặt
stream: truecho phép phát các token dần dần về trình duyệt để hiển thị UI theo thời gian thực. - Xử lý Stream Phản hồi: Bằng cách gói luồng LLM thô trong trợ giúp
transformStream, chúng ta trích xuất các thay đổi nội dung đã được token hóa và chuyển chúng dưới dạng phản hồi HTTP-streamable.
// Chuẩn bị cuộc gọi Thesys API (tương thích OpenAI)
const client = new OpenAI({
baseURL: 'https://api.thesys.dev/v1/embed',
apiKey: process.env.THESYS_API_KEY,
})
const llmStream = await client.chat.completions.create({
model: process.env.THESYS_MODEL || 'c1/anthropic/claude-sonnet-4/v-20250930',
messages: messagesToSend,
stream: true,
})
const responseStream = transformStream(
llmStream,
(chunk) => chunk?.choices?.[0]?.delta?.content ?? '',
)
return new NextResponse(responseStream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
},
})
Bạn có thể thử nghiệm trực tiếp trên playground của Thesys.

Kiến Trúc và Bộ Công Nghệ Sử Dụng
Dự án này được xây dựng trên một bộ công nghệ mạnh mẽ và hiện đại, đảm bảo hiệu suất và khả năng mở rộng. Dưới đây là các thành phần chính:
- Next.js (App Router): Cung cấp hệ thống định tuyến, khả năng render phía máy chủ (SSR) và các API endpoint hiệu quả.
- Thesys GenUI SDK (`@thesysai/genui-sdk`): Thư viện JavaScript mạnh mẽ này hỗ trợ giao diện trò chuyện (C1Chat) và hiển thị các form được tạo (C1Component).
- C1 by Thesys (Mô hình Anthropic): Nền tảng AI cốt lõi giúp các mô hình ngôn ngữ lớn phản hồi bằng các schema UI tương tác dựa trên các prompt đầu vào.
- `@crayonai/stream`: Một thư viện cần thiết để truyền tải đầu ra từ LLM đến frontend theo thời gian thực, tạo ra trải nghiệm người dùng mượt mà.
- MongoDB và Mongoose: Được sử dụng để lưu trữ định nghĩa form và các phản hồi người dùng trong cơ sở dữ liệu NoSQL linh hoạt.
- Node.js (Next.js API routes + middleware): Xử lý logic backend cho các chức năng trò chuyện, CRUD (Tạo, Đọc, Cập nhật, Xóa) form và xác thực người dùng.
Để hiểu rõ hơn về cách Thesys hoạt động với C1 API và GenUI React SDK, bạn có thể tham khảo bài viết chuyên sâu: “Thesys React SDK: Biến phản hồi LLM thành giao diện người dùng thời gian thực”.

Cấu Trúc Dự Án Chi Tiết
Hầu hết mã nguồn của dự án nằm trong thư mục src, tuân theo cấu trúc của Next.js App Router và các API routes:
.
├── .env.example
├── .gitignore
├── LICENSE
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── tsconfig.json
├── middleware.ts
├── public/
└── src/
├── app/ # Next.js App Router
│ ├── api/ # Serverless API routes
│ │ ├── chat/route.ts # Chat endpoint
│ │ └── forms/ # Form CRUD + submissions
│ │ ├── [id]/ # Form-specific endpoints
│ │ │ ├── submissions/
│ │ │ │ ├── [submissionId]/
│ │ │ │ │ └── route.ts # Delete submission of a form
│ │ │ │ └── route.ts # GET form submissions
│ │ ├── create/route.ts # Create new form
│ │ ├── delete/route.ts # Delete form by ID
│ │ ├── get/route.ts # Get form by ID
│ │ ├── list/route.ts # List all forms
│ │ └── submit/route.ts # Handle form submission
│ │
│ ├── assets/ # Local fonts
│ ├── forms/
│ │ ├── [id]/ # Dynamic form route
│ │ │ ├── submissions/
│ │ │ │ └── page.tsx # Show all submissions for a form
│ │ │ └── page.tsx # Show a single form (renders via C1Component)
│ │ └── page.tsx # All forms listing page
│ │
│ ├── home/ # Landing page (when not logged in)
│ │ └── page.tsx
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
│
├── components/
│ ├──C1ChatWrapper.tsx
| ├──ClientApp.tsx
| ├──FormsListPage.ts
│ └──SubmissionsPage.tsx
│
└── lib/
├── dbConnect.ts # MongoDB connection helper
├── fonts.ts # Next.js font setup
├── models/ # Mongoose models
│ ├── Form.ts
│ └── Submission.ts
└── utils.ts
Các Tuyến Đường (Routes) Chính
Các Tuyến Đường Trang (Page Routes):
/home– Trang giới thiệu (hiển thị khi chưa đăng nhập)/login– Trang đăng nhập quản trị viên/– Giao diện trò chuyện (yêu cầu xác thực)/forms– Liệt kê tất cả các form/forms/[id]– Hiển thị một form cụ thể/forms/[id]/submissions– Liệt kê các phản hồi cho một form cụ thể
Các Tuyến Đường API (API Routes):
POST /api/login– Xác thực và thiết lập cookie phiênPOST /api/chat– Endpoint chat với AIGET /api/forms/list– Lấy tất cả các formPOST /api/forms/create– Tạo form mớiGET /api/forms/get– Lấy schema form theo IDDELETE /api/forms/delete– Xóa form theo IDPOST /api/forms/submit– Gửi phản hồi formGET /api/forms/[id]– Liệt kê các phản hồi cho một formDELETE /api/forms/[id]/submissions– Xóa một phản hồi theo ID
Tổng Quan Kiến Trúc Hệ Thống
Dưới đây là tổng quan kiến trúc cấp cao của dự án, minh họa luồng dữ liệu và tương tác giữa các thành phần chính:
┌───────────────────────────────┐
│ Giao diện Người dùng Trình duyệt │
│ (GenUI Chat & C1Component) │
└──────────────┬────────────────┘
│ HTTP Streamable
▼
┌───────────────────────────────┐
│ Lớp API Next.js │
│ (app/api/chat & app/api/forms)│
└──────────────┬────────────────┘
│
┌──────┴───────────┐
│ Thesys LLM │
│ (api.thesys.dev) │
└──────┬───────────┘
│ SSE stream of <content>…</content>
┌─────────────▼───────────────────────────────┐
│ Giao diện Người dùng Trình duyệt (render các chunk được stream) │
│ render chat + UI‐spec │
└─────────────────────────────────────────────┘
┌───────────────────────────────┐
│ Lớp API Next.js │
│ (app/api/forms/* routes) │
└──────────────┬────────────────┘
│ Mongoose ORM
▼
┌───────────────────────────────┐
│ MongoDB (thông qua Mongoose) │
└───────────────────────────────┘
Kiến trúc này mô tả rõ ràng cách giao diện người dùng tương tác với lớp API của Next.js, lớp này lại giao tiếp với Thesys LLM để tạo ra các thành phần UI. Đồng thời, lớp API cũng quản lý việc lưu trữ và truy xuất dữ liệu form cũng như các phản hồi từ MongoDB thông qua Mongoose ORM.
Luồng Dữ Liệu: Từ Prompt → Form → Lưu
Quá trình tạo form, hiển thị và lưu trữ diễn ra thông qua một luồng dữ liệu liền mạch, bắt đầu từ yêu cầu của người dùng và kết thúc bằng việc lưu trữ form đã tạo.
Quá Trình Tạo Form Bằng AI
Khi người dùng tương tác để tạo form, luồng dữ liệu sẽ diễn ra như sau:
┌─────────┐ ┌───────────────┐ ┌──────────────────┐ ┌───────────┐
│ Người dùng │ │ Giao diện Trình duyệt │ │ Next.js API │ │ Thesys │
│ │ │(C1Chat/C1Comp)│ │ (/api/chat) │ │ LLM │
└───┬─────┘ └──────┬────────┘ └───────┬──────────┘ └────┬──────┘
│ "Tạo một │ │ │
│ form liên hệ" │ │ │
└───────────► │ POST /api/chat │ │
└───────────────────────►│ chat.completions.create(stream) ──────────► │
│ │
│ ◄── HTTP chunks <content>... (Streamable) ─── │
│ │
│ trênEnd → cache spec ───► │
│ │
Người dùng nhập một prompt vào widget chat (C1Chat). Frontend gửi tin nhắn người dùng đến API chat (/api/chat). API này xây dựng một yêu cầu LLM, thêm vào một system prompt để mô hình phát ra UI specs JSON trong thẻ <content>...</content>, sau đó stream phản hồi trở lại client. Khi các chunk dữ liệu đến, @crayonai/stream chuyển chúng vào component chat trực tiếp và tích lũy đầu ra.
Quá Trình Lưu Trữ Form
Khi người dùng quyết định lưu form, luồng dữ liệu tiếp tục:
┌─────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────┐ ┌───────────┐
│ Người dùng │ │ Giao diện Trình duyệt │ │ Next.js API │ │ Thesys │ │ MongoDB │
│ │ │ render form UI trực tiếp │ │ (onEnd) │ │ │ │ │
│ xem form │ │ │ │ kiểm tra "lưu" │ │ │ │ │
└───┬─────┘ └──────┬────────┘ └───────┬───────┘ └───────────┘ └───────┬───┘
│ "Lưu form này" │ │ │ │
└───────────► │ POST /api/chat │ │ │
└────────────────────► │ trênEnd → trích xuất title/desc ───► │
│ │ tạo │
│ │ tài liệu Form │
│ └──────► Form đã tạo thành công
│
│ ◄──────── HTTP stream hoàn thành ──────────────┘
▼
Giao diện Trình duyệt hiển thị "Form đã lưu thành công"
Sau khi stream kết thúc, API trích xuất payload <content>...</content>, phân tích cú pháp JSON và lưu trữ schema mới nhất. Nếu người dùng có ý định lưu, API sẽ POST schema đã lưu trong cache cùng với tiêu đề và mô tả đến /api/forms/create. Form sau đó được lưu vào MongoDB và người dùng nhận thông báo thành công.
Cách Thức Hoạt Động (Dưới Lớp Vỏ)
Dưới đây là phần giải thích chi tiết về các luồng người dùng chính, từ việc trò chuyện, tạo form, hiển thị form và mọi thứ liên quan.
System Prompt: Bộ Não Của Trợ Lý Tạo Form
System prompt là hướng dẫn cốt lõi cho mô hình LLM, định hình cách nó phản hồi và tương tác với người dùng. Nó đóng vai trò như một bộ quy tắc để đảm bảo mô hình hoạt động như một trợ lý tạo form chuyên nghiệp:
const systemPrompt = `
You are a form-builder assistant.
Rules:
- If the user asks to create a form, respond with a UI JSON spec wrapped in <content>...</content>.
- Use components like "Form", "Field", "Input", "Select" etc.
- If the user says "save this form" or equivalent:
- DO NOT generate any new form or UI elements.
- Instead, acknowledge the save implicitly.
- When asking the user for form title and description, generate a form with name="save-form" and two fields:
- Input with name="formTitle"
- TextArea with name="formDescription"
- Do not change these property names.
- Wait until the user provides both title and description.
- Only after receiving title and description, confirm saving and drive the saving logic on the backend.
- Avoid plain text outside <content> for form outputs.
- For non-form queries reply normally.
<ui_rules>
- Wrap UI JSON in <content> tags so GenUI can render it.
</ui_rules>
`
Như bạn có thể thấy, prompt này hướng dẫn mô hình trở thành một Trợ lý Xây dựng Form, với các quy tắc rõ ràng về cách tạo UI JSON, cách xử lý ý định lưu form và cách tương tác với người dùng để thu thập thông tin cần thiết.

Bạn có thể tham khảo tài liệu chính thức của Thesys để biết hướng dẫn từng bước về cách thêm system prompt vào ứng dụng của bạn.
Thiết Kế Form Dựa Trên Trò Chuyện
- Người dùng nhập một prompt vào widget chat (C1Chat).
- Frontend gửi tin nhắn của người dùng qua SSE (
fetch('/api/chat')) đến API chat. /api/chatxây dựng một yêu cầu LLM:- Thêm vào một system prompt hướng dẫn mô hình phát ra UI specs JSON bên trong
<content>…</content>. - Stream các phản hồi trở lại client.
- Thêm vào một system prompt hướng dẫn mô hình phát ra UI specs JSON bên trong
- Khi các chunk dữ liệu đến,
@crayonai/streamchuyển chúng vào component chat trực tiếp và tích lũy đầu ra. - Khi stream kết thúc, API thực hiện:
- Trích xuất payload
<content>…</content>. - Phân tích cú pháp nó thành JSON.
- Cache schema mới nhất (trong một biến global) cho các hành động “lưu” tiềm năng.
- Nếu người dùng có ý định lưu, nó POST schema đã cache cộng với tiêu đề/mô tả đến
/api/forms/create.
- Trích xuất payload
export async function POST(req: NextRequest) {
try {
const incoming = await req.json()
// Chuẩn hóa cấu trúc client...
const messagesToSend = [
{ role: 'system', content: systemPrompt },
...incomingMessages,
]
const client = new OpenAI({
baseURL: 'https://api.thesys.dev/v1/embed',
apiKey: process.env.THESYS_API_KEY,
})
const llmStream = await client.chat.completions.create({
model:
process.env.THESYS_MODEL ||
'c1/anthropic/claude-sonnet-4/v-20250930',
messages: messagesToSend,
stream: true,
})
const responseStream = transformStream(
llmStream,
(chunk) => chunk?.choices?.[0]?.delta?.content ?? '',
{
onEnd: async ({ accumulated }) => {
const rawSpec = Array.isArray(accumulated)
? accumulated.join('')
: accumulated
const match = rawSpec.match(/<content>([\s\S]+)<\/content>/)
if (match) {
const schema = JSON.parse(decodeHtmlEntities(match[1].trim()))
globalForFormCache.lastFormSpec = schema
}
if (isSaveIntent(incomingMessages)) {
const { title, description } = extractTitleDesc(incomingMessages)
await fetch(`${req.nextUrl.origin}/api/forms/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title,
description,
schema: globalForFormCache.lastFormSpec,
}),
})
}
},
}
) as ReadableStream<string>
return new NextResponse(responseStream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
},
})
} catch (err: any) {
/* …xử lý lỗi… */
}
}
Hình ảnh dưới đây minh họa giao diện trò chuyện, nơi bạn nhập mô tả để tạo form.

Lưu Trữ Form Mới
Việc lưu trữ form vào cơ sở dữ liệu được thực hiện thông qua một API route đơn giản:
- API route
POST /api/forms/create(serverless) nhận các thông tin{ title, description, schema }. - Nó gọi
dbConnect()để thiết lập kết nối MongoDB (với logic cache kết nối). - Một tài liệu
Formmới (Mongoose model) được ghi vào cơ sở dữ liệu với UI-schema JSON của bạn.
export async function POST(req: NextRequest) {
await dbConnect()
const { title, description, schema } = await req.json()
const form = await Form.create({ title, description, schema })
return NextResponse.json({ id: form._id, success: true })
}
Để hiển thị danh sách tất cả các form đã tạo, API route src\app\api\forms\list\route.ts được sử dụng:
export const runtime = 'nodejs'
import { NextResponse } from 'next/server'
import { dbConnect } from '@/lib/dbConnect'
import Form from '@/lib/models/Form'
export async function GET() {
await dbConnect()
const forms = await Form.find({}, '_id title description createdAt')
.sort({ createdAt: -1 })
.lean()
const formattedForms = forms.map((f) => ({
id: String(f._id),
title: f.title,
description: f.description,
createdAt: f.createdAt,
}))
return NextResponse.json({ forms: formattedForms })
}
Bạn có thể xem hình ảnh trang liệt kê form đã tạo.

Hiển Thị Form Đã Tạo
Sau khi form được tạo và lưu, nó có thể được hiển thị cho người dùng để thu thập phản hồi:
- Khách truy cập điều hướng đến
/forms/[id]. useEffect()của trang lấy schema đã lưu từGET /api/forms/get?id=[id].- Nó gói JSON thô trong
<content>…</content>và chuyển đến C1Component, thành phần này sẽ hiển thị các trường, input, select và nhiều hơn nữa.
Mỗi form được hiển thị tại src/app/forms/[id]/page.tsx:
useEffect(() => {
async function fetchForm() {
const res = await fetch(`/api/forms/get?id=${id}`)
const data = await res.json()
const wrappedSpec = `<content>${JSON.stringify(data.schema)}</content>`
setC1Response(wrappedSpec)
}
if (id) fetchForm()
}, [id])
if (!c1Response) return <div>Loading...</div>
return (
<C1Component
key={resetKey}
c1Response={c1Response}
isStreaming={false}
onAction={/* …xem phần tiếp theo… */}
/>
)
Hình ảnh dưới đây là một ví dụ về một form được tạo tự động và hiển thị.

Xử Lý Gửi Phản Hồi Form
Khi người dùng điền và gửi form, dữ liệu phản hồi sẽ được xử lý:
- Khi người dùng điền và gửi form,
C1Componentkích hoạt callbackonAction. - Callback này POST
{ formId, response }đến/api/forms/submit. - Máy chủ ghi một tài liệu
Submissionmới, liên kết trở lạiForm.
Dưới đây là Mongoose Model cho Submission:
const SubmissionSchema = new mongoose.Schema({
formId: { type: mongoose.Schema.Types.ObjectId, ref: 'Form' },
response: Object, // Dữ liệu đã điền (đã gửi) dưới dạng JSON
createdAt: { type: Date, default: Date.now },
})
export default mongoose.models.Submission ||
mongoose.model('Submission', SubmissionSchema)
Để hiển thị tất cả các phản hồi đã gửi, API route src\app\api\forms\[id]\submissions\route.ts được sử dụng:
import { NextRequest, NextResponse } from 'next/server'
import { dbConnect } from '@/lib/dbConnect'
import Submission from '@/lib/models/Submission'
export async function GET(
req: NextRequest,
context: { params: Promise<{ id: string }> }
) {
await dbConnect()
const { id } = await context.params
try {
const submissions = await Submission.find({ formId: id }).sort({
createdAt: -1,
})
return NextResponse.json({ success: true, submissions })
} catch (err) {
console.error('Lỗi khi lấy submissions:', err)
return NextResponse.json(
{ success: false, error: 'Không thể lấy submissions' },
{ status: 500 }
)
}
}
Hình ảnh dưới đây là giao diện xem các phản hồi form, nơi bạn có thể xóa các mục hoặc xuất tất cả phản hồi sang định dạng Markdown.

Quản Lý Form: Liệt Kê & Xóa
Trong khu vực được xác thực, bạn có thể quản lý các form của mình một cách dễ dàng. Các API route chuyên biệt cho phép bạn liệt kê tất cả các form, xem hoặc xóa từng form, và kiểm tra các phản hồi.
Đoạn mã sau đây minh họa cách liệt kê tất cả các form (src/app/api/forms/list/route.ts):
export async function GET() {
await dbConnect()
const forms = await Form.find({}, '_id title description createdAt')
.sort({ createdAt: -1 })
.lean()
const formattedForms = forms.map(f => ({
id: String(f._id),
title: f.title,
description: f.description,
createdAt: f.createdAt,
}))
return NextResponse.json({ forms: formattedForms })
}
Và đây là đoạn mã để xóa một form (src/app/api/forms/delete/route.ts):
export async function DELETE(req: NextRequest) {
await dbConnect()
try {
const { id } = await req.json()
if (!id) {
return NextResponse.json(
{ success: false, error: 'Cần có ID Form' },
{ status: 400 }
)
}
await Form.findByIdAndDelete(id)
return NextResponse.json({ success: true })
} catch (err) {
console.error('Lỗi khi xóa form:', err)
return NextResponse.json(
{ success: false, error: 'Không thể xóa form' },
{ status: 500 }
)
}
}
Luồng Xác Thực Đơn Giản
Dự án sử dụng một cơ chế xác thực quản trị viên đơn giản để bảo vệ các chức năng tạo và xóa form:
- Endpoint Đăng nhập:
POST /api/loginkiểm tra{ password }được cung cấp vớiprocess.env.ADMIN_PASSWORD. Khi thành công, nó sẽ đặt một cookie bảo mật, HTTP-only có tênauth. - Bảo vệ bằng Middleware: Một tệp middleware (
middleware.ts) sẽ kiểm tra cookieauth. Nếu người dùng chưa được xác thực, họ sẽ được chuyển hướng từ/đến trang công khai/home. - Biến Môi trường: Bạn cần thêm
ADMIN_PASSWORDvào tệp.envcủa mình (cũng có trong.env.example) để route đăng nhập có thể xác minh thông tin đăng nhập.
Với phương pháp này, các trang liệt kê form, trang trò chuyện và trang xem phản hồi đều được bảo vệ, chỉ cho phép quản trị viên truy cập.

Kết Luận và Hướng Phát Triển Tương Lai
Dự án giải pháp thay thế Google Forms tự lưu trữ và mã nguồn mở này đã đạt được mục tiêu ban đầu: biến việc tạo form từ một tác vụ thủ công thành một cuộc trò chuyện trực quan với AI. Bạn nói, AI xây dựng, và chỉ trong tích tắc, bạn đã có một form hoạt động.
Mặc dù đã có những thành công nhất định, vẫn còn nhiều tiềm năng để cải thiện và mở rộng. Một số lĩnh vực cần phát triển trong tương lai bao gồm: xác thực schema tốt hơn, hỗ trợ phiên bản form, và khả năng hỗ trợ đa người dùng. Những cải tiến này sẽ nâng cao tính ổn định, linh hoạt và khả năng ứng dụng của công cụ.
Chúng tôi hy vọng công cụ này sẽ truyền cảm hứng cho nhiều nhà phát triển khám phá tiềm năng của AI tạo sinh trong việc xây dựng các ứng dụng thực tế. Hãy cho chúng tôi biết suy nghĩ của bạn về ứng dụng này trong phần bình luận.
Cảm ơn bạn đã đọc! Chúc bạn một ngày tốt lành!
Bạn có thể xem thêm các dự án của tôi tại anmolbaranwal.com. Cảm ơn bạn đã đọc! 🥰
Theo dõi trên X (Twitter) | GitHub | LinkedIn




