chore(doc):Apply a unified bold underline style to the links

This commit is contained in:
david_bai
2025-12-27 10:50:04 +08:00
parent 4328cd0a1c
commit bb90d0c0fd
14 changed files with 214 additions and 214 deletions
@@ -36,10 +36,10 @@ Am Ende hast du eine minimale Struktur, die du in jedes Repo kopieren kannst:
- `docs/ai-playbook/collab-rules.md`: Kollaborationsregeln + ChangePlanTemplate (wie wir arbeiten)
Alle Beispiele stammen aus dem OpenSourceRepo PrivyDrop:
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
Und OpenAI hat kürzlich eine sehr ähnliche Praxisperspektive veröffentlicht:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -93,7 +93,7 @@ In PrivyDrop reichen fünf Punkte:
- Docs must stay in sync: `AGENTS.en.md:12`
- Verification required: `AGENTS.en.md:13`
Datei: [AGENTS.en.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
Datei: [<u>**AGENTS.en.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
Minimale StarterStruktur:
@@ -138,7 +138,7 @@ Das IndexDokument soll:
- in 30 Sekunden lesbar sein (Snapshot + LinkIndex)
- per Klick zu code-map / flows / collab-rules führen
Referenz: [docs/ai-playbook/index.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
Referenz: [<u>**docs/ai-playbook/index.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
MinimalTemplate:
@@ -167,7 +167,7 @@ Ziel: schnelle Orientierung, nicht Vollständigkeit.
- pro EntryFile ein Satz: Verantwortlichkeit
- bei einer Anfrage: erst 38 Kandidaten aus der CodeMap, dann DeepDive
Referenz: [docs/ai-playbook/code-map.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Referenz: [<u>**docs/ai-playbook/code-map.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Optional: „Common requests → Entry Points“:
@@ -188,7 +188,7 @@ Wenn code-map „wo“ beantwortet, beantwortet flows „wie“. Das verhindert
- Sequenz + Invarianten => weniger „BauchgefühlPatches“
- DebugPitfalls werden zur wiederverwendbaren Checklist
Referenz: [docs/ai-playbook/flows.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
Referenz: [<u>**docs/ai-playbook/flows.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
Mindestens enthalten:
@@ -203,7 +203,7 @@ Mindestens enthalten:
Der echte Hebel: Reviews nach vorne ziehen—vom „Diff lesen“ zum „Plan lesen“.
Template in `collab-rules.md` fixieren:
[docs/ai-playbook/collab-rules.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
[<u>**docs/ai-playbook/collab-rules.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
```text
Title: <short, clear title>
@@ -300,7 +300,7 @@ Please deeply read relevant docs/code. Think systematically, ask clarifying ques
## IndustryReferenz: OpenAI und Codex
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -30,10 +30,10 @@ By the end, youll have a minimal structure you can copy into any repo:
- `docs/ai-playbook/collab-rules.md`: collaboration rules + change-plan template (how we work)
All examples come from the open-source project PrivyDrop—feel free to follow along:
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
Also, OpenAI recently published a hands-on write-up with a very similar mindset:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -87,7 +87,7 @@ In PrivyDrop, five lines are enough to cover the core of engineering collaborati
- Docs must stay in sync: `AGENTS.en.md:12`
- Verification required: `AGENTS.en.md:13`
File: [AGENTS.en.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
File: [<u>**AGENTS.en.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
If you want a minimal starter, heres a good shape (keep it short, strict, and executable):
@@ -132,7 +132,7 @@ Your index page should do two things:
- Readable in 30 seconds: only “project snapshot + link index”
- One-click navigation: send readers/AI to code-map / flows / collab-rules
Reference implementation: [docs/ai-playbook/index.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
Reference implementation: [<u>**docs/ai-playbook/index.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
Minimal template (copy-pasteable):
@@ -161,7 +161,7 @@ The code map is for “fast navigation,” not “teaching you how to implement.
- One sentence per entry file: what its responsible for
- When a new request arrives: hit 38 candidate files in the code map before deep reading
Reference implementation: [docs/ai-playbook/code-map.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Reference implementation: [<u>**docs/ai-playbook/code-map.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Optional: add a “common requests → entry points” cheat sheet to reduce search cost further:
@@ -187,7 +187,7 @@ If code-map answers “where to change,” flows answers “how it runs.” This
- If you write down the sequence and invariants, AI stops “patching by vibes”
- You can compress past pitfalls into a reusable debug checklist
Reference implementation: [docs/ai-playbook/flows.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md) (with split deep dives)
Reference implementation: [<u>**docs/ai-playbook/flows.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md) (with split deep dives)
At minimum, include:
@@ -208,7 +208,7 @@ This is where the speed-up really comes from: move the review earlier—from “
Put the plan template in `collab-rules.md` and treat it as a hard constraint.
PrivyDrop template: [docs/ai-playbook/collab-rules.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
PrivyDrop template: [<u>**docs/ai-playbook/collab-rules.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
You can reuse this structure directly (goals/scope/approach/risks/acceptance/rollback/validation):
@@ -334,7 +334,7 @@ Please deeply read relevant docs/code. Think systematically, ask clarifying ques
## Industry reference: How OpenAI uses Codex to run a sprint
In “How we used Codex to build Sora for Android in 28 days,” OpenAI describes a workflow that matches this playbook closely:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
Key points to align with:
@@ -369,7 +369,7 @@ If you already have docs scattered everywhere: start with `index.md` to unify en
## 🚀 Next steps
1. **Start now**: copy the minimal structure into your repo and begin with `AGENTS.md`
2. **Reference implementation**: visit [PrivyDrop GitHub](https://github.com/david-bai00/PrivyDrop) and browse the full AI Playbook
2. **Reference implementation**: visit [<u>**PrivyDrop GitHub**</u>](https://github.com/david-bai00/PrivyDrop) and browse the full AI Playbook
3. **Feedback**: if this helps (or you hit pitfalls), open an issue on GitHub or leave a comment
4. **Star**: if its valuable, consider starring PrivyDrop 🌟
@@ -36,10 +36,10 @@ Al final tendrás una estructura mínima que puedes copiar a cualquier repositor
- `docs/ai-playbook/collab-rules.md`: reglas de colaboración + plantilla de plan de cambio (cómo trabajamos)
Todos los ejemplos vienen del repo open source PrivyDrop (puedes comparar con la implementación):
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
Y esta práctica de OpenAI tiene una filosofía muy similar:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -93,7 +93,7 @@ En PrivyDrop, cinco puntos bastan para cubrir el núcleo:
- Docs must stay in sync: `AGENTS.en.md:12`
- Verification required: `AGENTS.en.md:13`
Archivo: [AGENTS.en.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
Archivo: [<u>**AGENTS.en.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
Plantilla mínima sugerida (corta, estricta y accionable):
@@ -138,7 +138,7 @@ El index debe lograr dos cosas:
- Se lee en 30 segundos: solo “snapshot del proyecto + índice de enlaces”
- Navegación de un clic: llevar a code-map / flows / collab-rules
Referencia: [docs/ai-playbook/index.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
Referencia: [<u>**docs/ai-playbook/index.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
Plantilla mínima:
@@ -167,7 +167,7 @@ El objetivo es “localizar rápido”, no “enseñar a implementar”:
- Una frase por archivo: su responsabilidad
- Al llegar una solicitud: identifica 38 candidatos en code-map antes de leer en profundidad
Referencia: [docs/ai-playbook/code-map.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Referencia: [<u>**docs/ai-playbook/code-map.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Opcional: añade una tabla de “solicitud común → entry points”:
@@ -193,7 +193,7 @@ Si code-map responde “dónde tocar”, flows responde “cómo corre”. Para
- Con secuencia + invariantes claros, deja de “parchear por intuición”
- Los pitfalls históricos se vuelven checklist reutilizable
Referencia: [docs/ai-playbook/flows.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
Referencia: [<u>**docs/ai-playbook/flows.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
Incluye al menos:
@@ -214,7 +214,7 @@ Aquí está el acelerador: mover el review de “leer el diff” a “leer el pl
Fija una plantilla en `collab-rules.md` y úsala como regla dura.
Plantilla PrivyDrop: [docs/ai-playbook/collab-rules.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
Plantilla PrivyDrop: [<u>**docs/ai-playbook/collab-rules.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
Estructura reutilizable:
@@ -330,7 +330,7 @@ Please deeply read relevant docs/code. Think systematically, ask clarifying ques
## Referencia de industria: cómo OpenAI organiza un sprint con Codex
OpenAI describe un flujo muy parecido aquí:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
Puntos a alinear:
@@ -363,7 +363,7 @@ Si ya tienes docs dispersas: empieza por `index.md` para unificar el acceso; lue
## 🚀 Próximos pasos
1. **Empieza ya**: copia la estructura mínima y comienza por `AGENTS.md`
2. **Implementación de referencia**: [PrivyDrop GitHub](https://github.com/david-bai00/PrivyDrop)
2. **Implementación de referencia**: [<u>**PrivyDrop GitHub**</u>](https://github.com/david-bai00/PrivyDrop)
3. **Feedback**: abre un issue o comenta si te sirve (o te atoras)
4. **Star**: si te aporta valor, deja una estrella 🌟
@@ -36,10 +36,10 @@ Cet article présente une **méthode dingénierie exécutable** pour transfor
- `docs/ai-playbook/collab-rules.md` : règles de collaboration + template de plan de changement (comment on travaille)
Tous les exemples viennent du repo open source PrivyDrop :
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
OpenAI a aussi publié un retour dexpérience très proche dans lesprit :
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -81,7 +81,7 @@ Le remède est toujours le même : index + code-map + flows, puis un plan approu
- Docs must stay in sync : `AGENTS.en.md:12`
- Verification required : `AGENTS.en.md:13`
Fichier : [AGENTS.en.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
Fichier : [<u>**AGENTS.en.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
```md
# AGENTS — Repo Rules
@@ -99,25 +99,25 @@ First Principles
## Step 2 : `docs/ai-playbook/index.md` (entrée hautesignal)
Référence : [docs/ai-playbook/index.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
Référence : [<u>**docs/ai-playbook/index.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
---
## Step 3 : `code-map.md` (où changer)
Référence : [docs/ai-playbook/code-map.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
Référence : [<u>**docs/ai-playbook/code-map.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
---
## Step 4 : `flows.md` (comment ça tourne)
Référence : [docs/ai-playbook/flows.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
Référence : [<u>**docs/ai-playbook/flows.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
---
## Step 5 : rendre “plan first” obligatoire
Template : [docs/ai-playbook/collab-rules.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
Template : [<u>**docs/ai-playbook/collab-rules.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
---
@@ -141,7 +141,7 @@ Please deeply read relevant docs/code. Think systematically, ask clarifying ques
## Référence OpenAI
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -30,10 +30,10 @@ AI を「速い検索ボックス」として使うなら、これらの問題
- `docs/ai-playbook/collab-rules.md`:協働ルール + 変更計画テンプレ(どう進めるか)
例はすべて OSS の PrivyDrop から。実装と照らし合わせて読めます:
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
さらに、OpenAI の実践記事も考え方が近いです:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -87,7 +87,7 @@ PrivyDrop では、工学的な協働に必要な要点は 5 行に集約でき
- Docs must stay in sync`AGENTS.en.md:12`
- Verification required`AGENTS.en.md:13`
ファイル: [AGENTS.en.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
ファイル: [<u>**AGENTS.en.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
ゼロから最小版を作るなら、例えばこの形(短く・硬く・実行可能に):
@@ -132,7 +132,7 @@ AI が脱線する最大要因のひとつは、**あなたのコードの“入
- 30 秒で読める:プロジェクト概要 + リンク索引だけ
- 1 クリックで飛べる:読者/AI を code-map / flows / collab-rules に誘導する
参考実装: [docs/ai-playbook/index.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
参考実装: [<u>**docs/ai-playbook/index.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
最小テンプレ(そのままコピー可):
@@ -161,7 +161,7 @@ AI が脱線する最大要因のひとつは、**あなたのコードの“入
- 入口ファイルは 1 行で責務を書く
- 依頼が来たら、まず code-map で 3–8 個の候補を当ててから深掘り
参考実装: [docs/ai-playbook/code-map.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
参考実装: [<u>**docs/ai-playbook/code-map.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
オプション:よくある依頼 → 入口の早見表も便利です:
@@ -187,7 +187,7 @@ code-map が「どこを触るか」なら、flows は「どう動くか」で
- 時系列と不変条件が書かれていれば、AI は“雰囲気修正”をしなくなる
- 過去の落とし穴をチェックリストに圧縮して再利用できる
参考実装: [docs/ai-playbook/flows.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
参考実装: [<u>**docs/ai-playbook/flows.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
最低限入れたい 3 つ:
@@ -208,7 +208,7 @@ code-map が「どこを触るか」なら、flows は「どう動くか」で
`collab-rules.md` に計画テンプレを固定し、強制ルールとして運用します。
PrivyDrop テンプレ: [docs/ai-playbook/collab-rules.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
PrivyDrop テンプレ: [<u>**docs/ai-playbook/collab-rules.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
構造はこのまま再利用できます:
@@ -334,7 +334,7 @@ Please deeply read relevant docs/code. Think systematically, ask clarifying ques
## 業界参照:OpenAI は Codex でスプリントをどう回すか
OpenAI の「28 日で Android 版 Sora を作るために Codex をどう使ったか」は、この playbook と驚くほど一致します:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
合わせたいポイント:
@@ -369,7 +369,7 @@ docs/
## 🚀 次にやること
1. **今すぐ始める**:最小構成をあなたのリポジトリにコピーし、まず `AGENTS.md` から
2. **参考実装** [PrivyDrop GitHub](https://github.com/david-bai00/PrivyDrop) で AI Playbook 全体を見る
2. **参考実装** [<u>**PrivyDrop GitHub**</u>](https://github.com/david-bai00/PrivyDrop) で AI Playbook 全体を見る
3. **フィードバック**:役立った/詰まったら issue やコメントで共有
4. **Star**:価値があれば PrivyDrop に star を 🌟
@@ -29,10 +29,10 @@ AI를 “더 빠른 검색창”으로만 쓰면 이런 문제는 드러나지
- `docs/ai-playbook/collab-rules.md`: 협업 규칙 + 변경 계획 템플릿(어떻게 일할지)
모든 예시는 오픈소스 PrivyDrop에서 가져왔습니다:
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
OpenAI의 실전 글도 접근 방식이 매우 비슷합니다:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -74,7 +74,7 @@ OpenAI의 실전 글도 접근 방식이 매우 비슷합니다:
- Docs must stay in sync: `AGENTS.en.md:12`
- Verification required: `AGENTS.en.md:13`
파일: [AGENTS.en.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
파일: [<u>**AGENTS.en.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.en.md)
```md
# AGENTS — Repo Rules
@@ -92,25 +92,25 @@ First Principles
## Step 2: `docs/ai-playbook/index.md` 만들기 (고신호 진입점)
참고 구현: [docs/ai-playbook/index.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
참고 구현: [<u>**docs/ai-playbook/index.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.md)
---
## Step 3: `code-map.md` 만들기 (어디를 고칠지)
참고 구현: [docs/ai-playbook/code-map.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
참고 구현: [<u>**docs/ai-playbook/code-map.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.md)
---
## Step 4: `flows.md` 만들기 (어떻게 동작하는지)
참고 구현: [docs/ai-playbook/flows.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
참고 구현: [<u>**docs/ai-playbook/flows.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.md)
---
## Step 5: “plan first”를 강제하기
템플릿: [docs/ai-playbook/collab-rules.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
템플릿: [<u>**docs/ai-playbook/collab-rules.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.md)
---
@@ -134,7 +134,7 @@ Please deeply read relevant docs/code. Think systematically, ask clarifying ques
## OpenAI 참고
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -29,10 +29,10 @@ status: "published"
- `docs/ai-playbook/collab-rules.md`:协作规则 + 变更计划模板(怎么协作)
本文的所有示例都来自开源仓库 PrivyDrop,你可以直接对照实现:
[https://github.com/david-bai00/PrivyDrop](https://github.com/david-bai00/PrivyDrop)
[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)
另外,最近 OpenAI 的一篇实践文章也有相似的方法论:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
---
@@ -86,7 +86,7 @@ status: "published"
- 文档同步:`AGENTS.zh-CN.md:12`
- 验证要求:`AGENTS.zh-CN.md:13`
对应文件:[AGENTS.zh-CN.md](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.zh-CN.md)
对应文件:[<u>**AGENTS.zh-CN.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/AGENTS.zh-CN.md)
如果你想从零写一个最小版本,可以用下面这个结构(建议保持短、硬、可执行):
@@ -135,7 +135,7 @@ AI 最常见的跑偏原因之一是:**不知道你家代码“入口在哪”
- 30 秒读完:只放"项目快照 + 链接索引"
- 一键跳转:把读者/AI 带到 code-map / flows / collab-rules
参考实现:[docs/ai-playbook/index.zh-CN.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.zh-CN.md)
参考实现:[<u>**docs/ai-playbook/index.zh-CN.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/index.zh-CN.md)
最小模板(可直接复制):
@@ -164,7 +164,7 @@ AI 最常见的跑偏原因之一是:**不知道你家代码“入口在哪”
- 每个入口文件只写一句话职责
- 看到需求时,先在 code-map 里命中 3–8 个候选文件,再深入读
参考实现:[docs/ai-playbook/code-map.zh-CN.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.zh-CN.md)
参考实现:[<u>**docs/ai-playbook/code-map.zh-CN.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/code-map.zh-CN.md)
可选:也可以加一段“常见需求 → 入口文件”的速查表,进一步降低定位成本:
@@ -190,7 +190,7 @@ code-map 怎么生成(以及如何迭代):
- 把时序与不变量写清楚,AI 就不需要"凭感觉改"
- 你可以把"历史上踩过的坑"压缩为调试要点,直接复用
参考实现:[docs/ai-playbook/flows.zh-CN.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.zh-CN.md)(并拆分了深度阅读小节)
参考实现:[<u>**docs/ai-playbook/flows.zh-CN.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/flows.zh-CN.md)(并拆分了深度阅读小节)
建议至少包含三块内容:
@@ -211,7 +211,7 @@ flows 怎么生成(以及如何迭代):
建议在 `collab-rules.md` 里固化计划模板,并把它当成强约束。
PrivyDrop 的模板:[docs/ai-playbook/collab-rules.zh-CN.md](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.zh-CN.md)
PrivyDrop 的模板:[<u>**docs/ai-playbook/collab-rules.zh-CN.md**</u>](https://github.com/david-bai00/PrivyDrop/blob/main/docs/ai-playbook/collab-rules.zh-CN.md)
模板可以直接复用其中的结构(目标/范围/方案/风险/验收/回滚/验证),参考如下:
@@ -337,7 +337,7 @@ Validation
## 业界对照:OpenAI 如何用 Codex 组织冲刺(外部佐证)
OpenAI 在《我们如何使用 Codex 在 28 天内构建 Android 版 Sora》里总结了一套非常相似的工作模型:
[https://openai.com/index/shipping-sora-for-android-with-codex/](https://openai.com/index/shipping-sora-for-android-with-codex/)
[<u>**https://openai.com/index/shipping-sora-for-android-with-codex/**</u>](https://openai.com/index/shipping-sora-for-android-with-codex/)
可以重点对齐这几个点(与本文的方法一一对应):
@@ -376,7 +376,7 @@ docs/
## 🚀 下一步行动
1. **立即开始**:复制最小目录结构到你的项目,从 `AGENTS.md` 开始
2. **参考实现**:访问 [PrivyDrop GitHub](https://github.com/david-bai00/PrivyDrop),查看完整 AI Playbook
2. **参考实现**:访问 [<u>**PrivyDrop GitHub**</u>](https://github.com/david-bai00/PrivyDrop),查看完整 AI Playbook
3. **给我反馈**:如果这套方法对你有帮助(或踩坑了),欢迎在 GitHub 提 issue 或评论区交流
4. **Star 支持**:如果觉得有价值,给 PrivyDrop 一个 star 🌟
@@ -38,8 +38,8 @@ Beim Wechsel zum Empfangen füllen wir die letzte gespeicherte RaumID automat
Der Check läuft beim TabWechsel: Zuerst wird ausgefüllt, dann direkt die Beitrittslogik aufgerufen ein Einfügen/Klick weniger.
- CodeAnker:
- AutoJoin useEffect (Empfänger): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- CacheHelfer (localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
- AutoJoin useEffect (Empfänger): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- CacheHelfer (localStorage): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
Wann greift es nicht?
@@ -64,8 +64,8 @@ Implementierungsnotizen:
- IDs mit weniger als 8 Zeichen werden nicht gespeichert Schutz vor versehentlichen KurzIDs.
- CodeAnker:
- Einfach/Doppelklick inkl. TimerCleanup: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Sofortiger Beitritt bei „Gecachte ID verwenden“ (Sender): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
- Einfach/Doppelklick inkl. TimerCleanup: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- Sofortiger Beitritt bei „Gecachte ID verwenden“ (Sender): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ Wir beobachten drei Einstiegspunkte und stoßen die Wiederverbindung an:
- Proaktiver `socketId`Check: Bei SocketRecovery erneut validieren.
- CodeAnker:
- AutoBeitritt nach SocketConnect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Vereinheitlichter attemptReconnectionEinstieg: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- `lastJoinedSocketId` verfolgen und bei Bedarf `initiator-online`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- Sender verarbeitet `recipient-ready` und startet Neuverhandlung: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- Empfänger antwortet auf `initiator-online` mit `recipient-ready`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- AutoBeitritt nach SocketConnect: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- Vereinheitlichter attemptReconnectionEinstieg: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- `lastJoinedSocketId` verfolgen und bei Bedarf `initiator-online`: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- Sender verarbeitet `recipient-ready` und startet Neuverhandlung: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- Empfänger antwortet auf `initiator-online` mit `recipient-ready`: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- BackendRelais:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
- ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### Sequenz (Mermaid)
@@ -112,15 +112,15 @@ sequenceDiagram
### Zuverlässigkeitsdetails
- ICEKandidatenQueue: Ist die RemoteDescription nicht bereit oder die Verbindung im Schließen, werden Kandidaten gepuffert und später geflusht; siehe https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- DataChannelBackpressure & Chunking: SenderSchwelle `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); Netzsteuerung `maxBuffer≈3MB / lowThreshold≈512KB / 64KBChunks` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- ICEKandidatenQueue: Ist die RemoteDescription nicht bereit oder die Verbindung im Schließen, werden Kandidaten gepuffert und später geflusht; siehe [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.)
- DataChannelBackpressure & Chunking: SenderSchwelle `bufferedAmountLowThreshold=256KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82)); Netzsteuerung `maxBuffer≈3MB / lowThreshold≈512KB / 64KBChunks` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,) [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)).
- Mobile Wake Lock: Beim Verbinden anfordern, bei Trennung/Fehler freigeben reduziert Unterbrechungen im Hintergrund.
- Fehlerkapselung & Retries: seltene `sendData failed` werden gekapselt, angezeigt und erneut versucht (siehe `sendWithBackpressure`).
### Kurze vs. lange IDs: Wiederverwendungsstrategie
- Kurze IDs (4stellig) erhalten nach „leerem Raum + Trennung“ eine GnadenTTL von 15Min. (900s) schnelle Wiederverbindung im Fenster; siehe https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- StandardAblaufzeit für Räume: 24h; nur bei leerem Raum nach Trennung wird temporär auf 15Min. umgestellt; siehe https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- Kurze IDs (4stellig) erhalten nach „leerem Raum + Trennung“ eine GnadenTTL von 15Min. (900s) schnelle Wiederverbindung im Fenster; siehe [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.)
- StandardAblaufzeit für Räume: 24h; nur bei leerem Raum nach Trennung wird temporär auf 15Min. umgestellt; siehe [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.)
- Lange IDs (UUIDartig) eignen sich für Wiederverwendung über Sitzungen/Geräte hinweg am besten mit dem CacheButton kombinieren.
---
@@ -145,15 +145,15 @@ Mobil/Problemnetze:
Je geschmeidiger die Verbindung, desto größer der P2PWert. CachedIDAutoJoin und robuste Wiederverbindung machen PrivyDrop im echten Netz noch verlässlicher.
Wenn Ihnen das gefällt, freuen wir uns über einen Stern auf GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>). Das hilft, entdeckt zu werden und treibt uns an, weiter zu feilen.
Wenn Ihnen das gefällt, freuen wir uns über einen Stern auf GitHub ([<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)). Das hilft, entdeckt zu werden und treibt uns an, weiter zu feilen.
Jetzt online testen: <u>https://www.privydrop.app</u>. Feedback und Verbesserungsvorschläge gern als Issue helfen Sie uns, das „glatte Gefühl“ weiter auszubauen.
Jetzt online testen: [<u>**https://www.privydrop.app**</u>](https://www.privydrop.app). Feedback und Verbesserungsvorschläge gern als Issue helfen Sie uns, das „glatte Gefühl“ weiter auszubauen.
Zusätzlich sorgt Cloudflare CDN für Beschleunigung über Regionen hinweg schnellere, stabilere Zugriffe, weniger Ruckler.
Weiterführende Lektüre:
- [Warum ich PrivyDrop Open Source gestellt habe](/blog/privydrop-open-source)
- [Wie WebRTC BrowserDirekttransfer ermöglicht](/blog/webRTC-file-transfer)
- [Resumable Transfers: Schluss mit der GroßdateiAnxiety](/blog/resumable-transfers)
- [<u>**Warum ich PrivyDrop Open Source gestellt habe**</u>](/blog/privydrop-open-source)
- [<u>**Wie WebRTC BrowserDirekttransfer ermöglicht**</u>](/blog/webRTC-file-transfer)
- [<u>**Resumable Transfers: Schluss mit der GroßdateiAnxiety**</u>](/blog/resumable-transfers)
@@ -38,8 +38,8 @@ When you switch to the Receiver tab, if the following conditions are met, the la
This logic triggers on tab switch. If matched, we first fill the input, then immediately call the join routine—one less paste/click.
- Code anchors:
- Receiverside autojoin useEffect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- Cache helper (localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
- Receiverside autojoin useEffect: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- Cache helper (localStorage): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
When will it not trigger?
@@ -64,8 +64,8 @@ Implementation notes:
- We dont allow saving IDs shorter than 8 chars to avoid accidental short saves.
- Code anchors:
- Single/doubletap with timer cleanup: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Autojoin immediately on “Use Cached ID” (Sender): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
- Single/doubletap with timer cleanup: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- Autojoin immediately on “Use Cached ID” (Sender): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ We watch for disconnects from three entry points and trigger reconnection:
- Proactive `socketId` change check: on socket recovery, we validate once more.
- Code anchors:
- Auto rejoin after socket connects: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Unified attemptReconnection entry: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- Track `lastJoinedSocketId` and trigger `initiator-online` when needed: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- Sender handles `recipient-ready` and restarts negotiation: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- Receiver responds to `initiator-online` with `recipient-ready`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Auto rejoin after socket connects: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- Unified attemptReconnection entry: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- Track `lastJoinedSocketId` and trigger `initiator-online` when needed: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- Sender handles `recipient-ready` and restarts negotiation: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- Receiver responds to `initiator-online` with `recipient-ready`: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- Backend signaling relay:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
- ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### Sequence (Mermaid)
@@ -112,15 +112,15 @@ sequenceDiagram
### Reliability Details
- ICE candidate queue: if the remote description isnt ready or the connection is closing/closed, candidates are queued and flushed later; see https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- DataChannel backpressure & chunking: Sender threshold `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); network control `maxBuffer≈3MB / lowThreshold≈512KB / 64KB chunks` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- ICE candidate queue: if the remote description isnt ready or the connection is closing/closed, candidates are queued and flushed later; see [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.)
- DataChannel backpressure & chunking: Sender threshold `bufferedAmountLowThreshold=256KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82)); network control `maxBuffer≈3MB / lowThreshold≈512KB / 64KB chunks` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,) [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)).
- Mobile wake lock: request Wake Lock when connected; release on disconnect/failure to reduce background interruptions.
- Error wrapping & retries: rare `sendData failed` paths are wrapped, surfaced, and retried (see `sendWithBackpressure`).
### Short vs Long IDs: Reuse Strategy
- Short IDs (4digit) get a 15minute (900s) grace TTL when a room becomes empty after a disconnect—allowing quick reconnection within the window; see https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- Default room expiry is 24 hours; only emptyroom disconnects switch to the temporary 15minute keepalive; see https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- Short IDs (4digit) get a 15minute (900s) grace TTL when a room becomes empty after a disconnect—allowing quick reconnection within the window; see [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.)
- Default room expiry is 24 hours; only emptyroom disconnects switch to the temporary 15minute keepalive; see [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.)
- Long IDs (UUIDlike) are better for crosssession/crossdevice reuse; pair them with the cachedID button for best ergonomics.
---
@@ -145,15 +145,15 @@ Mobile/poor network scenarios:
Smoother connections amplify the value of P2P. CachedID autojoin on the receiver and resilient reconnect across the stack make PrivyDrop sturdier and more dependable in the real world.
If you find this useful, please star us on GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>) so more people can discover it. Your star directly affects search and recommendation signals—and fuels our motivation to keep polishing.
If you find this useful, please star us on GitHub ([<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)) so more people can discover it. Your star directly affects search and recommendation signals—and fuels our motivation to keep polishing.
Try it online: <u>https://www.privydrop.app</u>. We also welcome issues with your feedback and suggestions—help us make the “smooth experience” even smoother.
Try it online: [<u>**https://www.privydrop.app**</u>](https://www.privydrop.app). We also welcome issues with your feedback and suggestions—help us make the “smooth experience” even smoother.
Additionally, our domain is accelerated via Cloudflare CDN (saintly cyber help), significantly improving crossregion speed and stability so more users can open the site without hiccups.
Further Reading:
- [Why I OpenSourced PrivyDrop](/blog/privydrop-open-source)
- [How WebRTC Enables BrowserDirect Transfer](/blog/webRTC-file-transfer)
- [Resumable Transfers: Say Goodbye to BigFile Anxiety](/blog/resumable-transfers)
- [<u>**Why I OpenSourced PrivyDrop**</u>](/blog/privydrop-open-source)
- [<u>**How WebRTC Enables BrowserDirect Transfer**</u>](/blog/webRTC-file-transfer)
- [<u>**Resumable Transfers: Say Goodbye to BigFile Anxiety**</u>](/blog/resumable-transfers)
@@ -38,8 +38,8 @@ Al cambiar a la pestaña de Receptor, si se cumplen estas condiciones, rellenamo
La lógica se dispara al cambiar de pestaña: primero rellenamos, luego llamamos directamente a unirse—un pegado/clic menos.
- Anclas de código:
- useEffect de autoentrada en el receptor: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- Utilidad de caché (localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
- useEffect de autoentrada en el receptor: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- Utilidad de caché (localStorage): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
¿Cuándo no se activa?
@@ -64,8 +64,8 @@ Notas de implementación:
- No permitimos guardar IDs de menos de 8 caracteres para evitar guardados accidentales.
- Anclas de código:
- Simple/doble toque y limpieza del temporizador: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Unión inmediata al “Usar ID en caché” (emisor): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
- Simple/doble toque y limpieza del temporizador: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- Unión inmediata al “Usar ID en caché” (emisor): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ Observamos tres puntos para detectar cortes y disparar la reconexión:
- Comprobación proactiva de cambio de `socketId`: al recuperar el socket, validamos de nuevo.
- Anclas de código:
- Reentrada automática tras reconectar el socket: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Punto unificado de attemptReconnection: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- Registro de `lastJoinedSocketId` y envío de `initiator-online` si procede: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- El emisor recibe `recipient-ready` y reinicia la negociación: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- El receptor responde a `initiator-online` con `recipient-ready`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Reentrada automática tras reconectar el socket: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- Punto unificado de attemptReconnection: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- Registro de `lastJoinedSocketId` y envío de `initiator-online` si procede: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- El emisor recibe `recipient-ready` y reinicia la negociación: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- El receptor responde a `initiator-online` con `recipient-ready`: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- Relé de señalización en backend:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
- ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### Secuencia (Mermaid)
@@ -112,15 +112,15 @@ sequenceDiagram
### Detalles de fiabilidad
- Cola de candidatos ICE: si la descripción remota no está lista o la conexión se cierra, los candidatos se encolan y se envían después; ver https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- Backpressure y troceado del DataChannel: umbral del emisor `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); control de red `maxBuffer≈3MB / lowThreshold≈512KB / trozos de 64KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- Cola de candidatos ICE: si la descripción remota no está lista o la conexión se cierra, los candidatos se encolan y se envían después; ver [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.)
- Backpressure y troceado del DataChannel: umbral del emisor `bufferedAmountLowThreshold=256KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82)); control de red `maxBuffer≈3MB / lowThreshold≈512KB / trozos de 64KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,) [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)).
- Wake Lock móvil: se solicita al conectar y se libera al desconectar/fallar, para reducir interrupciones al pasar a segundo plano.
- Envoltorio de errores y reintentos: los raros `sendData failed` se capturan, se muestran y se reintentan (ver `sendWithBackpressure`).
### Estrategia de reutilización: IDs cortos vs largos
- IDs cortos (4 dígitos) reciben un TTL de 15 minutos (900s) cuando la sala queda vacía tras la desconexión; permite reconectar fácilmente en esa ventana; ver https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- La expiración por defecto de la sala es 24 horas; solo en “sala vacía + desconexión” pasamos a la retención temporal de 15 minutos; ver https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- IDs cortos (4 dígitos) reciben un TTL de 15 minutos (900s) cuando la sala queda vacía tras la desconexión; permite reconectar fácilmente en esa ventana; ver [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.)
- La expiración por defecto de la sala es 24 horas; solo en “sala vacía + desconexión” pasamos a la retención temporal de 15 minutos; ver [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.)
- IDs largos (tipo UUID) son mejores para reutilización entre sesiones/dispositivos; combínalos con el botón de caché para la mejor ergonomía.
---
@@ -145,15 +145,15 @@ Móvil/redes pobres:
Cuanto más suave es la conexión, más crece el valor del P2P. El autojoin por ID en caché y la reconexión resiliente hacen que PrivyDrop sea más robusto y confiable en redes reales.
Si te resulta útil, déjanos una estrella en GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>) para que más personas nos encuentren. Tu estrella impacta en búsqueda y recomendaciones—y alimenta nuestras ganas de seguir puliendo.
Si te resulta útil, déjanos una estrella en GitHub ([<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)) para que más personas nos encuentren. Tu estrella impacta en búsqueda y recomendaciones—y alimenta nuestras ganas de seguir puliendo.
Pruébalo online: <u>https://www.privydrop.app</u>. También te invitamos a abrir issues con comentarios y sugerencias para seguir afinando esa “experiencia sin fricción”.
Pruébalo online: [<u>**https://www.privydrop.app**</u>](https://www.privydrop.app). También te invitamos a abrir issues con comentarios y sugerencias para seguir afinando esa “experiencia sin fricción”.
Además, el dominio está acelerado con Cloudflare CDN, mejorando notablemente velocidad y estabilidad entre regiones para una apertura sin tirones.
Lecturas recomendadas:
- [Por qué hice PrivyDrop de código abierto](/blog/privydrop-open-source)
- [Cómo WebRTC permite la transferencia directa entre navegadores](/blog/webRTC-file-transfer)
- [Transferencias reanudables: adiós a la ansiedad por los archivos grandes](/blog/resumable-transfers)
- [<u>**Por qué hice PrivyDrop de código abierto**</u>](/blog/privydrop-open-source)
- [<u>**Cómo WebRTC permite la transferencia directa entre navegadores**</u>](/blog/webRTC-file-transfer)
- [<u>**Transferencias reanudables: adiós a la ansiedad por los archivos grandes**</u>](/blog/resumable-transfers)
@@ -38,8 +38,8 @@ Lorsque vous passez à longlet Récepteur, si les conditions suivantes sont r
La logique se déclenche au changement donglet. Si cest bon, on remplit dabord, puis on appelle aussitôt la routine dentrée — un collage/clic de moins.
- Repères de code :
- useEffect dautoentrée côté récepteur : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- Utilitaire de cache (localStorage) : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
- useEffect dautoentrée côté récepteur : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- Utilitaire de cache (localStorage) : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
Quand cela ne sappliquetil pas ?
@@ -64,8 +64,8 @@ Notes dimplémentation :
- Pas denregistrement dID de moins de 8 caractères pour éviter les « courts » accidentels.
- Repères de code :
- Simple/doubleclic et nettoyage du timer : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Rejoindre immédiatement après « Utiliser lID en cache » (émetteur) : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
- Simple/doubleclic et nettoyage du timer : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- Rejoindre immédiatement après « Utiliser lID en cache » (émetteur) : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ Nous surveillons trois points dentrée et déclenchons la reconnexion :
- Vérification proactive de changement de `socketId` : à la reprise du socket, on revalide.
- Repères de code :
- Ré‑entrée auto après connexion du socket : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Point dentrée unifié attemptReconnection : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- Suivi de `lastJoinedSocketId` et émission de `initiator-online` si nécessaire : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- Côté émetteur, réception de `recipient-ready` et reprise de la négociation : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- Côté récepteur, réponse `recipient-ready` à `initiator-online` : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Ré‑entrée auto après connexion du socket : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- Point dentrée unifié attemptReconnection : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- Suivi de `lastJoinedSocketId` et émission de `initiator-online` si nécessaire : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- Côté émetteur, réception de `recipient-ready` et reprise de la négociation : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- Côté récepteur, réponse `recipient-ready` à `initiator-online` : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- Relais côté backend :
- ready : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
- ready : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected : [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### Séquence (Mermaid)
@@ -112,15 +112,15 @@ sequenceDiagram
### Détails de fiabilité
- File dattente des candidats ICE : si la description distante nest pas prête ou que la connexion se ferme, on met en file et on rejoue plus tard ; voir https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- Rétropression et découpage DataChannel : seuil émetteur `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82) ; contrôle réseau `maxBuffer≈3MB / lowThreshold≈512KB / chunks de 64KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- File dattente des candidats ICE : si la description distante nest pas prête ou que la connexion se ferme, on met en file et on rejoue plus tard ; voir [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.)
- Rétropression et découpage DataChannel : seuil émetteur `bufferedAmountLowThreshold=256KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82)) ; contrôle réseau `maxBuffer≈3MB / lowThreshold≈512KB / chunks de 64KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,) [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)).
- Wake Lock mobile : demande à l’établissement de la connexion, libération à la déconnexion/échec — pour réduire les interruptions en arrièreplan.
- Encapsulation derreurs et retries : les rares `sendData failed` sont capturés, surfacés et réessayés (voir `sendWithBackpressure`).
### Stratégie de réutilisation : IDs courts vs longs
- IDs courts (4 chiffres) : en cas de « salle vide + déconnexion », TTL de grâce de 15 minutes (900s) — reconnexion rapide dans la fenêtre ; voir https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- Expiration par défaut : 24 h ; seul le cas « salle vide + déconnexion » passe en conservation temporaire de 15 min ; voir https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- IDs courts (4 chiffres) : en cas de « salle vide + déconnexion », TTL de grâce de 15 minutes (900s) — reconnexion rapide dans la fenêtre ; voir [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.)
- Expiration par défaut : 24 h ; seul le cas « salle vide + déconnexion » passe en conservation temporaire de 15 min ; voir [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.)
- IDs longs (type UUID) : mieux pour la réutilisation intersessions/appareils ; les combiner avec le bouton dID en cache offre la meilleure ergonomie.
---
@@ -145,14 +145,14 @@ Mobile / réseaux difficiles :
Plus la connexion est fluide, plus la valeur du P2P grandit. Lautojoin via ID en cache et la reconnexion résiliente renforcent la robustesse de PrivyDrop dans les réseaux réels.
Si vous aimez, metteznous une étoile sur GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>) — cela accroît la visibilité et nourrit notre envie de peaufiner.
Si vous aimez, metteznous une étoile sur GitHub ([<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)) — cela accroît la visibilité et nourrit notre envie de peaufiner.
Essai en ligne : <u>https://www.privydrop.app</u>. Vos retours et idées sont bienvenus via les issues : continuons ensemble à polir « lexpérience soyeuse ».
Essai en ligne : [<u>**https://www.privydrop.app**</u>](https://www.privydrop.app). Vos retours et idées sont bienvenus via les issues : continuons ensemble à polir « lexpérience soyeuse ».
Par ailleurs, notre domaine bénéficie de laccélération Cloudflare CDN, améliorant nettement vitesse et stabilité interrégions.
Pour aller plus loin :
- [Pourquoi jai opensourcé PrivyDrop](/blog/privydrop-open-source)
- [Comment WebRTC permet le transfert direct entre navigateurs](/blog/webRTC-file-transfer)
- [Transferts reprenables : adieu à lanxiété des gros fichiers](/blog/resumable-transfers)
- [<u>**Pourquoi jai opensourcé PrivyDrop**</u>](/blog/privydrop-open-source)
- [<u>**Comment WebRTC permet le transfert direct entre navigateurs**</u>](/blog/webRTC-file-transfer)
- [<u>**Transferts reprenables : adieu à lanxiété des gros fichiers**</u>](/blog/resumable-transfers)
@@ -38,8 +38,8 @@ PrivyDrop を初めて使うと、よくある小さな引っかかりが二つ
この判定はタブ切り替え時に走ります。条件一致なら、入力欄を埋めてからそのまま入室ロジックを呼び出し、貼り付け/クリックを 1 回減らします。
- コード参照:
- 受信側の自動入室 useEffect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- キャッシュユーティリティ(localStorage: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
- 受信側の自動入室 useEffect: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- キャッシュユーティリティ(localStorage: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
発動しないとき:
@@ -64,8 +64,8 @@ PrivyDrop を初めて使うと、よくある小さな引っかかりが二つ
- 8 文字未満は保存不可にして、短い ID の誤保存を防止。
- コード参照:
- シングル/ダブルタップとタイマーのクリーンアップ: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- 「キャッシュ ID を使用」で即入室(送信側): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
- シングル/ダブルタップとタイマーのクリーンアップ: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- 「キャッシュ ID を使用」で即入室(送信側): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ PrivyDrop を初めて使うと、よくある小さな引っかかりが二つ
- `socketId` の変化を能動チェック:Socket 復旧時に再確認。
- コード参照:
- Socket 接続後の自動再入室: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- 再接続の統一エントリ: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- `lastJoinedSocketId` の記録と必要時の `initiator-online` 送出: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- 送信側の `recipient-ready` 受信と再ネゴシエーション開始: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- 受信側の `initiator-online` 受信と `recipient-ready` 応答: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Socket 接続後の自動再入室: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- 再接続の統一エントリ: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- `lastJoinedSocketId` の記録と必要時の `initiator-online` 送出: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- 送信側の `recipient-ready` 受信と再ネゴシエーション開始: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- 受信側の `initiator-online` 受信と `recipient-ready` 応答: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- バックエンドの信令リレー:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
- ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### シーケンス(Mermaid
@@ -112,15 +112,15 @@ sequenceDiagram
### 信頼性ディテール
- ICE 候補キュー:リモート記述が未確立、または接続がクローズ系なら候補をキューイングし、後でまとめて反映;https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256。
- DataChannel の背圧と分割送信:送信側しきい値 `bufferedAmountLowThreshold=256KB`https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82);ネットワーク制御は `maxBuffer≈3MB / lowThreshold≈512KB / 64KB チャンク`https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)。
- ICE 候補キュー:リモート記述が未確立、または接続がクローズ系なら候補をキューイングし、後でまとめて反映;[<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256。**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256。)
- DataChannel の背圧と分割送信:送信側しきい値 `bufferedAmountLowThreshold=256KB`[<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82);ネットワーク制御は**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82);ネットワーク制御は) `maxBuffer≈3MB / lowThreshold≈512KB / 64KB チャンク`[<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,) [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)。**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)。)
- モバイルの Wake Lock:接続時に取得、切断/失敗で解放。バックグラウンド遷移による中断を低減。
- エラー包みとリトライ:まれな `sendData failed` を捕捉し、表面化&再試行(`sendWithBackpressure` を参照)。
### 短い ID と長い ID の使い分け
- 短い ID(4 桁)は「空室で切断」時、バックエンドが 15 分(900s)の TTL に更新。猶予内は再接続が容易;https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125。
- 既定の部屋期限は 24 時間。空室切断のときのみ 15 分の一時保持に切替;https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6。
- 短い ID(4 桁)は「空室で切断」時、バックエンドが 15 分(900s)の TTL に更新。猶予内は再接続が容易;[<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125。**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125。)
- 既定の部屋期限は 24 時間。空室切断のときのみ 15 分の一時保持に切替;[<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6。**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6。)
- 長い ID(UUID 相当)はセッション横断・デバイス横断の再利用に向く。キャッシュ ID ボタンと組み合わせると最良。
---
@@ -145,15 +145,15 @@ sequenceDiagram
“するり”とつながるほど、P2P の価値は増幅します。受信側のキャッシュ ID 自動入室と、スタック全体の再接続により、PrivyDrop は現実のネット環境でいっそう頑丈で頼れる存在になりました。
もし気に入っていただけたら、ぜひ GitHub で Star をお願いします(<u>https://github.com/david-bai00/PrivyDrop</u>)。見つけてもらいやすくなるだけでなく、私たちの磨き込みの原動力にもなります。
もし気に入っていただけたら、ぜひ GitHub で Star をお願いします([<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop))。見つけてもらいやすくなるだけでなく、私たちの磨き込みの原動力にもなります。
オンライン体験:<u>https://www.privydrop.app</u>。Issue から体験フィードバックや改善提案も歓迎します。“なめらかな体験”を、さらに厚くしていきましょう。
オンライン体験:[<u>**https://www.privydrop.app**</u>](https://www.privydrop.app)。Issue から体験フィードバックや改善提案も歓迎します。“なめらかな体験”を、さらに厚くしていきましょう。
なお、ドメインは Cloudflare CDN による加速を有効化。地域間の速度と安定性が向上し、より多くのユーザーがストレスなくアクセスできます。
関連記事:
- [なぜ PrivyDrop をオープンソース化したのか](/blog/privydrop-open-source)
- [WebRTC はどうやってブラウザ直送を実現するのか](/blog/webRTC-file-transfer)
- [レジューム転送:大容量でも焦らない](/blog/resumable-transfers)
- [<u>**なぜ PrivyDrop をオープンソース化したのか**</u>](/blog/privydrop-open-source)
- [<u>**WebRTC はどうやってブラウザ直送を実現するのか**</u>](/blog/webRTC-file-transfer)
- [<u>**レジューム転送:大容量でも焦らない**</u>](/blog/resumable-transfers)
@@ -38,8 +38,8 @@ PrivyDrop을 처음 쓰면 자주 마주치는 두 가지 작은 마찰이 있
이 로직은 탭 전환 때 트리거됩니다. 조건이 맞으면 입력 칸을 채운 뒤 바로 입장 로직을 호출하여, 붙여넣기/클릭을 한 번 줄입니다.
- 코드 앵커:
- 수신 측 자동 입장 useEffect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- 캐시 유틸(localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
- 수신 측 자동 입장 useEffect: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- 캐시 유틸(localStorage): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
다음 상황에서는 동작하지 않습니다.
@@ -64,8 +64,8 @@ PrivyDrop을 처음 쓰면 자주 마주치는 두 가지 작은 마찰이 있
- 8자 미만은 저장 불가로 하여, 짧은 ID 오저장을 방지
- 코드 앵커:
- 단/복 탭과 타이머 정리: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- “캐시 ID 사용” 시 즉시 입장(발신 측): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
- 단/복 탭과 타이머 정리: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- “캐시 ID 사용” 시 즉시 입장(발신 측): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ PrivyDrop을 처음 쓰면 자주 마주치는 두 가지 작은 마찰이 있
- `socketId` 변경의 능동 확인: 소켓 복구 시 한 번 더 검증
- 코드 앵커:
- 소켓 연결 후 자동 재입장: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- attemptReconnection 통합 진입점: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- `lastJoinedSocketId` 기록 및 필요 시 `initiator-online` 트리거: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- 발신 측의 `recipient-ready` 처리 및 재협상 시작: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- 수신 측의 `initiator-online` 응답(`recipient-ready` 전송): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- 소켓 연결 후 자동 재입장: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- attemptReconnection 통합 진입점: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- `lastJoinedSocketId` 기록 및 필요 시 `initiator-online` 트리거: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- 발신 측의 `recipient-ready` 처리 및 재협상 시작: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- 수신 측의 `initiator-online` 응답(`recipient-ready` 전송): [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- 백엔드 신호 릴레이:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
- ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected: [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### 시퀀스(Mermaid)
@@ -112,15 +112,15 @@ sequenceDiagram
### 신뢰성 디테일
- ICE 후보 큐: 원격 설명이 준비되지 않았거나 연결이 종료 단계면 후보를 큐에 담아 두었다가 나중에 한 번에 반영; https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- DataChannel 배압과 청킹: 발신 측 임계치 `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); 네트워크 제어 `maxBuffer≈3MB / lowThreshold≈512KB / 64KB 청크` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- ICE 후보 큐: 원격 설명이 준비되지 않았거나 연결이 종료 단계면 후보를 큐에 담아 두었다가 나중에 한 번에 반영; [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.)
- DataChannel 배압과 청킹: 발신 측 임계치 `bufferedAmountLowThreshold=256KB` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82)); 네트워크 제어 `maxBuffer≈3MB / lowThreshold≈512KB / 64KB 청크` ([<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111,) [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)).
- 모바일 Wake Lock: 연결 시 획득, 끊김/실패 시 해제 — 백그라운드 전환으로 인한 중단을 줄임.
- 에러 래핑과 재시도: 드물게 발생하는 `sendData failed` 경로를 포착/표면화/재시도(`sendWithBackpressure` 참고).
### 짧은 ID와 긴 ID 재사용 전략
- 짧은 ID(4자리)는 “빈 방 + 끊김” 시 백엔드가 TTL을 15분(900s)으로 갱신 — 그 창에서 빠르게 재연결 가능; https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- 기본 방 만료는 24시간; “빈 방 + 끊김”에 한해 일시적으로 15분 보존으로 전환; https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- 짧은 ID(4자리)는 “빈 방 + 끊김” 시 백엔드가 TTL을 15분(900s)으로 갱신 — 그 창에서 빠르게 재연결 가능; [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.)
- 기본 방 만료는 24시간; “빈 방 + 끊김”에 한해 일시적으로 15분 보존으로 전환; [<u>**https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.)
- 긴 ID(UUID 유사)는 세션/디바이스를 넘어 재사용에 유리 — 캐시 ID 버튼과 함께 쓰면 가장 편함.
---
@@ -145,15 +145,15 @@ sequenceDiagram
연결이 매끄러울수록 P2P의 가치는 커집니다. 캐시 ID 자동 입장과 전 구간 재연결로, PrivyDrop은 현실 네트워크에서 더 튼튼하고 믿을 만해졌습니다.
유용했다면 GitHub 별을 부탁드립니다(<u>https://github.com/david-bai00/PrivyDrop</u>). 더 많은 사람이 발견할 수 있고, 저희가 계속 다듬어 가는 동력이 됩니다.
유용했다면 GitHub 별을 부탁드립니다([<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)). 더 많은 사람이 발견할 수 있고, 저희가 계속 다듬어 가는 동력이 됩니다.
온라인 체험: <u>https://www.privydrop.app</u>. Issue로 사용 소감과 제안을 남겨 주세요. “부드러운 경험”을 더 두텁게 만들어가겠습니다.
온라인 체험: [<u>**https://www.privydrop.app**</u>](https://www.privydrop.app). Issue로 사용 소감과 제안을 남겨 주세요. “부드러운 경험”을 더 두텁게 만들어가겠습니다.
덧붙여, 도메인은 Cloudflare CDN 가속을 사용합니다. 지역 간 속도와 안정성이 크게 향상되어, 더 많은 지역에서 끊김 없이 접속할 수 있습니다.
더 읽기:
- [내가 PrivyDrop을 오픈 소스로 공개한 이유](/blog/privydrop-open-source)
- [WebRTC가 브라우저 직결 전송을 구현하는 방법](/blog/webRTC-file-transfer)
- [중단 후 재개 전송: 대용량 전송의 불안을 넘어](/blog/resumable-transfers)
- [<u>**내가 PrivyDrop을 오픈 소스로 공개한 이유**</u>](/blog/privydrop-open-source)
- [<u>**WebRTC가 브라우저 직결 전송을 구현하는 방법**</u>](/blog/webRTC-file-transfer)
- [<u>**중단 후 재개 전송: 대용량 전송의 불안을 넘어**</u>](/blog/resumable-transfers)
@@ -38,8 +38,8 @@ status: "published"
上述逻辑在切换面板时触发,一旦命中,会先填充输入框,再立即调用加入逻辑,减少一次粘贴/点击。
- 代码锚点:
- 前端自动入房 useEffect(接收端):[frontend/components/ClipboardApp.tsx#L151](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- 缓存工具(localStorage):[frontend/lib/roomIdCache.ts#L1](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
- 前端自动入房 useEffect(接收端):[<u>**frontend/components/ClipboardApp.tsx#L151**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- 缓存工具(localStorage):[<u>**frontend/lib/roomIdCache.ts#L1**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
何时不会触发?
@@ -64,8 +64,8 @@ status: "published"
- 输入长度不足 8 位时不会允许保存,避免误存短 ID。
- 代码锚点:
- 单/双击与计时器清理:[frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- 使用缓存 ID 后立刻直连(发送端):[frontend/components/ClipboardApp/SendTabPanel.tsx#L193](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
- 单/双击与计时器清理:[<u>**frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- 使用缓存 ID 后立刻直连(发送端):[<u>**frontend/components/ClipboardApp/SendTabPanel.tsx#L193**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
@@ -78,16 +78,16 @@ status: "published"
- 主动判断 `socketId` 变化:在 socket 连接恢复时复核一次。
- 代码锚点:
- Socket 连接后自动重入房:[frontend/lib/webrtc_base.ts#L121](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- 尝试重连的统一入口:[frontend/lib/webrtc_base.ts#L185](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- 记录 `lastJoinedSocketId` 并在需要时触发 `initiator-online`[frontend/lib/webrtc_base.ts#L460](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- 发送端接收 `recipient-ready` 并重启协商:[frontend/lib/webrtc_Initiator.ts#L12](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- 接收端响应 `initiator-online` 并发送 `recipient-ready`[frontend/lib/webrtc_Recipient.ts#L14](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- Socket 连接后自动重入房:[<u>**frontend/lib/webrtc_base.ts#L121**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- 尝试重连的统一入口:[<u>**frontend/lib/webrtc_base.ts#L185**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- 记录 `lastJoinedSocketId` 并在需要时触发 `initiator-online`[<u>**frontend/lib/webrtc_base.ts#L460**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- 发送端接收 `recipient-ready` 并重启协商:[<u>**frontend/lib/webrtc_Initiator.ts#L12**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- 接收端响应 `initiator-online` 并发送 `recipient-ready`[<u>**frontend/lib/webrtc_Recipient.ts#L14**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- 后端信令转发:
- ready[backend/src/socket/handlers.ts#L63](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online[backend/src/socket/handlers.ts#L102](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready[backend/src/socket/handlers.ts#L108](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected[backend/src/socket/handlers.ts#L119](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
- ready[<u>**backend/src/socket/handlers.ts#L63**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online[<u>**backend/src/socket/handlers.ts#L102**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready[<u>**backend/src/socket/handlers.ts#L108**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected[<u>**backend/src/socket/handlers.ts#L119**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### 时序(Mermaid
@@ -112,15 +112,15 @@ sequenceDiagram
### 可靠性细节
- ICE 候选队列:若远端描述尚未建立或连接处于关闭态,候选会入队,待可用时批量补交;见 [frontend/lib/webrtc_base.ts#L219-L256](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256)。
- DataChannel 背压与分片:发送端阈值 `bufferedAmountLowThreshold=256KB`[frontend/lib/webrtc_Initiator.ts#L82](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82));网络发送控制 `maxBuffer≈3MB / lowThreshold≈512KB / 64KB 分片`[frontend/lib/transfer/NetworkTransmitter.ts#L66-L111](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111)、[frontend/lib/transfer/NetworkTransmitter.ts#L160-L210](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210))。
- ICE 候选队列:若远端描述尚未建立或连接处于关闭态,候选会入队,待可用时批量补交;见 [<u>**frontend/lib/webrtc_base.ts#L219-L256**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256)。
- DataChannel 背压与分片:发送端阈值 `bufferedAmountLowThreshold=256KB`[<u>**frontend/lib/webrtc_Initiator.ts#L82**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82));网络发送控制 `maxBuffer≈3MB / lowThreshold≈512KB / 64KB 分片`[<u>**frontend/lib/transfer/NetworkTransmitter.ts#L66-L111**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111)、[<u>**frontend/lib/transfer/NetworkTransmitter.ts#L160-L210**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210))。
- 移动端唤醒锁:连接建立时申请 Wake Lock,断开/失败时释放,降低切后台导致的意外中断;
- 错误兜底与重试:小概率 `sendData failed` 会被包装、上报与重试(详见 `sendWithBackpressure` 相关逻辑)。
### 短 ID 与长 ID 的复用策略
- 短 ID(4 位)在“空房断开”后,会由后端将房间 TTL 刷新为 15 分钟(900s),窗口期内可直接重连,超时回收;见 [backend/src/socket/handlers.ts#L119-L125](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125)。
- 默认房间过期时间为 24 小时,仅在空房断开发生临时 15 分钟保留;见 [backend/src/services/redis.ts#L6](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6)。
- 短 ID(4 位)在“空房断开”后,会由后端将房间 TTL 刷新为 15 分钟(900s),窗口期内可直接重连,超时回收;见 [<u>**backend/src/socket/handlers.ts#L119-L125**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125)。
- 默认房间过期时间为 24 小时,仅在空房断开发生临时 15 分钟保留;见 [<u>**backend/src/services/redis.ts#L6**</u>](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6)。
- 长 ID(如 UUID 级别长度)更适合跨会话、跨设备的持续复用;与缓存 ID 按钮配合使用体验最佳。
---
@@ -145,14 +145,14 @@ sequenceDiagram
我们相信,越“顺手”的连接,越能放大 P2P 的价值。接收端缓存 ID 自动连接与断线重连,让 PrivyDrop 在真实网络环境下更加稳健、可依赖。
如果觉得好用,请到 GitHub 给我们一个 Star<u>https://github.com/david-bai00/PrivyDrop</u>),便于更多人发现与受益;你的 Star 也会直接影响搜索与推荐权重,是我们持续打磨产品的动力。
如果觉得好用,请到 GitHub 给我们一个 Star[<u>**https://github.com/david-bai00/PrivyDrop**</u>](https://github.com/david-bai00/PrivyDrop)),便于更多人发现与受益;你的 Star 也会直接影响搜索与推荐权重,是我们持续打磨产品的动力。
在线体验:<u>https://www.privydrop.app</u>。也欢迎在 Issue 中反馈你的使用体验与改进建议,让我们把“顺滑体验”继续做厚。
在线体验:[<u>**https://www.privydrop.app**</u>](https://www.privydrop.app)。也欢迎在 Issue 中反馈你的使用体验与改进建议,让我们把“顺滑体验”继续做厚。
另外,域名已启用 Cloudflare CDN 加速(赛博菩萨),显著提升跨区域的访问速度与稳定性,让更多地区用户打开网站不再卡顿,整体体验更流畅。
延伸阅读:
- [我为什么开源了 PrivyDrop](/blog/privydrop-open-source)
- [WebRTC 如何实现浏览器直传](/blog/webRTC-file-transfer)
- [断点续传:让大文件传输告别焦虑](/blog/resumable-transfers)
- [<u>**我为什么开源了 PrivyDrop**</u>](/blog/privydrop-open-source)
- [<u>**WebRTC 如何实现浏览器直传**</u>](/blog/webRTC-file-transfer)
- [<u>**断点续传:让大文件传输告别焦虑**</u>](/blog/resumable-transfers)