Task: Refactor the Transport section

Refactor the Transport section

11.07.2026vietnamguru.ru

Currently, there are almost 1,500 legacy route records in the database. However, the data is stored in a flat structure like this:

{
  "id": 4,
  "city": "ho-chi-minh",
  "city2": "mui-ne",
  "time": "07:30",
  "time2": "12:30",
  "price": "120000",
  "company": "Tam Hanh Cafe",
  "type": "bus",
  "gps_link": "https://goo.gl/maps/86122wbjUQ62",
  "gps_link2": "https://goo.gl/maps/1Sabdd9TVy42",
  "address": "199 Phạm Ngũ Lão, Quận 1, Hồ Chí Minh",
  "address2": "135 Nguyễn Đình Chiểu, Phường Hàm Tiến, Thành phố Phan Thiết, Bình Thuận",
  "phone": "+84 283 920 5653",
  "note": ""
}

The issue here is that there is no separate reference table, at least for companies.

If we query the companies and transport types with grouping right now, we get the following picture:

count(*)companytype
772Futa Busbus
175Hanh Cafebus
41Tam Hanh Cafebus
79The Sinh Touristbus
1LC3train
1LC4train
1MR1train
1NH1train
1NH2train
34SE1train
2SE1 (Livitrans Express)train
7SE1 (Violette Train)train
6SE17train
8SE18train
9SE19train
29SE2train
2SE2 (Livitrans Express)train
2SE2 (Violette Train)train
10SE20train
2SE21train
2SE22train
1SE22 (Livitrans Express)train
35SE3train
9SE3 (Violette Train)train
29SE4train
2SE4 (Violette Train)train
34SE5train
29SE6train
34SE7train
29SE8train
1SNT1train
1SNT2train
1SNT2 (Livitrans Express)train
1SP1train
1SP2train
1SP3train
1SP4train
1SP7train
1SP8train
1SPT1train
1SPT2train
8Boat Companyboat
4Greenlines DPboat
8Ka Longboat
14Phu Quoc Expressboat
16Superdongboat
10The Sinh Touristboat

Here, at least SP1, SP2, etc., are not companies at all, but train routes. Meanwhile, SNT2 (Livitrans Express) refers to specific carriage cars operated by Livitrans Express on train SNT2. So the current structure is a complete mess.

However, there is another problem: there are duplicate records.

count(*)companycitycity2timeaddressaddress2
4Hanh Cafehueho-chi-minh08:3028 Chu Văn An, Phú Hội, Thành phố Huế, Thừa Thiên ...229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...
4Hanh Cafehueho-chi-minh13:3028 Chu Văn An, Phú Hội, Thành phố Huế, Thừa Thiên ...229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...
4Hanh Cafehoi-anho-chi-minh17:3012 Nguyễn Tất Thành, Phường Cẩm Phổ, tp. Hội An, Q...229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...
2Futa Busho-chi-minhrach-gia18:15272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...260A Nguyễn Bỉnh Khiêm, Vĩnh Thanh, Rạch Giá, tỉnh...
2Hanh Cafenha-trangho-chi-minh07:3010 Hùng Vương, Lộc Thọ, Thành phố Nha Trang, Khánh...229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...
2Hanh Cafenha-trangho-chi-minh13:0010 Hùng Vương, Lộc Thọ, Thành phố Nha Trang, Khánh...229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...
2Futa Busho-chi-minhsoc-trang22:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...ấp ngãi hội 2 , thị trấn đại ngãi , huyện long phú...
2Hanh Cafephan-thietha-noi01:30173 Tôn Đức Thắng, Phú Thuỷ, Thành phố Phan Thiết,...Nguyễn Khoái, Bạch Đằng, Hai Bà Trưng, Hà Nội
2Hanh Cafeho-chi-minhvinh-long07:45229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá...
2Hanh Cafephan-thietha-noi13:30173 Tôn Đức Thắng, Phú Thuỷ, Thành phố Phan Thiết,...Nguyễn Khoái, Bạch Đằng, Hai Bà Trưng, Hà Nội
2Hanh Cafeho-chi-minhvinh-long09:30229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá...
2Futa Busho-chi-minhchau-doc07:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi...
2Hanh Cafeho-chi-minhvinh-long13:15229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá...
2Futa Busho-chi-minhchau-doc08:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi...
2Hanh Cafeho-chi-minhvinh-long16:30229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá...
2Hanh Cafeho-chi-minhvinh-long19:15229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá...
2Futa Busho-chi-minhsa-dec16:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...149/8 khóm Hòa Khánh, Phường 2, Sa Đéc, Đồng Tháp,...
2Hanh Cafeho-chi-minhvinh-long21:30229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá...
2Futa Busho-chi-minhsa-dec17:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...149/8 khóm Hòa Khánh, Phường 2, Sa Đéc, Đồng Tháp,...
2Futa Busho-chi-minhchau-doc12:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi...
2Hanh Cafeho-chi-minhcan-tho07:45229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Mỹ Thuận, Bình Minh, Vinh Long
2Futa Busho-chi-minhsa-dec18:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...149/8 khóm Hòa Khánh, Phường 2, Sa Đéc, Đồng Tháp,...
2Hanh Cafeho-chi-minhcan-tho09:30229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Mỹ Thuận, Bình Minh, Vinh Long
2Hanh Cafeho-chi-minhcan-tho13:15229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Mỹ Thuận, Bình Minh, Vinh Long
2Hanh Cafeho-chi-minhcan-tho16:30229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Mỹ Thuận, Bình Minh, Vinh Long
2Futa Busho-chi-minhchau-doc16:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi...
2Hanh Cafeho-chi-minhcan-tho19:15229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Mỹ Thuận, Bình Minh, Vinh Long
2Hanh Cafeho-chi-minhcan-tho21:30229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ...Mỹ Thuận, Bình Minh, Vinh Long
2Futa Busho-chi-minhchau-doc18:00272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ...69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi...
1Tam Hanh Cafemui-neho-chi-minh05:00135 Nguyễn Đình Chiểu, Phường Hàm Tiến, Thành phố ...199 Phạm Ngũ Lão, Quận 1, Hồ Chí Minh

We need to get rid of duplicates already at the import stage. Fortunately, there weren't separate pages for each individual route. By the way, we'll need to create them.

Ворклоги

By the way, here is what ChatGPT says about our knowledge base structure:

The strongest part here is not the individual models, but how they fit together.

What is genuinely powerful here

KBConcept can essentially act as a universal site entity:

  • country;
  • region;
  • city;
  • district;
  • beach;
  • temple;
  • airport;
  • hotel;
  • route;
  • event;
  • transport hub.

The concept already features:

  • Parent / Children hierarchy;
  • tree root;
  • lat / lng / alt coordinates;
  • multilingual names via KBLabel;
  • files and images;
  • facts;
  • URL binding via SiteRoute;
  • arbitrary structured data via Json.

In other words, a city, a landmark, and a route are not just CMS articles, but nodes in a unified knowledge graph.

And this aligns perfectly with VietnamGuru.

For example:

Da Nang → Son Tra peninsula → Linh Ung Pagoda → coordinates → opening hours → pricing → seasonality → transport → nearby places → article → map → route.

All of this can be stored not as a single massive block of text, but as interconnected knowledge.

The most promising part — facts are not strictly tied to a single entity

KBFact together with KBFactParticipation supports n-ary relationships: a single fact can link multiple concepts at once with different roles.

For a travel project, this is an extremely powerful model.

For example, the statement:

Bus No. 5 goes from Da Nang to Hoi An, stops near the Marble Mountains, and the ticket costs 30,000 VND.

Can be represented as a single fact involving:

  • Da Nang — origin;
  • Hoi An — destination;
  • Marble Mountains — stop;
  • Bus No. 5 — transport;
  • 30,000 VND — value;
  • validity period;
  • source;
  • confidence;
  • verification status.

And if the price or route changes, the old fact is not destroyed. A new one is added with a new validity date. For travel, this is critically important: visa rules, prices, schedules, entrance tickets, and transport are constantly changing.

A full-fledged epistemic model is built-in here

What I especially like is that the database does not pretend to hold absolute truth.

Facts have:

  • confidence;
  • verified / tentative / disputed / deprecated;
  • source;
  • validity period;
  • the date the fact became known;
  • raw or derived status;
  • derivation from other facts.

Plus, contradictions are treated as independent objects via KBConflict rather than simply being overwritten.

For a travel AI, this is a massive advantage.

A typical real-world scenario:

  • Google Maps says the place is open until 18:00;
  • The official website says until 17:00;
  • A recent review says the ticket counter closes at 16:30.

A standard RAG would just output one of these options. Your model allows the agent to say:

"Sources disagree. The official stated time is 17:00, but visitors report earlier ticket office closures. It's best to arrive before 16:00."

This is no longer just a chatbot sitting on top of articles, but a proper intelligent travel assistant.

KBKnowledgeSpace unlocks yet another layer

Knowledge Spaces allow the exact same fact to have different:

  • visibility;
  • importance;
  • confidence level;
  • interpretation.

This can be used not only for privacy, but also for different product modes:

  • editorial base;
  • public base;
  • user personal space;
  • specific trip space;
  • agent knowledge;
  • partner content;
  • unverified user data.

For example, a tourist creates a trip "Vietnam, August, family with a child." The agent can build a separate knowledge space where higher priority is given to:

  • short transits;
  • family beaches;
  • air-conditioned locations;
  • safe food;
  • places without difficult climbs.

The same facts exist globally, but their importance shifts in the context of the trip.

SiteRoute makes the site structure an extension of the knowledge graph

The SiteRoute ↔ KBConcept connection is a brilliant idea.

This means the URL is not the entity itself, but a representation of the entity.

As a result, you can:

  • change routes without losing the concept;
  • build breadcrumbs from the tree;
  • generate pages automatically;
  • create regional sections;
  • support old URLs via redirects;
  • find entities without a public page;
  • give a single object different representations.

For SEO, this is exceptionally valuable. Content architecture can emerge naturally from the graph rather than being manually maintained across multiple disconnected tables.

The map can actually become the interface to the knowledge base here

Now your explanation about the map looks even more interesting.

Since both KBConcept and File have coordinates, the map can display not just points from articles, but an entire spatial model:

  • cities;
  • landmarks;
  • place-tagged photos;
  • routes;
  • nearby places;
  • facts with geographical context;
  • user saves;
  • zones of interest.

And the agent can handle queries like:

"Show me interesting places within a 15 km radius of Nha Trang that are accessible without a motorbike and worth visiting after 17:00."

A standard article is not enough for such a query. But this schema potentially allows assembling an answer from coordinates, facts, relations, constraints, and user preferences.

By the way, some routes also have corrupted data.

"Can not get city2: \"cat-ba-island\"",
"Can not get city2: \"cat-ba-island\"",
"Can not get city2: \"cat-ba-island\"",
"Can not get city: \"cat-ba-island\"",
"Can not get city: \"cat-ba-island\"",
"Can not get city: \"cat-ba-island\"",
"Can not get city2: \"phong-nha-ke-bang\"",
"Can not get city2: \"nam-du-island\"",
"Can not get city2: \"nam-du-island\"",
"Can not get city2: \"nam-du-island\"",
"Can not get city: \"nam-du-island\"",
"Can not get city: \"nam-du-island\"",

Need to fix this along the way.