Privacy & data
Bounded history, real erasure
Section titled “Bounded history, real erasure”A value deleted or overwritten at time T is gone from every copy TapeDB keeps by T + retention: the local log, R2 log segments and older snapshots. That holds in a quiet workspace too. You are the controller of the data; TapeDB runs in your Cloudflare account and Cloudflare is your processor.
defineTapeDB({ schema, migrations, retention: { days: 30 } }); // default 30, at least 2What is stored
Section titled “What is stored”| Where | What | How long |
|---|---|---|
| Durable Object SQLite, one per workspace | Your models’ rows | Until deleted |
| Each write’s operations and time. Who made a row write is not recorded | Half the retention (15 days by default) | |
| Retry receipts: random client transaction id, sequence, time, and an operation hash while recent | Id, sequence and time for the workspace lifetime; hash removed after half the retention. Superseded R2 copies leave within the full retention | |
| The file index: path, size, content type and uploader | Until the file is deleted | |
R2 DATA bucket |
Log segments, snapshots, a manifest | Superseded copies leave within the retention |
R2 FILES bucket |
Uploaded bytes | Deleted with the file, at once |
| Socket state | A connected client’s subject, role, subscriptions, presence and topics, in memory and, past 12 KiB, in the Durable Object | While the socket is open |
| Claim limiter | A token count per HMAC of a caller’s IP or subject, never the values | Until the bucket refills, a minute by default |
| Broadcast | Messages | Not stored |
Receipts contain no row values or writer identity. Storage grows by one small receipt per transaction with a client id. Use random transaction ids, not user ids. Workspace erasure removes the receipts too.
Claim tokens never appear in a URL: HTTP requests carry them in Authorization, WebSocket upgrades in Sec-WebSocket-Protocol. If you log request headers in Cloudflare, exclude those two. Use an opaque user id as the claim’s sub, not an email address.
Outside TapeDB’s control
Section titled “Outside TapeDB’s control”- Durable Object point-in-time recovery. Cloudflare keeps 30 days of restorable history for every SQLite-backed Durable Object. TapeDB never restores from it, but the effective bound is the greater of the retention and 30 days. That is why the default retention is 30 days.
- R2 bucket locks. A lock rule on the
DATAorFILESbucket stops TapeDB from deleting what it covers. Don’t add one to TapeDB’s buckets.
Answering requests
Section titled “Answering requests”| Request | How |
|---|---|
| Access and portability | db.$export() or tapedb export --workspace <id> streams every row and file entry the claim may read, through the read rules. See Export. |
| Rectification | Update the rows. Old values leave the history within the retention. |
| Erasure of a person | Delete or overwrite their rows and delete their files with db.$files.delete(path), which removes the bytes at once. The old values leave the history within the retention, and Cloudflare’s recovery within 30 days. |
| Erasure of a workspace | tapedb erase --workspace <id> --confirm <id>, or DELETE /engine/workspaces/:id with an owner claim, deletes the R2 history, the files and the Durable Object storage. The workspace answers 410 afterwards. |
Where the data lives
Section titled “Where the data lives”By default Cloudflare places each workspace’s Durable Object near its first request, and R2 buckets wherever they were created. tapedb init --jurisdiction eu keeps the Durable Objects and both buckets in Cloudflare’s EU jurisdiction, and tapedb deploy refuses a config where the two disagree. Choose it before the first deploy: changing it later addresses new, empty workspaces. Cloudflare remains the processor, so your transfer assessment and Cloudflare’s data processing addendum still apply.