SnapDTU  /  Tài liệu sản phẩm
Tài liệu kỹ thuật sản phẩm

Tài liệu sản phẩm &
Kiến trúc hệ thống

Đặc tả chi tiết về tính năng, quy trình người dùng và kiến trúc kỹ thuật của SnapDTU — ứng dụng chia sẻ ảnh hàng ngày dành riêng cho sinh viên Đại học Duy Tân. Toàn bộ hệ thống được thiết kế và xây dựng nội bộ: hai ứng dụng native iOS & Android dùng chung một backend riêng trên Cloudflare và Firebase.

Đang trong giai đoạn beta iOS 17+ & Android 8+ (native) Backend tự xây dựng Đăng nhập myDTU
01 — Tổng quan

SnapDTU là gì

SnapDTU là một mạng xã hội chia sẻ ảnh theo ngày, dành riêng cho cộng đồng sinh viên Đại học Duy Tân (DTU), Đà Nẵng. Mỗi sinh viên đăng nhập bằng chính tài khoản myDTU của trường, nên lớp, khoa và lịch học được nhận diện tự động — cộng đồng trong app là 100% sinh viên DTU thật.

Triết lý sản phẩm xoay quanh sự chân thật và chọn lọc: mỗi người chỉ đăng tối đa 3 ảnh/ngày, và muốn xem ảnh của bạn bè thì phải góp một khoảnh khắc của chính mình. Kết quả là một feed thật, gần gũi, theo từng lớp học và khuôn viên.

Đối tượng
Sinh viên Đại học Duy TânXác thực bằng tài khoản myDTU của trường
Nền tảng
iOS 17+ & Android 8+Hai ứng dụng native, không phải web/hybrid
Kiến trúc
Native client + edge backendCloudflare Workers/R2 · Firebase · Google Vision
Phạm vi
Theo lớp · khoa · trườngCó cổng vị trí quanh 4 cơ sở DTU
Vì sao đây là phần mềm độc quyền

SnapDTU không dựng trên template hay nền tảng dựng-app có sẵn. Toàn bộ logic nghiệp vụ — tích hợp đăng nhập myDTU, cộng đồng theo môn học, cổng vị trí khuôn viên, thuật toán xếp hạng feed, đường ống kiểm duyệt ảnh tự động và bộ máy nhắc nhở theo lịch học — đều do đội ngũ tự thiết kế và lập trình. Hai ứng dụng native dùng chung một backend serverless tự vận hành. Các phần sau mô tả cụ thể từng thành phần đó.

02 — Tính năng

Đặc tả tính năng

SnapDTU gồm các nhóm tính năng sau, mỗi tính năng kèm tham số nghiệp vụ thực tế đang chạy trong hệ thống.

Đăng nhập bằng myDTU (SSO trường)

Sinh viên đăng nhập bằng tài khoản myDTU. Mật khẩu chỉ dùng một lần để xác thực qua lớp proxy ở backend và không bao giờ được lưu; sau đó app hoạt động bằng phiên đăng nhập riêng của Firebase. Hồ sơ (mã sinh viên, họ tên, lớp, khoa, khoá) được đồng bộ tự động. Ngoài ra hỗ trợ liên kết Google và Apple, một tài khoản gắn nhiều phương thức.

mật khẩu không lưuphiên Firebase 30 ngày tự gia hạnGoogle · Apple link

Chụp & đăng ảnh hàng ngày

Chụp ảnh ngay trong app (chế độ chụp im lặng, không tiếng màn trập) và đăng với phạm vi tự chọn. Giới hạn 3 ảnh/ngày, làm mới lúc 0h00. Khi đăng vào lớp, ảnh được gắn cộng đồng môn học tương ứng.

tối đa 3 ảnh/ngàyreset 0h00scope class · faculty · schoolsilent capture

Cổng "đăng để xem" (feed gate)

Chưa đăng ảnh hôm nay, sinh viên chỉ xem được 5 ảnh đầu trong feed; ảnh thứ 6 trở đi bị làm mờ kèm lời mời đăng ảnh. Chỉ cần đăng 1 ảnh là mở khoá xem không giới hạn đến hết ngày. Đây là cơ chế cốt lõi giữ feed luôn có sự tham gia hai chiều.

xem trước 5 ảnhđăng 1 ảnh → mở khoá vô hạn

Cổng vị trí khuôn viên DTU

Khi đăng ảnh vào lớp, thiết bị phải nằm trong bán kính 500m quanh một trong các cơ sở của DTU. Hệ thống tự nhận cơ sở gần nhất; backend là nơi xác thực sau cùng và từ chối (403) nếu ngoài vùng. Ảnh hợp lệ được gắn toạ độ và mã cơ sở để hiển thị trên bản đồ hồ sơ.

bán kính 500m4 cơ sở DTUkhoảng cách Haversinebackend authoritative

Cộng đồng theo môn học

Lịch học (TKB) được đồng bộ trực tiếp từ myDTU. Mỗi môn được gom thành một cộng đồng theo khoá định danh ổn định {termId}-{mã môn}, nên mọi lớp của cùng một môn chia sẻ chung một feed. Thành viên được thêm tự động theo lịch học, không cần mời thủ công.

key {termId}-{subjectSlug}thành viên tự độngfeed riêng/môn

Thuật toán xếp hạng feed

Feed không xếp theo thời gian thuần. Mỗi bài có điểm feed_score tổng hợp từ ba yếu tố có trọng số, ưu tiên nội dung gần gũi và mới mẻ trong cộng đồng của bạn.

recency 40%engagement 30%proximity 30%20 bài/trang

Kiểm duyệt ảnh tự động 3 tầng

Mọi ảnh được quét bằng Google Vision SafeSearch trước khi hiển thị. Kết quả phân theo ba tầng xử lý: chặn ngay và hạn chế người dùng, đưa vào hàng đợi duyệt thủ công, hoặc đăng tự động — toàn bộ có nhật ký kiểm toán.

Google Vision SafeSearchchặn · chờ duyệt · đănghạn chế 24h khi vi phạm nặng

Tương tác realtime & an toàn cộng đồng

Thả tim và bình luận đồng bộ realtime giữa các thiết bị (cập nhật optimistic ở client, đếm chính xác qua Cloud Functions). Bình luận được lọc từ ngữ không phù hợp ở cả client và server. Người dùng có thể báo cáo hoặc chặn người khác; nội dung bị nhiều báo cáo sẽ vào hàng đợi duyệt.

like & comment realtimeprofanity filter 2 lớpreport & block

Nhắc nhở & chủ đề mỗi ngày

Mỗi ngày hệ thống đăng một "chủ đề hôm nay" và gửi push nhắc đăng ảnh vào các khung giờ trong ngày. Bộ máy nhắc nhở chạy trên Cloudflare (cron + D1 + queues), prefetch danh sách người dùng từ tối hôm trước rồi gửi theo lô qua FCM/APNs. Người dùng có thể tắt nhắc nhở trong Cài đặt.

chủ đề/ngày4 mốc nhắc/ngàyFCM + APNsopt-out

Hồ sơ: timeline, streak, kỷ yếu, bản đồ ảnh

Trang cá nhân tổng hợp ảnh theo dòng thời gian từng tháng, chuỗi ngày đăng liên tiếp (streak), lưới "kỷ yếu" ảnh và bản đồ những nơi đã chụp gần các cơ sở DTU. Ảnh cá nhân (không đăng vào lớp) được lưu kho riêng, không vào feed công khai.

timeline theo thángstreakbản đồ ảnhkho ảnh cá nhân

Bảng quản trị (admin console)

Console web riêng cho vận hành: duyệt hàng đợi kiểm duyệt, quản lý hạn chế người dùng, xem nhật ký kiểm duyệt và cấu hình runtime (ví dụ số ảnh tối đa/ngày, bật/tắt cổng vị trí) mà không cần phát hành lại app.

duyệt thủ côngcấu hình runtimetách Dev/Prod
03 — Quy trình

Quy trình người dùng

Bốn luồng nghiệp vụ chính, từ tương tác của người dùng đến xử lý ở backend.

A. Đăng nhập myDTU → phiên Firebase
  1. Nhập tài khoản myDTUSinh viên nhập tài khoản trường trên màn đăng nhập (iOS/Android).
  2. App gửi lên backend qua kênh mã hoáThông tin được gửi tới lớp proxy ở Cloudflare Workers, không gửi thẳng từ client tới đâu khác.
  3. Backend xác thực với hệ thống trườngWorkers xác thực với myDTU, nhận hồ sơ sinh viên rồi loại bỏ mật khẩu — không lưu ở bất kỳ đâu.
  4. Tạo custom token FirebaseBackend ký một custom token và đồng bộ hồ sơ vào Firestore (users/{uid}).
  5. App đổi token lấy phiên đăng nhậpClient gọi signIn(withCustomToken:); từ đây mọi truy cập dùng phiên Firebase, tự gia hạn 30 ngày.
  6. Đồng bộ lịch học & hoàn tấtApp tải TKB và hồ sơ, vào màn chính.
B. Chụp → upload → kiểm duyệt → đăng
  1. Chụp & chọn phạm viNgười dùng chụp ảnh và chọn scope: lớp, khoa hay trường.
  2. Tải lên backendẢnh nén được gửi tới Workers kèm token và metadata (scope, mã môn, toạ độ nếu có).
  3. Backend kiểm tra điều kiệnXác thực token, kiểm tra hạn mức 3 ảnh/ngày, và cổng vị trí 500m nếu đăng vào lớp.
  4. Lưu vào kho chờ duyệt (R2)Ảnh được lưu vào bucket R2 tạm; tạo bản ghi bài viết trạng thái processing.
  5. Hàng đợi kiểm duyệtSự kiện đẩy vào Cloudflare Queues; consumer gọi Google Vision SafeSearch.
  6. Quyết định 3 tầngChặn (vi phạm nặng → xoá + hạn chế 24h), chờ duyệt (đưa vào hàng đợi thủ công), hoặc đăng (chuyển sang bucket công khai).
  7. App cập nhật realtimeClient lắng nghe trạng thái bài viết và hiển thị kết quả tức thì (đã đăng / đang xét / bị từ chối).
C. Xem feed & mở khoá cổng 5 ảnh
  1. Tải feedClient truy vấn các bài published, sắp theo feed_score giảm dần, 20 bài/trang.
  2. Đếm lượt xemNếu hôm nay chưa đăng, mỗi ảnh xem qua được đếm vào hạn mức xem miễn phí.
  3. Chạm cổng ở ảnh thứ 6Ảnh từ thứ 6 bị làm mờ kèm CTA "Đăng 1 ảnh để xem không giới hạn".
  4. Người dùng đăng ảnhSau khi đăng thành công, cờ "đã đăng hôm nay" bật lên.
  5. Mở khoá xem vô hạnFeed dựng lại, gỡ cổng; tự prefetch trang tiếp khi gần hết.
D. Bộ máy nhắc nhở hằng ngày
  1. Đăng chủ đề trong ngàyCloud Function tạo "chủ đề hôm nay" lúc nửa đêm (giờ VN).
  2. Prefetch tối hôm trướcCron quét người dùng bật nhắc nhở, đẩy vào queue, lấy sẵn FCM token vào D1.
  3. Cron các khung giờĐến các mốc trong ngày, job gửi đọc danh sách đã prefetch từ D1.
  4. Gửi theo lô qua FCM/APNsWorker gửi push hàng loạt; iOS qua APNs, Android qua FCM, có gộp thông báo chống spam.
  5. Người dùng nhận & mở appChạm thông báo mở thẳng màn chụp/đúng bài liên quan.
04 — Kiến trúc

Kiến trúc kỹ thuật

SnapDTU theo mô hình native client + backend serverless ở biên (edge). Client không gọi thẳng tới dịch vụ bên thứ ba nhạy cảm; mọi nghiệp vụ nhạy cảm đi qua lớp Cloudflare Workers đặt gần người dùng.

Sơ đồ hệ thống

Client
iOS Swift · SwiftUI
Android Kotlin · Compose
Edge / Backend
Cloudflare Workers TypeScript · Hono
Cloud Functions triggers · cron
Dữ liệu & dịch vụ
Firestore realtime DB
R2 lưu ảnh
D1 lịch nhắc
Vision · FCM/APNs

Ngăn xếp công nghệ

LớpCông nghệVai trò
iOSSwift + SwiftUI (iOS 17+), Kingfisher, Firebase SDKỨng dụng native iPhone
AndroidKotlin + Jetpack Compose Material3 (minSdk 26), Retrofit, Firebase SDKỨng dụng native Android
HTTP edgeCloudflare Workers (TypeScript, Hono)Auth proxy, upload, đồng bộ lịch, kiểm duyệt, admin API
Trigger & cronFirebase Cloud Functions (TypeScript)Đếm tim/bình luận, thông báo, chủ đề hằng ngày
Cơ sở dữ liệuFirebase FirestoreHồ sơ, bài viết, môn học, hàng đợi duyệt — realtime listeners
Lưu trữ ảnhCloudflare R2Bucket chờ duyệt → bucket công khai (zero egress)
Kiểm duyệtGoogle Vision SafeSearchPhân loại nội dung ảnh tự động
PushFCM + APNsThông báo tim/bình luận, nhắc nhở
Lịch nhắcCloudflare D1 + Queues + CronPrefetch & gửi nhắc nhở theo khung giờ

Các luồng dữ liệu chính

  • Xác thực: client → Workers (proxy myDTU) → tạo custom token → Firebase Auth → client lưu phiên an toàn.
  • Đăng ảnh: client → Workers (kiểm hạn mức + vị trí) → R2 chờ duyệt → Queue → Vision → cập nhật Firestore → client nhận realtime.
  • Thông báo: sự kiện (tim/bình luận/nhắc) → Functions/Workers → tra FCM token → gửi qua FCM/APNs → deep-link mở đúng màn.
  • Kiểm duyệt: sự kiện R2 → Queue consumer → Vision SafeSearch → cây quyết định 3 tầng → cập nhật trạng thái + ghi nhật ký kiểm toán.
05 — Độc quyền

Năng lực tự xây dựng

Những thành phần dưới đây là logic nghiệp vụ riêng của SnapDTU, không có sẵn ở bất kỳ nền tảng dựng-app nào — đây là phần lõi tạo nên tính độc quyền của sản phẩm.

Tích hợp đăng nhập myDTU

Lớp xác thực riêng giúp sinh viên dùng tài khoản trường, ánh xạ lớp/khoa/khoá vào hồ sơ mà mật khẩu không bao giờ được lưu.

Cộng đồng theo môn học

Cơ chế định danh môn ổn định {termId}-{mã môn} gom mọi lớp của cùng một môn vào một cộng đồng, thành viên tự động theo TKB.

Cổng vị trí khuôn viên

Geofence 500m quanh 4 cơ sở DTU, xác thực ở backend bằng khoảng cách Haversine — gắn ảnh với khuôn viên thật.

Thuật toán feed_score

Công thức xếp hạng riêng cân bằng recency 40% / engagement 30% / proximity 30%, ưu tiên nội dung gần gũi trong cộng đồng.

Đường ống kiểm duyệt 3 tầng

Tự động hoá Google Vision với ngưỡng phân tầng riêng, hàng đợi duyệt thủ công và hạn chế người dùng luỹ tiến, có nhật ký kiểm toán.

Bộ máy nhắc nhở trên D1

Lịch nhắc đặt trên Cloudflare D1 với kiến trúc 2 pha prefetch + gửi theo lô, không phụ thuộc dịch vụ gửi tin bên thứ ba.

Hai app native, một backend

iOS và Android dùng chung một backend duy nhất — đồng bộ chéo realtime, không fork API, chi phí bảo trì tối thiểu.

Console quản trị cấu hình runtime

Bảng admin cho phép đổi tham số vận hành (số ảnh/ngày, cổng vị trí…) tức thời mà không cần phát hành lại app.

06 — Tham chiếu

Bảng tham chiếu kỹ thuật

Tham số & hạn mức nghiệp vụ

Tham sốGiá trịGhi chú
Ảnh tối đa/ngày3 (cấu hình runtime)Reset 0h00; admin chỉnh được
Xem trước khi chưa đăng5 ảnhĐăng 1 ảnh → xem vô hạn
Bán kính cổng vị trí500 métQuanh 4 cơ sở DTU
Trọng số feed_score40 / 30 / 30recency / engagement / proximity
Phân trang feed20 bài/trangPrefetch khi còn ~3 bài
Độ dài bình luận≤ 500 ký tựLọc từ ngữ 2 lớp
Nhắc nhở/ngày4 mốcTheo khung giờ trong ngày (giờ VN)
Hạn chế khi vi phạm nặng24 giờ (luỹ tiến)Tái phạm tăng mức

Nhóm endpoint backend (đại diện)

EndpointMục đíchXác thực
POST /auth/mydtuĐổi tài khoản myDTU lấy phiên FirebaseKhông (proxy)
PUT /upload/imageTải ảnh + metadata để kiểm duyệtToken Firebase
POST /schedule/syncĐồng bộ TKB từ myDTUToken Firebase
GET /schedule/liveLấy lịch học trực tiếpToken Firebase
GET /admin/*Duyệt nội dung, cấu hình runtimeToken Firebase (admin)

Bộ sưu tập Firestore chính

Bộ sưu tậpNội dung
usersHồ sơ sinh viên, hạn mức ngày, FCM token, tuỳ chọn thông báo, kho ảnh cá nhân con
postsBài viết (scope, trạng thái, like/comment count, feed_score) + subcollection likes/comments/reports
coursesMôn học + sessions (lịch) + members (thành viên) + posts (bài theo lớp)
daily_promptsChủ đề ảnh theo từng ngày
review_queue · moderation_logHàng đợi duyệt thủ công & nhật ký kiểm toán kiểm duyệt