doc/plans/2026-02-20-storage-system-implementation.md
Status: Draft
Owner: Backend + UI
Date: 2026-02-20
Add a single storage subsystem for Paperclip that supports:
local_disk and s3.~/.paperclip/instances/<instanceId>/data/storage.assets is generic metadata table; issue_attachments links assets to issues/comments.packages/shared/src/constants.ts: add STORAGE_PROVIDERS and StorageProvider type.packages/shared/src/config-schema.ts: add storageConfigSchema with:
local_disk | s3packages/shared/src/index.ts: export new storage config/types.cli/src/config/schema.ts: ensure re-export includes new storage schema/types.cli/src/commands/configure.ts: add storage section support.cli/src/commands/onboard.ts: initialize default storage config.cli/src/prompts/storage.ts: new prompt flow for local disk vs s3 settings.cli/src/prompts/index (if present) or direct imports: wire new storage prompt.server/src/config.ts: load storage config and resolve home-aware local path.server/src/home-paths.ts: add resolveDefaultStorageDir().doc/CLI.md: document configure --section storage.doc/DEVELOPING.md: document default local storage path and overrides.paperclipai onboard writes a valid storage config block by default.paperclipai configure --section storage can switch between local and s3 modes.server/src/storage/types.ts: define provider + service interfaces.server/src/storage/service.ts: provider-agnostic service (key generation, validation, stream APIs).server/src/storage/local-disk-provider.ts: implement local disk provider with safe path resolution.server/src/storage/s3-provider.ts: implement S3-compatible provider (@aws-sdk/client-s3).server/src/storage/provider-registry.ts: provider lookup by configured id.server/src/storage/index.ts: export storage factory helpers.server/src/services/index.ts: export storageService factory.server/src/app.ts or route wiring point: inject/use storage service where needed.server/package.json: add AWS SDK dependency if not present.local_disk mode, uploading + reading a file round-trips bytes on disk.s3 mode, service can put/get/delete against S3-compatible endpoint.packages/db/src/schema/assets.ts: new generic asset metadata table.packages/db/src/schema/issue_attachments.ts: issue-to-asset linking table.packages/db/src/schema/index.ts: export new tables.packages/db/src/migrations/*: generate migration for both tables and indexes.packages/shared/src/types/issue.ts (or new asset types file): add IssueAttachment type.packages/shared/src/index.ts: export new types.assets:
id, company_id, provider, object_keycontent_type, byte_size, sha256, original_filenamecreated_by_agent_id, created_by_user_id, timestampsissue_attachments:
id, company_id, issue_id, asset_id, issue_comment_id (nullable), timestampspackages/shared/src/validators/issue.ts: add schemas for upload/list/delete attachment operations.server/src/services/issues.ts: add attachment CRUD helpers with company checks.server/src/routes/issues.ts: add endpoints:
POST /companies/:companyId/issues/:issueId/attachments (multipart)GET /issues/:issueId/attachmentsGET /attachments/:attachmentId/contentDELETE /attachments/:attachmentIdserver/src/routes/authz.ts: reuse/enforce company access for attachment endpoints.server/src/services/activity-log.ts usage callsites: log attachment add/remove mutations.server/src/app.ts: ensure multipart parsing middleware is in place for upload route.400/401/403/404/409/422/500.ui/src/api/issues.ts: add attachment API client methods.ui/src/api/client.ts: support multipart upload helper (no JSON Content-Type for FormData).ui/src/lib/queryKeys.ts: add issue attachment query keys.ui/src/pages/IssueDetail.tsx: add upload UI + attachment list/query invalidation.ui/src/components/CommentThread.tsx: optional comment image attach or display linked images.packages/shared/src/types/index.ts: ensure attachment types are consumed cleanly in UI.cli/src/checks/storage-check.ts: add storage check (local writable dir, optional S3 reachability check).cli/src/checks/index.ts: export new storage check.cli/src/commands/doctor.ts: include storage check in doctor sequence.doc/DATABASE.md or doc/DEVELOPING.md: mention storage backend behavior by deployment mode.doc/SPEC-implementation.md: add storage subsystem and issue-attachment endpoint contract.paperclipai doctor reports actionable storage status.server/src/__tests__/issue-attachments.auth.test.ts: company boundary and permission tests.server/src/__tests__/issue-attachments.lifecycle.test.ts: upload/list/read/delete flow.server/src/__tests__/storage-local-provider.test.ts: local provider path safety and round-trip.server/src/__tests__/storage-s3-provider.test.ts: s3 provider contract (mocked client).server/src/__tests__/activity-log.attachments.test.ts: mutation logging assertions.cli/src/__tests__/configure-storage.test.ts: configure section writes valid config.cli/src/__tests__/doctor-storage-check.test.ts: storage health output and repair behavior.ui/src/...: issue detail upload and error handling tests.Run:
pnpm -r typecheck
pnpm test:run
pnpm build
If any command is skipped, document exactly what was skipped and why.