HomeProjectsWorkflowRepositoryAccountingStorageDocs

Notifications

Unread messages

No notifications.

Show all

Documentation

Index
Loading documentation...

🏛️ Repository Vault Feature Design

Status: Active (Beta build, sharing/expiry backlog)
Target Branch: repository
Owner: Platform
Last Updated: 2025-10-02

📚 Table of Contents

  • 1. Problem / Motivation
  • 2. Goals / Non-Goals
  • 3. User Stories (MVP)
  • 4. Data Model (Initial)
  • 5. Storage & Encryption Strategy
  • 6. API Endpoints (MVP)
  • 7. Expiration & Notification Logic
  • 8. Versioning Semantics
  • 9. UI Plan
  • 10. Security Considerations
  • 11. Migration Plan
  • 12. Risks / Mitigations
  • 13. Open Questions
  • 14. Minimal Initial Migration (Sketch)
  • 15. Success Criteria (MVP)

1. Problem / Motivation

A secure, centralized place to store and manage critical personal or project-related documents (licenses, certificates, warranties, IDs). Today, documents may be attached to workflows, but there is no canonical, user-centric repository with:

  • Private-by-default visibility
  • Version history (retain superseded copies)
  • Expiration tracking / renewal reminders
  • Archival vs destruction lifecycle
  • Controlled sharing (user-specific or token-based temporary access)

2. Goals / Non-Goals

Goals:

  • Fast MVP: upload, list, view metadata, download latest version
  • Private by default; explicit sharing only
  • Track expiry + notify upcoming (e.g., 30/7/1 days)
  • Immutable versions (append-only) with file hash
  • Soft archive & soft delete initial (hard delete admin script)
  • Minimal ergonomic UI (table/grid + detail pane)

Deferred / Non-Goals (Phase 2+):

  • Full-text OCR search
  • External storage backends abstraction (start with same storage/S3-like)
  • Complex tagging taxonomy (start with free-form tag array)
  • End-to-end encryption in browser (consider later)

3. User Stories (MVP)

  1. Upload a document (PDF/JPG/PNG) and set name + category + optional expiry date.
  2. See a list of my documents sorted by updated date with filters (expired, expiring soon, archived).
  3. Receive a notification before a document expires.
  4. Upload a new version while retaining older versions for audit.
  5. Archive a document to hide it from active lists.
  6. Permanently destroy (soft delete first) an archived document I own.
  7. Share a document with another authenticated user (Phase 1) or generate a revocable token link (Phase 2).

4. Data Model (Initial)

Tables (Drizzle / Postgres):

// RepositoryDocuments
id: uuid (pk)
ownerUserId: varchar(128) not null
name: varchar(160) not null
category: varchar(64) null
tags: text[] default '{}'
status: varchar (enum: 'active' | 'archived' | 'destroyed') default 'active'
visibility: varchar (enum: 'private' | 'shared') default 'private'
latestVersionId: uuid null (FK -> versions.id, maintained by trigger or app logic)
expiresAt: timestamp null
archivedAt: timestamp null
destroyedAt: timestamp null
createdAt: timestamp default now()
updatedAt: timestamp default now()

// RepositoryDocumentVersions
id: uuid pk
documentId: uuid fk -> documents.id on delete cascade
version: int not null (1..n unique per document)
fileName: varchar(255) not null
mimeType: varchar(128) null
size: int null
hashSha256: char(64) not null
storageKey: text not null (path / object key)
createdAt: timestamp default now()
uploadedByUserId: varchar(128) not null
supersedesVersionId: uuid null fk self (optional)

// RepositoryDocumentShares (Phase 1 user-based)
id: uuid pk
documentId: uuid fk -> documents.id
sharedWithUserId: varchar(128) not null
createdByUserId: varchar(128) not null
createdAt: timestamp default now()
revokedAt: timestamp null

// RepositoryDocumentAuditEvents
id uuid pk
documentId uuid fk
versionId uuid null fk
action varchar(64) not null // upload_version, archive, restore, destroy, share, revoke, download
actorUserId varchar(128) not null
meta json null
createdAt timestamp default now()

Indexes:

  • documents(ownerUserId, status)
  • versions(documentId, version desc)
  • shares(documentId, sharedWithUserId unique active)
  • audit(documentId, createdAt desc)
  • expiry partial index where expiresAt is not null and status='active'

5. Storage & Encryption Strategy

Hybrid approach:

  1. Per-version envelope encryption (AES-256-GCM) with random DEK.
  2. DEK wrapped by master key / KMS (placeholder local master key for MVP) stored as encryptedDEK.
  3. Small ciphertext (<= INLINE_FILE_MAX_BYTES) stored inline (bytea). Larger stored via object storage using abstraction.
  4. lib/storage/repository.ts abstraction:
  • putObject({ storageKey, stream|buffer, mimeType })
  • getObjectStream(storageKey)
  • deleteObject(storageKey) (GC / hard delete only)

storageKey pattern: repo/<ownerUserId>/<documentId>/<versionNumber>/<sanitizedFileName>

Security additions:

  • Hash (sha256) persisted for integrity
  • authTag + iv stored per version
  • Future: client-side zero-knowledge option (Phase 2)

6. API Endpoints (MVP)

POST   /api/repository/upload           -> create document (if first) + version
GET    /api/repository                  -> list (filters: status, expiringSoon, search=name substring)
GET    /api/repository/:id              -> metadata + latest version pointer
GET    /api/repository/:id/versions     -> list versions
GET    /api/repository/:id/download     -> decrypt & stream latest (signed URL optional if object storage pre-signed)
GET    /api/repository/:id/versions/:v/download -> decrypt & stream specific version
GET    /api/repository/:id/view         -> inline (Content-Disposition inline) for viewer (pdf/image)
PATCH  /api/repository/:id              -> update name/category/tags/expiry
POST   /api/repository/:id/archive      -> archive
POST   /api/repository/:id/restore      -> restore
POST   /api/repository/:id/destroy      -> soft destroy (status=destroyed + destroyedAt)
POST   /api/repository/:id/version      -> add new version
POST   /api/repository/:id/share        -> add share (Phase 1)
POST   /api/repository/:id/unshare      -> revoke user share

Authorization rules enforced server-side per owner or share membership.

7. Expiration & Notification Logic

A scheduled job (future cron or on-demand server action) queries:

SELECT id, ownerUserId, expiresAt
FROM RepositoryDocuments
WHERE status='active'
  AND expiresAt BETWEEN now() AND now() + interval '30 days'

Bucket by days remaining (30/7/1) -> insert Notifications rows with type repo.expiry.upcoming.

8. Versioning Semantics

  • Increment version sequentially (SELECT max(version)+1)
  • Maintain latestVersionId on document (transaction) for quick lookups
  • Allow downloading any historical version
  • Optional: if same hash uploaded consecutively, skip new version (Phase 2 optimization)

9. UI Plan

Route Group: app/(repository) isolates vault layout. Pages:

  • /repository (list): table (Name / Category / Status / Expires / Updated / Actions) with personal/public scopes
  • /repository/new (document-type guided upload with attachment slots)
  • /repository/[documentId] detail: metadata, version list, inline viewer, transcription queue, audit hooks
  • Components:
    • RepositoryUploadForm
    • RepositoryDocumentRow
    • RepositoryDocumentViewer (inline iframe + attachment cards)
    • RepositoryMetadataEditor
    • VersionHistoryTable
    • ExpiryBadge
    • ShareDialog (Phase 1 user search)

Implementation status (Oct 2025):

  • Route group + vault list with scope tabs, search, inline preview launcher
  • Guided upload form with document-type templates (driver's license, warranty, generic)
  • Detail page with inline viewer, metadata editor, transcription queue surfacing
  • Sharing dialog + endpoints
  • Expiry badge automation & notifications wiring

10. Security Considerations

  • All documents private unless shared explicitly
  • No public unauthenticated links in MVP
  • Signed URLs TTL (e.g., 2 minutes)
  • Enforce ownership on mutation
  • Ensure soft-deleted & archived docs excluded appropriately
  • Sanitize filenames (strip path chars, limit length)
  • Hash verification to detect tampering (server recomputes SHA-256 of uploaded buffer/stream)

11. Migration Plan

  1. Create feature branch feat/repository-vault
  2. Add schema + migrations (000X_repository_core.sql)
  3. Implement storage abstraction
  4. Implement API handlers incrementally:
    • upload (create + version)
    • list / get / download
    • version add
    • metadata patch
    • archive / restore / destroy
  5. Add UI route group & list page
  6. Add detail + version history
  7. Add notifications for expiry (stub job / manual script)
  8. Write README updates & usage docs
  9. QA & merge -> main

12. Risks / Mitigations

Risk Mitigation
Large file uploads blocking server Stream to storage provider; enforce size limit (config)
Race on concurrent version uploads DB transaction w/ max(version) FOR UPDATE
Orphaned storage objects on soft delete Keep; periodic GC script for destroyed > retention window
Notification spam De-dup by (doc, dayBucket) key

13. Open Questions

  • Need encryption at rest beyond provider? (Defer)
  • Tag search implementation (GIN on text[] vs JSONB?) – initial simple = text[] + @> / ILIKE name filter.
  • Should shares allow role-based groups later? (Future extension: RepositoryShareGroups)

14. Minimal Initial Migration (Sketch)

CREATE TABLE "RepositoryDocuments" (...);
CREATE INDEX idx_repo_docs_owner ON "RepositoryDocuments" ("ownerUserId", "status");
CREATE TABLE "RepositoryDocumentVersions" (...);
CREATE UNIQUE INDEX uq_repo_version_per_doc ON "RepositoryDocumentVersions" ("documentId", "version");
ALTER TABLE "RepositoryDocuments" ADD CONSTRAINT repo_latest_version_fk
  FOREIGN KEY ("latestVersionId") REFERENCES "RepositoryDocumentVersions"("id") ON DELETE SET NULL;

(See final migration file in branch for exact SQL with constraints & timestamps.)

15. Success Criteria (MVP)

Encryption Specific Success:

  • Version ciphertext stored (no plaintext at rest)
  • Decryption path validated (round trip test)
  • Size limit enforcement per MIME type

End of draft.

Project Roadmap & Progress

For a detailed, actionable project timeline and ongoing development updates, see:

  • Repository Project Roadmap
  • Repository Development Progress Log

These files are updated as the project advances and provide visibility into phases, milestones, and daily progress.