Development

Tôi Đã Dùng AI Để Xây Ginbok.com Như Thế Nào — Từ Ý Tưởng Đến Production

By Ginbok10 min read

Ginbok.com bắt đầu như một side project tôi tự xây dựng trong thời gian rảnh — một blog cá nhân chạy Optimizely CMS 12 ở backend và Next.js 14 ở frontend. Điều làm dự án này khác với những project trước không phải là tech stack — mà là mức độ tôi dựa vào AI xuyên suốt toàn bộ quá trình phát triển. Bài này là câu chuyện thực tế về điều đó.

Tech Stack Tổng Quan

  • Backend: Optimizely CMS 12 (ASP.NET Core 6, C#)
  • Frontend: Next.js 14 với App Router, deploy trên Vercel
  • AI Layer: Google Gemini API cho content generation và enrichment
  • Integration: ginbok-mcp — MCP server tự xây cho phép AI agent giao tiếp trực tiếp với CMS
  • DevOps: Azure DevOps cho repo, pipeline, và work item
AI Dev Tools CURSOR + CLAUDE Công cụ AI coding GINBOK-MCP publish-post · list-posts get-post · update-post create-post · PAT auth stdio transport AZURE REPOS + PIPELINES push → build → deploy Core System GEMINI API Enrichment nội dung · SEO · dịch VI OPTIMIZELY CMS 12 ASP.NET Core 6 · C# · IIS BlogGenerator · EN/VI branches SQL Server · McpApiController IndexNow · Google Indexing API REST API NEXT.JS 14 — VERCEL App Router · i18n · SSR · SEO Current: Optimizely CMS + Next.js + ginbok-mcp (stdio) publish IIS ginbok.com — kiến trúc hệ thống

Xây Dựng Frontend Next.js Với AI

Frontend là nơi AI tiết kiệm thời gian cho tôi nhiều nhất. Tôi dùng Cursor (với Claude 3.5 Sonnet và sau đó là Gemini) làm editor chính, với AI autocomplete bật gần như mọi lúc.

  • Component scaffolding: Mô tả một blog card grid theo phong cách broadsheet, nhận về React skeleton hoạt động được trong vài giây.
  • CSS module generation: Tôi không dùng Tailwind — AI tạo ra CSS module vanilla có cấu trúc tốt để tôi tinh chỉnh tiếp.
  • i18n routing: Thiết lập cấu trúc [locale] trong App Router với next-intl middleware — AI map ra đúng file structure ngay lần đầu.
  • SEO metadata: Helper generateMetadata() tái sử dụng được với canonical URL, hreflang, và OG tag — một prompt, 20 phút review.

Chỗ tôi phải tự xử lý: performance. Component do AI tạo thường gây vấn đề Core Web Vitals — layout shift từ ảnh chưa optimize, client-side state không cần thiết. Bước review đã bắt được tất cả.

Backend Optimizely CMS 12

Optimizely là nơi kiến thức AI chung bắt đầu sụp đổ. Platform này có content repository pattern riêng và language branch API mà LLM không có đủ training data.

AI gặp khó ở đâu

Định nghĩa page type cần sửa liên tục — AI nhầm XhtmlString với string, và gợi ý các overload của IContentRepository không tồn tại. Tôi luôn verify lại với SDK thực tế.

AI thực sự hữu ích ở đâu

Tầng logic. Service class, LINQ query, slug generation, và tag normalisation helper đều là C# thuần — AI xử lý tốt. Đây là hàm GetUniqueSlug() thực tế — AI draft, tôi review:

private string GetUniqueSlug(string title, ContentReference parentLink, LanguageSelector language)
{
    var baseSlug = Slugify(title);
    if (string.IsNullOrEmpty(baseSlug)) baseSlug = "post";

    var existingSlugs = _contentRepository
        .GetChildren<BlogDetailPage>(parentLink, language)
        .Select(p => p.URLSegment)
        .Where(s => !string.IsNullOrEmpty(s))
        .ToHashSet(StringComparer.OrdinalIgnoreCase);

    if (!existingSlugs.Contains(baseSlug))
        return baseSlug;

    var counter = 2;
    while (existingSlugs.Contains($"{baseSlug}-{counter}"))
        counter++;

    return $"{baseSlug}-{counter}";
}

BlogMaintenanceJob — Gộp Hai Job Thành Một

Ban đầu tôi có hai scheduled job riêng biệt — BlogAuditAndEnrichmentJobBlogSeoEnrichmentJob. Theo thời gian sự chồng chéo ngày càng lớn: cả hai đều động vào cùng một bài post, cùng gọi Gemini API, và chạy riêng lẻ nghĩa là rate-limit wait nhân đôi và CMS save trùng lặp.

Tôi gộp lại thành một BlogMaintenanceJob chạy bốn phase trong một lượt:

  • Phase 1 — Localize + Enrich: Kiểm tra VI branch — nếu chưa có thì gọi Gemini dịch và tạo. Trong cùng lượt, điền các trường SEO còn thiếu bằng một lần gọi GenerateSeoAsync().
  • Phase 2 — Cleanup sweep: Chuẩn hóa Category/Tags trên cả nhánh EN và VI bằng HashtagHelper.
  • Phase 3 — Taxonomy sanitization: Duyệt CategoryRepository, đổi tên item lỗi format, xóa duplicate.
  • Phase 4 — Author normalisation: Đảm bảo mọi branch có Author = "Ginbok".

Tôi thiết kế cấu trúc phase và data contract, AI implement các vòng lặp, WaitForRateLimit() (8 giây giữa các lần gọi Gemini), và HTML + CSV report builder. Việc gộp giảm runtime khoảng 40%.

Tầng MCP — Một Thử Nghiệm Thành Công

Phần thử nghiệm nhất là xây ginbok-mcp — TypeScript MCP server expose CMS thành callable tool. Cho phép tôi nói "publish bài blog về X" trong chat và hệ thống tự tạo nội dung EN/VI rồi đẩy lên Optimizely — không cần chạm CMS admin UI.

export const publishPostSchema = z.object({
    TitleEn: z.string().describe("English title. Required."),
    TitleVi: z.string().optional(),
    BodyEn: z.string().describe("English HTML body. Required."),
    BodyVi: z.string().optional(),
    Category: z.string().optional(),
    Tags: z.string().optional(),
    Author: z.string().optional(),
});

export async function publishPost(input: PublishPostInput): Promise<string> {
    const response = await apiPost("/api/mcp/posts/publish", input);
    return response.data?.success
        ? `✅ Published: ${input.TitleEn} (ID: ${response.data.postId})`
        : `❌ Failed: ${response.error}`;
}

Các MCP Tool Thay Đổi Quy Trình Dev

DBHub MCP — AI Hiểu Database Của Bạn

Tôi kết nối DBHub MCP với SQL Server của ginbok.com. AI có thể query cấu trúc table, kiểm tra kiểu column, và đọc sample data trực tiếp từ chat.

  • Debug nhanh hơn. Thay vì giải thích schema thủ công, tôi nói "check DB và debug lỗi này" — AI tự đọc và đưa ra câu trả lời chính xác.
  • Query đúng ngay lần đầu. AI thấy tên cột thực tế nên SQL khớp schema mà không cần sửa đi sửa lại.
  • Context onboarding tức thì. Đầu mỗi session, AI tự đọc data model thay vì tôi phải re-explain.

Azure DevOps MCP — Đóng Vòng Lặp Giữa Chat Và Work Item

Kết nối Azure DevOps MCP vào Cursor cho phép AI tạo, đọc, và cập nhật work item trực tiếp từ chat.

  • Tạo work item từ hội thoại. Phát hiện bug hoặc feature → mô tả với AI → nhận work item có cấu trúc đầy đủ mà không rời editor.
  • Đo lường rõ ràng hơn. Mọi feature và bug fix đều có work item — lịch sử phát triển hoàn toàn trace được.
  • Lên kế hoạch học AI. Map out lộ trình học thành epic → feature → task trong một session.

Tác Động Kết Hợp

  • DBHub giải quyết context gap — AI không hiểu đủ hệ thống để trả lời chính xác.
  • Azure DevOps MCP giải quyết traceability gap — công việc trong AI chat không được log chính thức.

Quy Trình Thực Tế

  1. Idea: Xác định feature hoặc vấn đề
  2. Spec: Mô tả ngắn về behaviour, edge case, file liên quan
  3. AI Draft: Prompt Cursor/Claude/Gemini — lần đầu thường đúng 70–80%
  4. Review: Đọc từng dòng, sửa 20–30% còn lại
  5. Deploy: Push lên Azure Repos → pipeline → IIS/Vercel

Gợi Ý AI Tôi Giữ vs. Quyết Định Tôi Tự Làm

Gợi ý AI tôi giữ lại

  • Dùng next-intl cho i18n routing
  • Sequential slug suffix (-2, -3)
  • HashSet-based duplicate slug detection
  • IndexNow + Google Indexing API khi publish

Quyết định tôi tự làm

  • Chọn Optimizely làm headless CMS — AI gợi ý Contentful hoặc Sanity.
  • MCP thay vì REST API thuần — AI không gợi ý pattern này.
  • Không dùng Tailwind CSS — AI luôn default Tailwind, tôi override mỗi lần.
  • Gộp hai job thành BlogMaintenanceJob — AI không phát hiện redundancy; tôi tự nhận ra.
  • Rate limit 8 giây/lần Gemini — dựa trên quan sát quota API thực tế.

Kết Quả Thực Tế

Thời gian tiết kiệm: ~40–50%

Nhiều nhất: code structural lặp lại, CSS scaffolding, documentation. Ít nhất: Optimizely-specific pattern và bất cứ thứ gì cần production judgment.

Chỗ AI làm chậm tôi

Hallucination trên platform-specific API — tự tin gợi ý method không tồn tại trong Episerver SDK. Bài học: verify mọi thứ với platform doc thực tế khi làm với framework chuyên biệt.

Điều bất ngờ

MCP workflow hoạt động mượt hơn kỳ vọng. Kết nối DBHub + Azure DevOps MCP trên nền ginbok-mcp làm hệ thống cảm giác thực sự integrated thay vì tập hợp tool rời rạc.

Lời Kết

AI không xây ginbok.com — tôi xây. Nhưng nó thay đổi có ý nghĩa cách tôi làm việc. Mental model tốt nhất: một junior developer rất nhanh nhưng không hoàn toàn đáng tin. Bước review không thể bỏ qua.

Nếu bạn đang nghĩ đến việc tích hợp AI vào side project: bắt đầu từ nơi bạn tự tin nhất có thể review output. Và hãy xem xét nghiêm túc MCP servers — kết nối AI với database và project management tool thực tế thay đổi chất lượng trợ giúp nhiều hơn việc chuyển đổi giữa các model.

Roadmap — Kiến Trúc Tương Lai

Hệ thống hiện tại hoạt động tốt, nhưng có nhiều hướng kiến trúc tôi đang lên kế hoạch phát triển. Thay đổi lớn nhất là chuyển sang monorepo — gộp CMS backend, Next.js frontend, ginbok-mcp, BFF API, và các app tương lai vào một repository duy nhất quản lý bởi Azure Repos với pipeline thống nhất.

Các thành phần chính trong roadmap:

  • BFF API — một lớp Backend for Frontend riêng biệt (ASP.NET Core minimal API) nằm giữa Optimizely CMS và tất cả frontend app. BFF xử lý aggregate, shape response, cache, và rate-limit.
  • ginbok-mcp thành remote HTTP + SSE server — chuyển từ stdio transport cục bộ thành một hosted MCP server thực sự, có thể truy cập bởi bất kỳ AI client nào qua network.
  • App B — một frontend application thứ hai nằm song song với Next.js, cả hai cùng consume BFF API từ cùng một monorepo.
  • Notification Layer — hệ thống phân phối nội dung event-driven, kích hoạt khi post được publish qua Azure Functions, tự động đẩy bài mới đến email newsletter và các kênh social.

Đây là kiến trúc mục tiêu:

AZURE REPOS + PIPELINES monorepo · push → build → deploy all services AI Dev Tools CURSOR + CLAUDE Công cụ AI coding uses MCP Layer GINBOK-MCP HTTP + SSE · remote server publish · list · get · update API calls Notification Layer WEBHOOK TRIGGER on publish · Azure Function EMAIL Newsletter · Resend SOCIAL LinkedIn · X Core System — monorepo GEMINI API Enrichment nội dung · SEO · dịch VI OPTIMIZELY CMS 12 ASP.NET Core 6 · C# · IIS · SQL Server BlogGenerator · EN/VI · McpApiController IndexNow · Google Indexing API on publish BFF API ASP.NET Core minimal API · aggregate · transform cache · rate-limit · single entry point shaped response NEXT.JS 14 ginbok.com · EN / VI APP B future · TBD Roadmap: monorepo · BFF · MCP remote · App B · Notification

Mục tiêu là một hệ thống trong đó mọi thành phần — AI tooling, content pipeline, frontend app, và distribution — vận hành như một thể thống nhất thay vì tập hợp các phần rời rạc. Cấu trúc monorepo thực thi điều này: một repo, một pipeline, một nơi duy nhất để lý giải toàn bộ hệ thống.

#AI#Next.js#Optimizely CMS#MCP#Side Project#Developer Workflow#Gemini#Azure DevOps#DBHub#Cursor#Claude
← Back to Articles