Nhiệm vụ: Chuyển trang web sang nền tảng mới

Chuyển trang web sang nền tảng mới

23.06.2026pivkarta.ru

Trang web đã rất cũ, ban đầu chạy trên MODX, sau đó được viết lại bằng các công nghệ JS thủ công và thậm chí cả Prisma thế hệ đầu tiên. Do đó, nó tiêu tốn quá nhiều tài nguyên (hơn 2 GB).

docker stats --no-stream |grep pivkarta
fab6503884d8   docker-pivkartaru-mysql-1          0.47%     531.3MiB / 6.954GiB   7.46%     572MB / 12.1GB    26.7GB / 1.58GB   41
6657aa9c2c22   docker-pivkartaru-front-1          23.59%    405.4MiB / 6.954GiB   5.69%     45.7GB / 91.9GB   40.1GB / 31.6MB   23
202c9196d804   docker-pivkartaru-api-1            3.88%     226.4MiB / 6.954GiB   3.18%     815MB / 547MB     3.71GB / 1.27MB   23
782d45865722   docker-pivkartaru-prisma-1         2.70%     908.3MiB / 6.954GiB   12.75%    500MB / 646MB     8.43GB / 62.9MB   78

Để so sánh, haih-agent thậm chí chạy cùng với n8n cũng chỉ tốn chưa đầy một gigabyte (thường là khoảng 500 MB).

Ворклоги

Cấu trúc CSDL legacy: giả thuyết "chỉ cần kết nối" bị xem xét lại

Sau khi chạy thử cục bộ, chúng tôi đã xem xét cấu trúc thực tế của cơ sở dữ liệu MySQL hiện có. Quy mô của legacy lớn hơn đáng kể so với những gì chỉ nhìn thấy qua Docker stack: 250 bảng, khoảng 198 nghìn dòng và ~82 MiB dữ liệu.

Trong tổng số 250 bảng, khoảng 150 bảng có tiền tố MODX cũ fSdf12_. Đây là lớp hệ thống lớn của chính MODX và các tiện ích mở rộng (Extras) được cài đặt qua nhiều năm: ACL/policies, contexts, manager/dashboard, media sources, package transport, lexicon, sessions, users/groups, các module billing/shop, society, SDK/importer, search, monitoring, GeoIP và các phân hệ khác. Phần lớn các bảng này trống hoặc chỉ chứa vài bản ghi, nhưng khi phân tích legacy, chúng vẫn trông giống như một phần có khả năng quan trọng của hệ thống.

Ngoài ra còn có một lớp mô hình lịch sử khác: hàng chục bảng quan hệ theo phong cách Prisma _...; nhiều bảng trong số đó hiện đang trống. Dấu vết của việc di chuyển/trùng lặp thực thể liên tiếp cũng hiển thị rõ: ví dụ như các biến thể cũ và mới của Place, Beer, User, Photo, các bình luận và bảng liên kết, các bảng sao lưu người dùng, views và các công cụ lưu trữ khác nhau (MyISAM + InnoDB). Đây không còn là một lược đồ miền đơn lẻ, mà là một vài thế hệ kiến trúc cùng tồn tại trong một cơ sở dữ liệu.

Đồng thời, lõi miền thực tế của pivkarta.ru nhỏ hơn nhiều. Dữ liệu cho thấy có vài nghìn địa điểm (Place ~3.8k), khoảng 1.6k loại/mục Beer, ~13k liên kết PlaceBeer, hình ảnh, người dùng và các liên kết của địa điểm với bia/tàu điện ngầm/người dùng; cộng với các thực thể nội dung như bình luận, chủ đề, tin tức/blog, v.v. Những thực thể nào thực sự cần thiết cho phiên bản sản phẩm hiện đại vẫn cần được xác định dựa trên các yêu cầu thực tế — số lượng bản ghi tự nó không chứng minh rằng tính năng đó cần được chuyển sang.

Điều này minh họa rõ ràng luận điểm từ bài viết «MODX trả một cái giá kiến trúc cố định khổng lồ cho các tính năng mà hầu hết các dự án gần như không bao giờ sử dụng»: ngay cả một bảng trống cũng không có nghĩa là chi phí kiến trúc bằng không. Nếu một phân hệ tồn tại, khi làm việc với legacy, chúng ta phải tìm hiểu mô hình, các mối quan hệ, ngữ nghĩa thời gian chạy (runtime semantics) của nó và hiểu xem liệu có thể loại bỏ nó một cách an toàn hay không. Trong cơ sở dữ liệu này, hiệu ứng có thể được nhìn thấy rõ ràng theo nghĩa đen: phần lớn lược đồ mô tả các khả năng của engine và các thử nghiệm lịch sử, chứ không phải mô hình miền hiện tại của pivkarta.ru.

Thay đổi hướng thử nghiệm

Trong worklog trước, lựa chọn đầu tiên là con đường ít xâm lấn nhất: giữ nguyên MySQL hiện có làm ranh giới bền vững (persistence boundary) và kết nối API mới thông qua Knex. Sau khi xem xét lược đồ, lựa chọn này không còn tỏ ra là tối ưu một cách hiển nhiên nữa.

Giờ đây, một giả thuyết có triển vọng hơn là — tạo một CSDL sạch mới với mô hình miền tối thiểu và chỉ di chuyển sang đó dữ liệu thực sự cần thiết đã được chứng minh. Sử dụng CSDL cũ làm nguồn dữ liệu và khảo cổ học yêu cầu, nhưng không coi nó làm nền tảng vĩnh viễn cho kiến trúc mới.

Điều này làm tăng công việc ở hiện tại: tác nhân (agent) sẽ phải tìm hiểu xem trong số 250 bảng, bảng nào thực sự tham gia vào sản phẩm, bảng nào là bảng kỹ thuật của MODX/Prisma/Extras, bảng nào đại diện cho các phiên bản cũ của cùng một dữ liệu, và tính năng nào thậm chí không còn cần thiết nữa. Nhưng chính điều này lại là một bài kiểm tra brownfield tốt cho HAIH: không mang theo độ phức tạp tích lũy chỉ vì nó đã tồn tại; khôi phục các yêu cầu thực tế và xây dựng một mô hình mới tối thiểu cho chúng.

Bước hợp lý tiếp theo là xây dựng bản đồ legacy tables → các khả năng thực tế (capabilities) → cần thiết/không cần thiết → mô hình mới → di chuyển/xác minh (migration/verification), sau đó chọn kịch bản theo chiều dọc (vertical scenario) đầu tiên và chuyển nó cùng với dữ liệu theo hình thức end-to-end.

Thử nghiệm liên quan: haih.site và nhiệm vụ /tasks/cmujk0ehv0m20qw0rs14y30bw. Nhiệm vụ hiện tại: /tasks/cmqqxckd3003zp50up0dmzbld.

Tổng kết di chuyển pivkarta.ru: production và SEO/performance evidence

Đã hoàn thành nhiệm vụ: pivkarta.ru mới đã được đưa lên production. Các cải tiến tiếp theo sẽ được xử lý trong các tác vụ riêng biệt.

Quy mô di chuyển brownfield

Trang web mới được xây dựng dựa trên HAIH runtime đang phát triển, nhưng đối với một dự án legacy thực tế, engine này đã được cải tiến đáng kể để thành một mô hình production hoàn chỉnh: Express runtime đơn độc, React Router SSR, GraphQL/Apollo/Pothos, Knex kết nối với MySQL hiện có, Vite middleware trong môi trường development, phục vụ static production, Varnish, xử lý thumbnail legacy thông qua Sharp, ETag/GET/HEAD và giải phóng tài nguyên máy chủ đúng cách.

Khôi phục cấu trúc công khai chính của sản phẩm cũ: bia, địa điểm, bài viết, thành viên, bình luận, thành phố, bản đồ và liên hệ, bao gồm các URL lịch sử và mối quan hệ giữa các thực thể. Kiểm kê dữ liệu legacy ghi nhận 1.636 bản ghi bia, 3.797 địa điểm, 600 bài viết, 64 thành phố, 3.296 bình luận và 26.548 hồ sơ công khai.

Để đảm bảo tính tương thích, một registry gồm 73.760 địa chỉ đã được xây dựng. Toàn bộ quá trình HTTP crawl được ghi nhận là passed: 73760 không có lỗi ở trạng thái đã kiểm tra. Ngoài ra, 11.579 liên kết nội dung và 19.660 URL tài nguyên đã được kiểm tra bổ sung. Các thay đổi tiếp theo của nhánh được bao phủ bởi các bài kiểm tra mục tiêu, do đó toàn bộ quá trình crawl cũ không nên được coi là sự kiểm tra cho mọi commit cuối cùng.

Kết quả production có thể đo lường

Công việc chính của lần lặp hiện tại kể từ ngày 28 tháng 9 mất 18:01:02 theo đồng hồ bấm giờ.

Lighthouse trước/sau:

Chỉ sốLegacyMới
Performance4993
Accessibility75100
Best Practices7496
SEO83100

Application runtime theo docker stats:

  • legacy front: 588.4 MiB;
  • legacy api: 231.3 MiB;
  • legacy prisma: 953.2 MiB;
  • tổng tầng ứng dụng legacy: ~1773 MiB (~1.73 GiB);
  • app mới: 178.2 MiB.

Như vậy, RAM của ứng dụng đã giảm khoảng 10 lần (~90%), đồng thời Lighthouse Performance tăng từ 49 lên 93 và đạt 100 điểm về Accessibility và SEO. Điều đặc biệt đáng chú ý là chỉ riêng Prisma 1 của stack cũ đã tiêu thụ ~953 MiB — lớn hơn gấp năm lần tổng số application runtime mới.

Kết luận kỹ thuật chính

Quá trình di chuyển đã xác nhận giả thuyết brownfield của HAIH: để thay thế một ứng dụng legacy, không nhất thiết phải tái tạo kiến trúc lịch sử của nó. Con đường thực tế đã diễn ra như sau:

hệ thống legacy → khôi phục các yêu cầu/khả năng thực tế → kiểm tra dữ liệu và hợp đồng URL → loại bỏ di sản không cần thiết → kiến trúc mới tối thiểu → xác minh (verification) → bằng chứng production (production evidence).

Giả thuyết ban đầu về việc giữ nguyên mô hình legacy làm ranh giới kiến trúc chính đã được điều chỉnh sau khi nghiên cứu cơ sở dữ liệu thực tế và 250 bảng. Kết quả là dữ liệu công khai có giá trị, các mối quan hệ và web contract được giữ lại, nhưng độ phức tạp về cơ sở hạ tầng tích lũy của hệ thống cũ không được tái tạo.

Điều này làm cho kết quả khác biệt so với một đợt thiết kế lại thông thường: tạo ra được một bản thay thế production cho một trang web lâu năm thực tế với khả năng tương thích có thể đo lường, chi phí runtime thấp hơn đáng kể và các chỉ số web tốt hơn rõ rệt.

Ranh giới của nhiệm vụ này

Trong khuôn khổ nhiệm vụ này, chúng tôi coi việc di chuyển đã hoàn tất. Các kịch bản ghi bị hoãn (xác thực, tạo/chỉnh sửa thực thể), việc thiết kế lại từng trang nội dung bên trong tiếp theo, các bài kiểm tra production bổ sung và các cải tiến khác phải được thực hiện trong các tác vụ riêng biệt chứ không mở rộng tác vụ hiện tại.

Thí nghiệm HAIH mới: brownfield trên pivkarta.ru

Nhiệm vụ này đã được đặt ra từ lâu như một bản nâng cấp cho haih-agent cũ, nhưng kể từ đó, một cách tiếp cận HAIH mới đã xuất hiện, mà chúng tôi hiện đang kiểm tra thực tế tại haih.site. Công việc hiện tại về ý tưởng đang được thực hiện trong nhiệm vụ «Phát triển và ra mắt trang web», và pivkarta.ru có vẻ là một vật thí nghiệm tiếp theo tốt cho công nghệ/cách tiếp cận mới.

Nếu haih.site là một thí nghiệm greenfield về việc «nhanh chóng xây dựng một kiến trúc đủ dùng từ các yêu cầu thực tế», thì pivkarta.ru có thể trở thành một thí nghiệm brownfield: AI-agent có khả năng phân tích một sản phẩm hiện có nhanh đến mức nào, giữ lại các yêu cầu thực tế của nó và dần dần thay thế kiến trúc lỗi thời, mà không mang theo gánh nặng lịch sử của nó vào hệ thống mới.

Điều quan trọng là không bắt đầu bằng việc viết lại hoàn toàn (rewrite) và chọn trước một «stack đúng». MySQL hiện tại có thể được giữ lại làm ranh giới bền vững (persistence boundary) và cho lát cắt dọc (vertical slice) đầu tiên, hãy kết nối với nó thông qua Knex, phía trên tạo một API kiểu mới trên Pothos/GraphQL, và ở phía client là codegen/Apollo + React. Tức là chuyển giao trước hết là các yêu cầu và hành vi, chứ không phải kiến trúc cũ.

Thí nghiệm thực tế đầu tiên: chọn một kịch bản người dùng thực tế và thực hiện nó từ đầu đến cuối (end-to-end) qua hệ thống mới (React → Apollo → GraphQL/Pothos → Knex → MySQL hiện có), ghi lại thời gian triển khai, các vấn đề, phương pháp kiểm tra và tài nguyên. Đường cơ sở (baseline) đã có của hệ thống cũ (~2 GB RAM theo các số đo hiện tại) sẽ cho phép so sánh kết quả không chỉ về mặt tính năng mà còn về chi phí runtime.

Điều này sẽ trở thành loại bằng chứng (evidence) thứ hai cho HAIH sau haih.site: không chỉ là «AI thu thập cái mới nhanh đến mức nào», mà còn là nó có khả năng định hình lại và thay thế legacy theo các chiều dọc hoạt động nhanh đến mức nào.

Legacy baseline đã được khởi chạy cục bộ

Chúng tôi đã thành công trong việc chạy lại pivkarta.ru cũ cục bộ — Docker đã giúp ích rất nhiều trong việc duy trì tính tái tạo ngay cả sau nhiều năm. Đồng thời, điều này cũng cho thấy rõ ràng một lớp lịch sử lớn đã tích tụ trong kiến trúc hiện tại như thế nào.

Một số thành phần tiêu biểu của baseline:

  • build image: mhart/alpine-node:10 — Node.js 10;
  • Docker Compose 3.7;
  • prismagraphql/prisma:1.15.3 (Prisma 1) như một dịch vụ riêng biệt giữa ứng dụng và CSDL;
  • MySQL 5.7;
  • các container riêng biệt front và api từ prisma-cms cũ chung;
  • frontend riêng pivkarta.ru-2;
  • phpMyAdmin;
  • Caddy proxy tự xây dựng;
  • MailHog;
  • rtcmultyconnection riêng biệt;
  • Coturn với cơ sở hạ tầng STUN/TURN.

Nói cách khác, đây không chỉ đơn thuần là bài toán cập nhật một vài gói npm: trước mắt chúng ta là một dự án brownfield thực tế tốt với các lớp giải pháp từ nhiều năm khác nhau và một lượng lớn cơ sở hạ tầng, trong đó có phần có thể cần thiết, nhưng cũng có phần là gánh nặng lịch sử.

Đối với thí nghiệm HAIH, điều này cực kỳ hữu ích. Chúng ta sẽ không chuyển đổi một cách máy móc "vườn thú" công nghệ này sang các phiên bản hiện đại. Dự án cũ trở thành nguồn cung cấp yêu cầu và baseline hành vi, chứ không phải là thông số kỹ thuật của kiến trúc mới. Đối với mỗi lớp, cần phải tìm hiểu: nó đang cung cấp khả năng thực tế nào ngay bây giờ, pivkarta.ru hôm nay có cần nó không, và giải pháp kiểm chứng tối thiểu nào đáp ứng yêu cầu đó.

Vertical slice mới đầu tiên được lên kế hoạch vẫn giữ nguyên sự đơn giản: giữ lại MySQL hiện tại làm ranh giới bền vững legacy và đi qua chuỗi React → Apollo/codegen → GraphQL/Pothos → Knex → MySQL hiện tại. Điều này sẽ cho phép bắt đầu thay thế hệ thống cũ bằng các luồng dọc hoạt động, mà không bắt đầu bằng việc di chuyển dữ liệu rủi ro và không mang theo Prisma 1 chỉ vì nó có sẵn trong legacy.

Thí nghiệm HAIH liên quan: haih.site và nhiệm vụ «Phát triển và ra mắt trang web». Nhiệm vụ hiện tại của pivkarta.ru: /tasks/cmqqxckd3003zp50up0dmzbld.