-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdynamic.yaml
More file actions
96 lines (84 loc) · 5.36 KB
/
Copy pathdynamic.yaml
File metadata and controls
96 lines (84 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# staticine dynamic layer — PocketBase (machine-readable)
# Lớp dynamic NHỎ, TÁCH HẲN read path. Reads (catalog/phim) vẫn 100% static R2+CDN.
# PocketBase = 1 binary (SQLite + Auth + Realtime + rules + admin) trên 1 VPS ~$5.
version: v1
invariant:
- "Dynamic box ⟂ read path: catalog/phim/proxy KHÔNG bao giờ hỏi PocketBase"
- "PB sập -> xem phim + watch-progress LOCAL vẫn chạy; chỉ tạm mất sync/comment (degrade)"
- "Client local-first (IndexedDB); PB chỉ để sync đa thiết bị + comment shared"
topology:
read_domain: "cdn.example -> R2 + Cloudflare (static, no server)"
proxy_domain: "px.example -> Worker/Pages Fn (video proxy /p/*)"
api_domain: "api.example -> PocketBase sau Cloudflare (proxy on)"
why_behind_cf: "cache GET comment-list (TTL ngắn) -> offload VPS; che IP gốc; CORS"
# ── Collections ──────────────────────────────────────────────────────────────
collections:
users: # auth collection (built-in)
type: auth
extra_fields: { name: text, avatar: file|url }
oauth: [google, discord, github, email]
user_record: # sync watchlist/watch-progress/history/settings (per-user)
fields:
uid: "relation(users)"
type: "select: watchlist | progress | history | setting"
rkey: "text" # titleId | partId | settingKey
data: "json" # progress: { posSec, dur, partId, at } ; watchlist: { addedAt }
updatedAt: "number(ms)" # client-supplied, cho LWW
deleted: "bool" # tombstone (xoá đa thiết bị)
index: "UNIQUE (uid, type, rkey)"
rules:
list: "uid = @request.auth.id"
view: "uid = @request.auth.id"
create: '@request.auth.id != "" && uid = @request.auth.id'
update: "uid = @request.auth.id"
delete: "uid = @request.auth.id"
lww_hook: "pb_hooks onRecordBeforeUpdate: từ chối nếu incoming.updatedAt <= stored.updatedAt"
note: "progress = vị trí phát (posSec) để 'Xem tiếp'; LWW theo updatedAt giữa thiết bị"
comments: # shared/public — phim/tập
fields:
target: "text (titleId | partId)"
uid: "relation(users)"
body: "text (max 2000)"
parent: "relation(comments) | null" # reply 1 cấp
spoiler: "bool (default false)" # ẩn nội dung spoiler phim
score: "number (default 0)"
deleted: "bool"
rules:
list: "deleted = false"
view: "deleted = false"
create: '@request.auth.id != "" && uid = @request.auth.id'
update: "uid = @request.auth.id"
delete: "uid = @request.auth.id"
author: "expand(uid) lấy name/avatar — khỏi denorm"
abuse_hook: "pb_hooks onRecordBeforeCreate: rate-limit/uid + word-filter + verify Turnstile"
comment_votes:
fields: { uid: "relation(users)", comment: "relation(comments)", value: "number(-1|1)" }
index: "UNIQUE (uid, comment)"
rules: { create: '@request.auth.id != ""', update: "uid = @request.auth.id" }
ratings: # đánh giá phim của user (tuỳ chọn)
fields: { uid: "relation(users)", target: "text (titleId)", value: "number(1..10)" }
index: "UNIQUE (uid, target)"
rules: { create: '@request.auth.id != ""', update: "uid = @request.auth.id", list: "true" }
reports: # moderation
fields: { uid: "relation(users)", target: text, reason: text }
rules: { create: '@request.auth.id != ""', list: "@request.auth.id != '' && @collection.users.id ?= moderators" }
# ── Sync model (per-record LWW + delta + tombstone) ─────────────────────────
sync:
client: "local-first IndexedDB; ghi LOCAL tức thì + queue đẩy PB (debounce)"
push: "upsert user_record qua SDK (POST mới / PATCH nếu incoming.updatedAt lớn hơn)"
pull: "list user_record filter 'updated > {lastSyncAt}' (chỉ của mình) -> merge LWW vào IndexedDB"
delete: "tombstone (deleted=1, giữ updatedAt) -> propagate xoá"
anon_merge: "đăng nhập lần đầu -> đẩy watch-progress anon (IndexedDB) lên account"
progress_write: "player throttle ghi posSec (vd mỗi 5s/khi pause) -> IndexedDB + queue PB"
# ── Comments read strategy ──────────────────────────────────────────────────
comments_read:
default: "client-direct list theo target + Realtime subscribe (live)"
offload: "đặt PocketBase sau Cloudflare; cache GET list TTL ngắn -> VPS nhẹ tải"
scale_option: "phim viral: hook regen static /v1/comments/{target}/0.json lên R2 (read 0-cost)"
# ── Deploy ───────────────────────────────────────────────────────────────────
deploy:
host: "VPS ~$5 (hoặc Fly/Railway); 1 binary pocketbase serve"
data: "pb_data/ (1 file SQLite) — own toàn bộ"
backup: "litestream -> R2 (continuous) hoặc cp định kỳ"
front: "Cloudflare proxy (cache comment GET, CORS, che origin)"
cost: "~$5/tháng; read path + xem phim vẫn $0/static + edge proxy"