Skip to content

Document Management

SCOPE_ITEM: Secure document sharing between company and client, with versioning, access control, optional e-signatures, and retention policies. Replaces email attachments, WeTransfer, and shared drives.

Decision Tree

IF: Documents are primarily one-way (company shares with client). THEN: Simple document library with upload + download.

IF: Documents require client feedback or approval. THEN: Include document status workflow (shared, reviewed, approved).

IF: Documents need legally binding signatures (contracts, agreements). THEN: Include e-signature module (ZealID, Signicat, or Scrive preferred — EU-based. DocuSign or Dropbox Sign secondary if client explicitly requires. NOTE: DocuSign/Dropbox Sign are US-based — EU data sovereignty risk).

IF: Documents contain sensitive/regulated data. THEN: Include enhanced access control + audit logging + retention.

IF: Large files are common (>100 MB, design files, video). THEN: Include chunked upload and resumable transfers.


Document Upload

Company Upload (Primary)

SCOPE_ITEM: Company staff uploads documents for clients.

INCLUDES: - Drag-and-drop upload zone. - Presigned URL upload directly to S3 (no server relay for large files). - File type validation (configurable whitelist per portal). Default: PDF, DOCX, XLSX, PPTX, PNG, JPG, SVG, ZIP. - Maximum file size: 100 MB (configurable). - Virus scanning on upload completion (ClamAV sidecar or API service). File quarantined until scan passes. - Upload progress indicator. - Metadata on upload: title, description, category, project assignment. - Notification to client on document share.

Client Upload

OPTIONAL: SCOPE_ITEM: Client uploads documents to share with company.

INCLUDES: - Upload zone in client portal (same technical flow). - File type and size validation (same rules). - Virus scanning (same flow). - Notification to company team on client upload. - Upload tied to project or conversation.

OPTIONAL: - Upload request: company sends request to client for specific document (e.g., "Please upload your signed contract"). Request includes: description, deadline, category. Client sees request in portal with upload action. Reminder email if deadline approaching.

Upload Implementation

Client browser
  └── Request presigned URL from API
        └── API generates S3 presigned PUT URL (15-min expiry)
  └── Upload file directly to S3 via presigned URL
  └── Notify API of upload completion
        └── API triggers virus scan (BullMQ job)
        └── Scan passes → set document status to "available"
        └── Scan fails → quarantine, notify admin
        └── Create activity event
        └── Send notification to recipients

CHECK: Presigned URLs must include Content-Type restriction. CHECK: S3 bucket must have server-side encryption enabled (AES-256). CHECK: S3 bucket must be in EU region (GDPR Article 44). CHECK: CORS on S3 bucket must only allow portal domain.


Document Versioning

SCOPE_ITEM: Track document revisions over time.

Version Management

INCLUDES: - Automatic version increment on re-upload to same document slot. - Version history list (v1, v2, v3... with date, uploader, note). - Download any version. - Current version clearly indicated. - Version note field (what changed — optional but encouraged). - Previous versions remain accessible (not overwritten in S3).

Implementation

CREATE TABLE documents (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  client_org_id UUID REFERENCES client_organisations(id),
  project_id UUID REFERENCES projects(id),
  title TEXT NOT NULL,
  description TEXT,
  category TEXT NOT NULL,          -- contract, deliverable, invoice, etc.
  current_version_id UUID,
  created_by UUID REFERENCES users(id),
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE document_versions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  document_id UUID REFERENCES documents(id),
  version_number INTEGER NOT NULL,
  file_name TEXT NOT NULL,
  file_size_bytes BIGINT NOT NULL,
  mime_type TEXT NOT NULL,
  s3_key TEXT NOT NULL,            -- storage path in S3
  scan_status TEXT DEFAULT 'pending',  -- pending, clean, infected
  version_note TEXT,
  uploaded_by UUID REFERENCES users(id),
  created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE document_access_log (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  document_id UUID REFERENCES documents(id),
  version_id UUID REFERENCES document_versions(id),
  user_id UUID REFERENCES users(id),
  action TEXT NOT NULL,            -- view, download, upload, delete
  ip_address INET,
  created_at TIMESTAMPTZ DEFAULT now()
);

OPTIONAL: - Visual diff for text-based documents (extract text, show changes). - Side-by-side version comparison. - Restore previous version (creates new version from old content). - Version locking (prevent edits while under review).


E-Signatures

OPTIONAL: SCOPE_ITEM: Request legally binding electronic signatures on documents.

Provider Decision

IF: Client needs eIDAS-compliant qualified electronic signatures (QES). THEN: Use ZealID (SE) or Signicat (NO) — EU-based QTSPs on EU Trusted List.

IF: Client needs standard advanced electronic signatures (AES), EU-first. THEN: Use Scrive (SE) — EU-based, strong API, eIDAS-compliant.

IF: Client prefers open-source / self-hosted. THEN: Evaluate DocuSeal (open-source, self-hosted e-signature).

IF: Client already uses DocuSign and explicitly requires it. THEN: Integrate with DocuSign eSignature API. NOTE: US-based service — EU data sovereignty risk.

IF: Cost is a primary concern (lower volume) and client accepts US provider. THEN: Integrate with Dropbox Sign (HelloSign). NOTE: US-based service — EU data sovereignty risk.

Criteria ZealID (SE) Signicat (NO) Scrive (SE) DocuSeal DocuSign (US) Dropbox Sign (US)
HQ Sweden (EU) Norway (EEA) Sweden (EU) Self-hosted USA USA
Pricing Per-signature Per-transaction From EUR 20/mo Free (self-hosted) From EUR 600/yr From EUR 15/mo
EU data residency Yes (native) Yes (native) Yes (native) Yes (self-hosted) Yes (EU option) Partial
eIDAS QES Yes (QTSP) Yes (QTSP) Advanced Depends on setup Advanced Standard
API quality Good (REST) Excellent Good (REST) Good (REST) Excellent (complex) Good (simple)
Embedded signing Yes Yes Yes Yes Yes Yes
eID integration DigiD, BankID DigiD, BankID, 20+ BankID No No No

E-Signature Flow

1. Company staff selects document in portal
   └── "Request signature" action

2. Configure signature request
   ├── Signers (name, email — can be client users or external)
   ├── Signing order (sequential or parallel)
   ├── Signature field placement (drag on document preview)
   └── Optional: due date, custom message

3. API call to e-sign provider
   ├── Upload document
   ├── Define signers and field positions
   └── Send signature request

4. Signers receive email with signing link
   ├── Embedded signing (opens in portal iframe/modal), OR
   └── Provider-hosted signing page (redirect)

5. Signer completes signature
   └── Provider webhook: signature completed

6. All signatures collected
   └── Provider webhook: envelope/request completed
   └── Download signed document (with audit trail)
   └── Store signed version in portal (new document version)
   └── Notify company staff of completion
   └── Activity event logged

CHECK: E-signature provider must support EU data processing (GDPR). CHECK: Signed documents must be stored as a new version in the portal (not only at the e-sign provider). CHECK: Audit trail from provider must be stored alongside signed document. CHECK: For eIDAS Advanced Electronic Signature compliance, verify provider capabilities match client's legal requirements.


Access Control

Document-Level Access

SCOPE_ITEM: Control who can access documents.

INCLUDES: - Default: all documents scoped to client organisation (automatic). - All users in client org can view documents shared with their org. - Documents tied to projects inherit project access. - Company staff can see all documents across clients (with context switch).

OPTIONAL: - Per-document access restriction (only specific client users). - Document marked as "primary contact only" (sensitive financials). - Access expiry (document accessible until date X, then hidden). - View-only mode (preview in browser, download disabled). - Watermark on view/download (client name + date stamped on PDF).

Download Logging

SCOPE_ITEM: Track document access for audit and compliance.

INCLUDES: - Log entry on every download (user, document, version, timestamp). - Log entry on every view (if inline preview enabled). - Access log visible to company admin. - Export access log (CSV) for compliance audits.

CHECK: Access log is append-only (immutable). CHECK: Access log retention: minimum 7 years for regulated portals.


Retention Policies

SCOPE_ITEM: Automated document lifecycle management.

Configuration

INCLUDES: - Retention period per document category (configurable by admin). Default suggestions: - Contracts: 10 years after expiry. - Deliverables: 5 years after project completion. - Invoices: 7 years (Dutch tax law requirement). - Correspondence: 2 years. - Warning notification to admin before retention expiry (30 days before). - Archived state (hidden from client, visible to admin for review). - Permanent deletion after archive review period (30 days).

OPTIONAL: - Legal hold flag (prevents deletion regardless of retention policy). - Cold storage migration for archived documents (S3 Glacier). - Automated retention report (monthly summary of upcoming expirations).

Implementation

ALTER TABLE documents ADD COLUMN
  retention_until TIMESTAMPTZ,        -- calculated from category policy
  archived_at TIMESTAMPTZ,
  legal_hold BOOLEAN DEFAULT false;

-- BullMQ daily job: check for documents past retention
-- 1. Mark as archived (hide from client)
-- 2. Notify admin for review
-- 3. After review period: delete from S3 + hard delete record

CHECK: Deletion must remove file from S3 AND database record. CHECK: Legal hold overrides retention policy (document cannot be deleted). CHECK: Deletion is irreversible — require admin confirmation.


File Organisation

Category System

INCLUDES: - Predefined categories (configurable per portal): contracts, deliverables, invoices, reports, correspondence, other. - Category assignment required on upload. - Filter by category in document library. - Category-based retention policy inheritance.

OPTIONAL: - Custom categories per client organisation. - Tags (free-form, multiple per document). - Folder structure (hierarchical, per project). - Full-text search in document content (PDF text extraction on upload, indexed in PostgreSQL FTS or Meilisearch).


Scoping Questions

CHECK: Who uploads documents (company only, or client too)? CHECK: Is document versioning required? CHECK: Are e-signatures needed? Which provider preference? CHECK: What document categories/types will be used? CHECK: Are there regulatory retention requirements? CHECK: Is document-level access control needed (beyond per-client)? CHECK: What is the typical document size (affects upload strategy)? CHECK: Is full-text search within document content needed? CHECK: Is watermarking or view-only mode needed? CHECK: How many documents per client (expected volume)?