Building Relay
Xây dựng một công ty nền tảng chat thời gian thực từ một thư mục trống — bao gồm đặc tả, mã nguồn, triển khai và giám sát.
Phần 0 — Ý tưởng và trang giấy
0.1 · Từ ứng dụng đến hạ tầng — đi tìm sản phẩm đích thực
Bạn sẽ tạo ra: Một bản tuyên ngôn định vị; một danh sách non-goals
0.2 · Bốn người sẽ phán xét chúng ta
Bạn sẽ tạo ra: Một bộ chân dung người dùng, bao gồm cả người dùng cuối vô hình
0.3 · Hành trình — nơi những sản phẩm gục ngã
Bạn sẽ tạo ra: Bản đồ hành trình; những khoảnh khắc ★
0.4 · Những yêu cầu bạn có thể kiểm chứng
Bạn sẽ tạo ra: Một lát cắt SRS với đầy đủ ID, độ ưu tiên và phương pháp kiểm chứng
0.5 · Quyết định trên giấy trắng mực đen — bản SAD và thói quen viết ADR
Bạn sẽ tạo ra: Bảng động lực thiết kế (drivers); hai bản ADR viết từ con số không
Phần 1 — Đặt nền móng
1.1 · Monorepo và bộ công cụ
Bạn sẽ tạo ra: Một pnpm workspace chạy được — TypeScript, lint, và bộ test xanh
1.2 · Một câu lệnh, cả thế giới
Bạn sẽ tạo ra: Hạ tầng local một câu lệnh — bốn store, có healthcheck và đã kiểm chứng
1.3 · Package protocol
Bạn sẽ tạo ra: Bản giao kèo đường truyền dùng chung — kiểu frame, mã lỗi, và schema biết từ chối dữ liệu hỏng
1.4 · Bộ khung biết đi
Bạn sẽ tạo ra: Hai service bộ khung chạy được — có health check, request ID, log JSON có cấu trúc
Phần 2 — Vòng lặp cốt lõi
2.1 · Schema có xương sống
Bạn sẽ tạo ra: Schema đã migrate và tầng repository khóa theo tenant — rò rỉ giữa các tenant thành điều không thể viết ra
2.2 · Quá trình gửi tin nhắn
Bạn sẽ tạo ra: Gửi tin nhắn: channel row lock và sequence assignment (ADR-03)
2.3 · Gửi hai lần
Bạn sẽ tạo ra: Idempotency keys, unique index một phần (DR-03)
2.4 · Lịch sử biết phân trang
Bạn sẽ tạo ra: Cursor pagination trên (channel_id, seq)
2.5 · Socket
Bạn sẽ tạo ra: Gateway: WS termination, JWT verify, connection registry
2.6 · Hai server, một cuộc trò chuyện
Bạn sẽ tạo ra: Redis fan-out (ADR-07); lập luận về fabric có thể mất frame
2.7 · Đường hầmhiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Resume protocol: cursor, backfill, buffer subscribe-trước-backfill
2.8 · Cột mốc: bài kiểm tra Tuan
Bạn sẽ tạo ra: Suite e2e cho journey 4 — tiêu chí thoát Phase 1
Phần 3 — Vươn mình thành nền tảng
3.1 · Tenant từ trên xuống dưới
Bạn sẽ tạo ra: Org, app, environment; signup bằng OAuth; environment dev tạo tự động
3.2 · Key và token — hai loại credential, một lỗi thường gặp
Bạn sẽ tạo ra: API keys (prefix, hash, rotation); user JWTs; endpoint dev-token
3.3 · Outbox
Bạn sẽ tạo ra: Transactional outbox + relay (ADR-06); crash-in-the-gap test
3.4 · JetStream và consumer đầu tiên
Bạn sẽ tạo ra: Cấu hình stream; subject grammar dùng chung; durable pull consumer tự dedupe
3.5 · Webhook sống sót qua phía khách hàng
Bạn sẽ tạo ra: Một dispatcher service: ký HMAC, lịch retry theo thời điểm tới hạn, dead letter
3.6 · Khi nào thì thôi cố
Bạn sẽ tạo ra: Bản ghi lần thử trên stream analytics, và auto-disable từ hai trigger
3.7 · Commit và publish là hai khoảnh khắc
Bạn sẽ tạo ra: Khép lại lỗi trùng lặp khi resume: một high-water mark sống lâu hơn buffer
3.8 · Những giới hạn bạn thấy trước
Bạn sẽ tạo ra: Bộ đếm request theo từng environment, các header trên mọi response, và hai bộ giới hạn hỏng theo hai hướng ngược nhau
3.9 · Email chẳng ai gửi
Bạn sẽ tạo ra: Mẫu outbox lần thứ ba, trên một cột mà chương 3.6 đã viết sẵn — và Mailpit, vì chỉ thư đã nhận mới chứng minh được email không mang bí mật nào
3.10 · Quota và cái giá của nóhiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Quota theo tháng, hạn mức chi tiêu, và cách suy giảm chỉ chặn gửi mà không ảnh hưởng history
3.11 · Đếm một kết nốihiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Connection-minutes được đo từ một service không sở hữu bảng nào, một cú crash tính thiếu trong một giới hạn đã biết thay vì tính thừa mãi mãi, và close code 4008 lần đầu được gửi kể từ khi chương 1.3 khai báo nó
3.12 · Cột mốc: cửa ải cô lập tenanthiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Một bộ kiểm thử cross-tenant tự suy ra danh sách mục tiêu từ router đang chạy, bốn dạng tấn công trên 24 route, một kiểm tra cấu trúc rằng mọi bảng đều có đường về tenant, tầng socket bị tấn công từ chính frame union của protocol, và ba lần cố ý tái tạo lỗi — một lần vẫn xanh và dạy ta giới hạn của bộ kiểm thử
3.13 · Các endpoint và các thiết bị đohiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Hai endpoint công khai mà Part 3 cần và chưa ai xây, tính đẳng xâm (idempotent) do unique index bảo đảm chứ không phải do bộ nhớ ứng dụng, mọi lỗi validation lần đầu tiên gọi tên field của nó, guard thao tác toàn cục canh chín bảng thay vì năm, và độ phủ nhánh của tầng repository được trả lời bằng một con số
3.14 · Cột mốc: lỗi có trang để xem, và một người ngoàihiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Mười ba error code với một registry và một luật URL duy nhất, một docs_url resolve được vào tài liệu đã xuất bản, một package tích hợp bị niêm phong về mặt cơ chế nên không thể import code trong workspace, và một phán quyết cho tiêu chí ra khỏi Phase 2 của SRS kèm những gì đã đo và những gì chỉ được giả định
3.15 · Kênh mà khách hàng kiểm soáthiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Một loại kênh private thực sự quyết định điều gì đó ở cả bốn cửa vào, xoá thành viên và phân quyền, lưu trữ kênh để từ chối gửi tin mà không tiết lộ kênh có tồn tại, và một gauntlet tấn công chính tenant của bạn
3.16 · Những gì một người dùng thấyhiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Danh sách channel phân trang bằng cursor và xếp theo hoạt động, số tin chưa đọc suy ra từ chính sequence mà đường ghi vẫn duy trì, profile người dùng được tạo ngầm ở lần xác thực đầu tiên, một người dùng đã xoá mà tin nhắn vẫn còn, và một lệnh ban có hiệu lực cả ở cửa vào lẫn trên đường gửi
3.17 · Người gửi mà một tin nhắn chưa từng cóhiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Bot user mang theo một description mà cơ sở dữ liệu bắt buộc phải có, một người gửi bắt buộc trên mọi tin nhắn và được chính trình biên dịch bảo đảm thay vì một bài test, một application credential chỉ được nói với danh nghĩa phần mềm chứ không phải bất kỳ con người nào, những lời từ chối không hé ra ai đang tồn tại, và một bot vẫn được tính tiền như active user nhưng được miễn khỏi cái ngưỡng vốn từ chối tin gửi
3.18 · Tin nhắn chưa từng tớihiện chỉ có bản tiếng Anh
Bạn sẽ tạo ra: Một tin nhắn gửi qua REST tới được socket đang mở, một thứ tự phải tách theo transport vì response của một request handler CHÍNH LÀ acknowledgement của nó, một publisher sống sót qua broker đã chết trong 2 ms ở nơi client của gateway treo vô hạn, và một điều khoản P1 được đo là chưa thoả mãn rồi ghi lại thay vì bị thu hẹp
3.19 · Presence, và ai được phép nhìn thấy
Bạn sẽ tạo ra: Một frame đã nằm trong protocol union từ chương 1.3 mà chưa từng có producer, một subject grammar thứ hai giữ nguyên từng byte của đường đi message, một key mà sự tồn tại của nó chính là trạng thái và SET … NX của nó chính là cuộc bầu chọn, một grace period mà bản vá đầu tiên khiến người dùng mắc kẹt online vĩnh viễn, và một phạm vi chuyển giao không có lấy một dòng code lọc nào
3.20 · Membership đổi ngay dưới một socket đang sống
Bạn sẽ tạo ra: Một điều khoản chưa được thoả từ chương 2.6 và bị một bài test khẳng định là vi phạm từ 3.18, nay đóng lại bằng chính bài test đó đảo ngược với thời gian chờ 5.500 ms giữ nguyên; một ngữ pháp subject thứ ba mà hình dạng thứ hai gửi tới một principal thay vì một channel, bởi một lần thêm thành viên không thể đi nhờ cái subject mà chính instance của nó chưa subscribe; một lệnh ban tới nơi như một thay đổi và rời đi thành một frame cho mỗi channel, với ký hiệu canh gác không bao giờ chạm tới client; và một lần đọc lại định kỳ đứng thay cho một cursor không tồn tại
3.21 · Cái frame không ai được gửi
Bạn sẽ tạo ra: Frame đầu vào thứ hai đầu tiên sau hai mươi chương, đứng sau một tập hợp có tên mà một bài test ghim cả kích thước lẫn thành viên; một ngữ pháp subject thứ tư được nhận chứ không phải né, sau khi đếm lại con số của ADR-19 và tìm thấy bảy điểm được định kiểu chứ không phải ba như bản ghi viết; một khoảng renew hai giây vốn là đại lượng khác với hạn năm giây của FR-RTM-08, ở mức 2,5 lần renew mỗi cửa sổ nên một lần publish bị rơi không làm nhấp nháy; và một phán quyết thành thật về một điều khoản nền tảng này không thực hiện được — không frame nào kết thúc một chỉ báo, nên timer thuộc về bên nhận
3.22 · Kết nối thứ sáu, và con số ấy sống ở đâu
Bạn sẽ tạo ra: FR-RTM-09 đóng lại ở cả hai nửa: một cái trần năm kết nối mà không instance gateway nào tự tính được, giữ dưới dạng năm khoá slot giành bằng `SET NX PX` và gia hạn bằng `SET IFEQ PX`; một mã đóng thứ sáu, vì cả năm mã cũ đều đẩy client tới phương thuốc sai còn đây là lời từ chối duy nhất trong bộ mà cách xử lý đúng không phải là thử lại; một lời từ chối hoàn tất cái bắt tay chỉ để đóng nó, vì trình duyệt không đọc được thân phản hồi của một lần upgrade thất bại; và một cái trần hỏng theo hướng mở một cách ồn ào, nơi dòng log là thứ duy nhất phân biệt `unenforced` với `dưới mức trần`
3.23 · Những lời ai đó muốn lấy lại
Bạn sẽ tạo ra: FR-MSG-07, FR-MSG-08 và FR-MSG-10 được dựng, và hai kind cuối trong sáu kind của FR-RTM-05 lần đầu có bên phát: một ngữ pháp subject thứ năm, `revision:{channel_id}`, mang cả hai loại thay đổi với cái kind nằm trong payload, bởi một bia mộ không phải `Message` còn một lần sửa thì là và sẽ không phân biệt được với một lần tạo; bảng `message_edits` dựng lại đúng như SAD §6.1 đã công bố, kèm cái giá của khoá chính ghép được viết ra; hai mã lỗi thay cho 403 chung chung, bởi không credential nào cấp quyền tác giả và không thay đổi phân quyền nào biến một tin nhắn thành của bạn; một phép kiểm tenancy được dạy rằng khả năng tới được không phải là kề nhau, sau khi nó từ chối cái bảng mới trong bốn mili giây; và cái mép mềm duy nhất được ghi lại thay vì đóng lại — một tin nhắn cũ hơn con trỏ của client mà đổi trong lúc mất kết nối thì không sinh frame nào **và không có lỗ hổng số thứ tự nào**, nên cơ chế sửa chữa mọi frame bị lỡ khác chẳng thấy gì để sửa
3.24 · Tin nhắn không chỉ có chữ
Bạn sẽ tạo ra: Nửa external-URL của FR-MSG-11 được dựng: một tin nhắn mang attachment, giới hạn mười phần tử và 2.048 ký tự, bị từ chối trừ khi scheme là http hoặc https. Nửa media_id được hoãn tới §4.14 và bị từ chối đích danh, bằng một mã lỗi riêng.
Chặng đường phía trước
- Phần 4Con đường dữ liệu thứ haisắp ra mắt
- Phần 5Trải nghiệm lập trình viênsắp ra mắt
- Phần 6Ship sản phẩmsắp ra mắt
- Phần 7Vận hànhsắp ra mắt
- Phần 8Nhìn lại chặng đườngsắp ra mắt