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)?