paperclip/packages/db/src
Devin Foley 23a1b025c2
feat(server): chunked resumable company import transfers (#11223)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Company import moves large packages into an instance, and since the
upload cap rose to 1 GB, the transport is the weak point: one HTTP
request, buffered fully in memory, with no resume
> - A dropped connection at 90% of an 800 MB upload starts the whole
transfer over, and a server restart loses all progress
> - This pull request adds the server side of chunked resumable import
transfers: a durable run ledger and routes that accept the same import
zip as verified ~32 MB parts spooled to disk
> - An interrupted transfer resumes from the parts already uploaded —
across dropped connections, page refreshes, and server restarts — and
peak upload memory drops from the whole package to one part
> - The benefit is that large imports become reliable on real-world
connections instead of all-or-nothing

## Linked Issues or Issue Description

**What happened?**

Large company imports travel as a single HTTP upload. On a slow or flaky
connection, any interruption discards all progress and the upload
restarts from zero. The server buffers the entire compressed package in
memory during upload. A server restart mid-upload loses the transfer
entirely. With the upload cap now at 1 GB, these failure modes govern
exactly the imports the cap was raised for.

**Expected behavior**

A large import upload survives interruptions: already-transferred data
is kept and verified, only the missing remainder is re-sent, and the
server's memory use during upload is bounded by a part, not the package.

**Steps to reproduce**

1. Import a multi-hundred-MB company package over a connection that
drops mid-upload.
2. The upload fails; retrying starts from byte zero.
3. Repeat on an unstable connection and the import may never complete.

## What Changed

- New `company_transfer_runs` table (drizzle schema + migration) and
`companyTransferRunService`: one row per transfer with a content-derived
idempotency key, per-part completion recorded atomically and
idempotently, resume scoped to actor and direction, completed runs
short-circuiting retries of identical content.
- New transfer routes beside the existing import routes, same
authorization: declare a sliced zip (`POST /import/transfers` —
validates cap, 64 MB part ceiling, contiguity, size sums, sha256
format), upload parts (`PUT .../parts/:n` — raw body, hash-and-size
verified before an atomic write to a disk spool under the instance root;
re-uploads are no-op successes), poll resume state (`GET .../:id` —
missing parts recomputed from disk), and apply (`POST .../:id/apply` —
requires all parts, re-verifies the assembled zip against the whole-file
hash fail-closed, then feeds the existing import pipeline through
factored helpers rather than duplicated logic).
- Hourly sweep fails and cleans spools idle for 24 h; a swept transfer
honestly reports all parts missing on resume.
- Strict UUID gating on run ids before any filesystem path construction.
- The existing single-shot upload path is untouched; clients arrive in
the follow-up PR.

## Verification

- Transfer route suite (embedded Postgres): create/upload/status/apply
round-trip with a real imported company, out-of-order parts, wrong-hash
part rejected and unrecorded, re-upload no-op, apply-with-missing-parts
rejection, resume after failure with prior progress intact,
assembled-hash mismatch failing closed with spool deletion, actor
scoping 404s, async-job apply, sweep followed by honest resume.
- Ledger suite (embedded Postgres): part idempotency, actor/direction
scoping, completed-run short-circuit, cancelled runs staying cancelled.
- Existing portability route suite unchanged and green; server + db
typechecks clean. Exact counts in the PR checks.

## Risks

- New routes are additive; the existing import path is untouched. The
transfer routes carry the same board authorization as the import routes
they sit beside.
- Disk spool: bounded by the existing upload cap per transfer, cleaned
on success, failure, hash mismatch, and by the 24 h sweep. Spool paths
are strict-UUID-gated.
- The apply step still materializes the assembled zip in memory once
(same profile as today's single-shot import at apply time); upload-time
memory drops to one part.
- Known limitation, deliberate: transfers are keyed on content alone, so
identical package content cannot be imported twice without re-exporting
(surfaced explicitly to the caller). Acceptable for v1; noted for
review.

## Model Used

- Claude Fable 5 (`claude-fable-5`) via Claude Code CLI, with extended
thinking and tool use (multi-agent implementation with independent
verification).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-11 15:25:07 -07:00
..
migrations feat(server): chunked resumable company import transfers (#11223) 2026-08-11 15:25:07 -07:00
schema feat(server): chunked resumable company import transfers (#11223) 2026-08-11 15:25:07 -07:00
agent-wakeup-requests-schema.test.ts feat: maintained in_review review-path contract + stalled-review actions (#10675) 2026-08-04 13:54:40 -05:00
backup-lib.test.ts fix(db): use calendar month retention for backups (#3718) 2026-07-24 13:12:43 -05:00
backup-lib.ts fix(db): use calendar month retention for backups (#3718) 2026-07-24 13:12:43 -05:00
backup.ts [codex] Add LLM Wiki plugin host support (#5597) 2026-05-10 07:34:12 -05:00
built-in-agent-unique-marker-migration.test.ts fix: prevent duplicate built-in agents and self-heal reconciliation (#10223) 2026-07-28 11:12:58 -07:00
check-migration-numbering.ts feat(routines): add workspace-aware routine runs 2026-04-02 11:38:57 -05:00
check-migration-safety.test.ts feat(db): add migration safety lint 2026-07-07 01:43:12 +00:00
check-migration-safety.ts feat(db): add migration safety lint 2026-07-07 01:43:12 +00:00
client-options.test.ts db: env-configurable client options; parallelize attention feed queries (#10795) 2026-08-04 06:30:36 -07:00
client.test.ts feat(skills): import skills from projects (#9620) 2026-07-15 18:01:44 -05:00
client.ts db: env-configurable client options; parallelize attention feed queries (#10795) 2026-08-04 06:30:36 -07:00
company-secret-proposals-migration.test.ts feat(secrets): add human-approved secret proposals (#9934) 2026-08-05 21:49:40 -05:00
connections-v3-schema-core-migration.test.ts feat(connections): add v3 schema core (#9958) 2026-07-21 15:16:26 -05:00
decision-queue-migrations.test.ts feat(decisions): add desk workflow and retention (#10672) 2026-08-02 10:47:03 -05:00
embedded-postgres-error.test.ts Improve embedded Postgres bootstrap errors 2026-03-26 12:35:19 -05:00
embedded-postgres-error.ts Improve embedded Postgres bootstrap errors 2026-03-26 12:35:19 -05:00
embedded-postgres-native.test.ts feat(cli): add managed install, update, and service lifecycle (#10045) 2026-07-31 18:52:23 -07:00
embedded-postgres-native.ts [codex] Improve runtime and import reliability (#6549) 2026-05-22 09:57:22 -05:00
environment-custom-images-schema.test.ts Scope environment custom images to instance environments (#8850) 2026-07-01 23:57:31 -07:00
external-objects-schema.test.ts External object references across issue surfaces (#8512) 2026-06-23 08:27:19 -05:00
heartbeat-context-snapshot-index-migration.test.ts perf(server): cut steady-state DB hot paths in dashboard, attention, and productivity sweeps (#10992) 2026-08-06 11:56:40 -05:00
inbox-archive-agent-policies-migration.test.ts feat(authz): govern agent inbox archive access (#9658) 2026-07-16 09:51:48 -05:00
index.ts feat(mcp) [split 2/8]: add governed access contracts (#9557) 2026-07-14 12:57:20 -05:00
issue-comment-derived-attribution-migration.test.ts fix(db): relocate slow 0126 issue-comment attribution backfill to fast idempotent 0132 (#9108) 2026-07-06 11:41:24 -07:00
issue-comment-on-behalf-migration.test.ts feat(issues): contain cross-issue agent side effects (#10837) 2026-08-04 13:17:49 -05:00
migrate.ts Fix dev migration prompt and embedded db:migrate 2026-03-10 15:31:05 -05:00
migration-runtime.ts [codex] Improve runtime and import reliability (#6549) 2026-05-22 09:57:22 -05:00
migration-safety-baseline.ts feat(db): add migration safety lint 2026-07-07 01:43:12 +00:00
migration-status.ts feat(costs): add billing, quota, and budget control plane 2026-03-16 15:11:01 -05:00
nested-skill-folders-migration.test.ts feat: organize skills with nested folders and My Skills (#9633) 2026-07-16 15:50:45 -05:00
pipelines-schema.test.ts Add pipeline workflow primitives and operator UI (#7903) 2026-06-26 12:02:44 -05:00
runtime-config.test.ts [codex] Add LLM Wiki plugin host support (#5597) 2026-05-10 07:34:12 -05:00
runtime-config.ts [codex] Add LLM Wiki plugin host support (#5597) 2026-05-10 07:34:12 -05:00
seed.ts Expand data model with companies, approvals, costs, and heartbeats 2026-02-17 09:07:22 -06:00
status-card-migrations.test.ts feat(status-cards): add experimental status card update view (#10101) 2026-07-24 12:26:43 -05:00
summary-slots-schema.test.ts feat: add built-in summarizer and summary slots (#9713) 2026-07-17 11:03:07 -05:00
table-size-estimates.ts Replace host-to-host Cloud Sync with full-fidelity company Import/Export (#10507) 2026-07-30 11:37:00 -07:00
test-embedded-postgres.test.ts fix(db): harden embedded Postgres test start with bounded retry (#10540) 2026-07-30 22:22:31 -07:00
test-embedded-postgres.ts fix(db): harden embedded Postgres test start with bounded retry (#10540) 2026-07-30 22:22:31 -07:00