Prototype có nhiệm vụ chứng minh ý tưởng. Repo sống có nhiệm vụ tồn tại qua nhiều tuần, nhiều người sửa, nhiều lần deploy, nhiều bug nhỏ. Hai thứ này không giống nhau.

Vibe coding rất mạnh ở giai đoạn prototype. Bạn mô tả app, agent dựng màn hình, nối vài flow, bạn click thử và sửa bằng feedback. Nhưng nếu prototype bắt đầu có user thật, dữ liệu thật, hoặc người khác phải maintain, câu hỏi đổi hẳn: không phải “app có chạy không”, mà là “repo này có sống nổi không”.

Không phải prototype nào cũng đáng harden. Nhiều prototype nên bị bỏ đi sau khi học được bài học. Nhưng nếu quyết định giữ, bạn cần một vòng chuyển từ vibe-coded output sang repo có chủ, có structure, có test tối thiểu, có setup/deploy rõ, và có phần được rewrite thủ công nếu cần.

Đừng harden mọi prototype

Sai lầm đầu tiên là xem mọi prototype chạy được như sản phẩm tương lai. Không phải.

Một prototype nên bỏ hoặc giữ nhẹ nếu:

  • Nó chỉ dùng để demo ý tưởng trong một buổi họp.
  • Data toàn mock.
  • Flow chính đã chứng minh là không có nhu cầu.
  • Tech stack được chọn vì agent dễ dựng, không phù hợp team.
  • Code quá rối và rewrite rẻ hơn sửa.
  • Không ai nhận trách nhiệm maintain.

Harden prototype tốn thời gian. Nếu app không có người dùng, không có business case, không có owner, thì đừng biến nó thành dự án dài hạn chỉ vì AI đã dựng nhanh.

Một câu hỏi thẳng:

Nếu AI không viết prototype này, mình có vẫn muốn đầu tư thêm hai tuần để làm nó thành sản phẩm không?

Nếu không, dừng lại. Bài học đã đủ.

Repo sống cần structure đọc được

Vibe-coded prototype thường có structure theo tiện tay: component lớn, file dài, helper nằm lẫn trong UI, naming không đều, route tạo nhanh, config nằm nhiều chỗ. Prototype vẫn chạy. Nhưng người sau đọc sẽ khó.

Structure sống được không cần enterprise. Nó cần boring và dễ đoán:

src/
  components/
  features/
  hooks/
  lib/
  pages/
  styles/

Hoặc structure khác tùy framework. Quan trọng là nhất quán với project. Nếu repo đã có pattern, follow pattern đó. Đừng để agent tự tạo architecture mới chỉ vì tutorial trên mạng hay dùng vậy.

Khi audit structure, tìm:

  • Component quá dài làm nhiều việc.
  • Helper nằm trong file UI nhưng dùng ở nhiều nơi.
  • Tên file mơ hồ như NewComponent, FinalPage, Utils2.
  • Folder trùng nghĩa.
  • File cũ không còn import.
  • Route thử nghiệm vẫn còn.
  • CSS hoặc assets không dùng.

Đừng refactor toàn bộ ngay. Sửa các điểm cản maintenance rõ nhất. Một prototype thành repo sống cần đủ sạch để người khác sửa tiếp, không cần đạt chuẩn hoàn mỹ.

Dead code là nợ review

Agent hay để lại code chết: component không dùng, state cũ, mock data, handler bỏ dở, comment “TODO”, route test, CSS class không còn gắn vào UI. Dead code không chỉ làm repo xấu. Nó làm reviewer không biết phần nào còn quan trọng.

Trước khi gọi prototype là repo sống, search các dấu hiệu:

mock
dummy
sample
TODO
FIXME
console.log
debugger
localhost
test-only

Không xoá mù. Có TODO thật sự cần giữ thì chuyển thành issue hoặc ghi rõ owner. Nhưng mock data trong production path phải bị loại bỏ hoặc đánh dấu rõ là demo-only.

Một prompt tốt:

Scan the codebase for unused prototype leftovers.
List them first.
Do not delete anything until I approve.
Group findings into safe cleanup, needs review, and keep.

Với vibe coding, cleanup không nên giao toàn quyền ngay. Agent có thể xoá nhầm file ít dùng nhưng quan trọng.

Minimal tests cho flow kiếm tiền hoặc giữ dữ liệu

Repo sống không cần test mọi dòng ngay từ đầu. Nhưng cần test cho flow mà nếu hỏng thì app mất giá trị.

Với booking app nhỏ, flow tối thiểu có thể là:

  • User submit booking hợp lệ.
  • Form reject email hoặc date sai.
  • Confirmation hiển thị đúng booking.
  • Admin list thấy booking mới.
  • CSV export có đúng cột.

Nếu chưa có test infra, viết manual smoke checklist cũng tốt hơn không có gì. Nhưng khi app bắt đầu có deploy lặp lại, nên có ít nhất vài automated tests cho core flow. AI có thể giúp viết test, nhưng bạn phải kiểm tra test có bắt behavior thật không.

Test yếu:

renders booking form

Test hữu ích:

submitting a valid booking shows confirmation with selected date and email

Không cần coverage đẹp. Cần regression guard.

Setup docs phải đủ cho người khác chạy lại

Prototype thường chạy được trên máy người tạo vì context còn trong chat hoặc platform. Repo sống cần người khác clone và chạy lại được.

Tối thiểu cần:

  • Node/runtime version.
  • Install command.
  • Dev command.
  • Build command.
  • Test command nếu có.
  • Environment variables required.
  • Cách tạo local database hoặc connect staging.
  • Known limitations.

README.md không cần dài. Nhưng nếu một dev mới phải hỏi “chạy lệnh gì”, repo chưa sống.

Ví dụ đủ thực dụng:

Install: npm install
Run dev: npm run dev
Build: npm run build
Env: copy .env.example to .env.local and fill DATABASE_URL
Test: npm test

Với secret, chỉ ghi tên biến và cách lấy từ nơi nội bộ. Không ghi giá trị thật.

Deploy docs và rollback docs đi cùng nhau

Nếu app được share public, deploy path phải rõ. Không cần pipeline phức tạp, nhưng cần biết:

  • Deploy ở đâu.
  • Branch nào deploy.
  • Command hoặc dashboard nào dùng.
  • Env vars nằm ở đâu.
  • Cách xem log.
  • Cách rollback deploy gần nhất.

Nhiều vibe-coded app dừng ở “tôi bấm publish trên platform”. Điều đó ổn cho demo. Nhưng khi app có user thật, người khác phải biết nếu lỗi thì rollback bằng cách nào.

Một deploy note ngắn:

Hosting: Vercel project booking-demo
Production branch: main
Env vars: Vercel project settings
Rollback: Vercel deployments -> promote previous successful deploy
Smoke after deploy: submit booking, open admin list, export CSV

Không có rollback note thì deploy note chưa hoàn chỉnh.

Owner quan trọng hơn folder đẹp

Một repo sống cần owner. Không nhất thiết là senior engineer. Nhưng phải có người chịu trách nhiệm trả lời:

  • Ai review change?
  • Ai deploy?
  • Ai xử lý bug?
  • Ai quản lý secret?
  • Ai quyết định feature nào không làm?
  • Ai dọn dependency?

Vibe coding làm nhiều người tưởng app tự sinh ra thì cũng tự maintain. Không có chuyện đó. AI có thể hỗ trợ maintenance, nhưng vẫn cần người chịu trách nhiệm với user và dữ liệu.

Nếu không có owner, hãy giữ app ở trạng thái prototype nội bộ. Đừng share public như sản phẩm thật.

Phần nào nên rewrite thủ công

Không phải code AI viết đều phải rewrite. Nhưng có vài vùng nếu prototype thành sản phẩm thì nên xem kỹ, đôi khi rewrite thủ công rẻ hơn vá:

  • Auth và permission.
  • Payment.
  • Database schema cốt lõi.
  • File upload.
  • Data import/export quan trọng.
  • Background jobs.
  • Error handling cho giao dịch chính.
  • API client dùng nhiều nơi.

Lý do không phải “AI kém”. Lý do là các vùng này cần domain judgment, security judgment, và rollback planning. Agent có thể viết draft tốt, nhưng draft nên được dev thật review hoặc rewrite theo pattern repo.

Với UI marketing page, AI output có thể giữ nhiều. Với payment webhook, đừng tiếc công rewrite.

Handoff checklist

Trước khi chuyển prototype cho dev/team maintain, chuẩn bị một handoff ngắn:

What this app does
Core user flows
Tech stack
How to run locally
How to deploy
Required env vars
Known mock/demo parts
Known risks
Manual smoke checklist
Open questions

Đừng handoff bằng “chat history ở đây”. Chat history dài không phải documentation. Nó có thể giúp tra lại quyết định, nhưng người nhận cần một file ngắn nói repo hiện tại là gì.

Chốt lại

Prototype vibe-coded đáng giá vì nó làm ý tưởng thành thứ click được. Nhưng repo sống cần tiêu chuẩn khác: structure đọc được, dead code được dọn, test tối thiểu, setup/deploy rõ, rollback biết đường, và owner thật.

Đừng harden mọi prototype. Với những prototype đáng giữ, hãy làm một vòng chuyển trạng thái có chủ đích. Từ “AI dựng app” sang “team có thể maintain app” là một bước riêng. Nếu bỏ qua bước đó, bạn không có sản phẩm nhanh. Bạn có một demo đẹp đang chờ thành nợ kỹ thuật.