Preview Vault stores only encrypted content. The server never sees plaintext.
Data layout in MinIO/S3
projects/
<projectId>/
project.json # Project metadata + PBKDF2 salt
manifest.enc # Encrypted manifest wrapper (iv + ciphertext)
files/
<fileId> # Encrypted file bytesProject metadata (project.json)
Unencrypted fields used for bootstrapping decryption.
projectId: Unique project ID.projectName: Optional label for the UI.salt: Base64 PBKDF2 salt to derive the AES-GCM key.createdAt: ISO timestamp.
Manifest (manifest.enc)
JSON wrapper with two fields:
iv: Base64 AES-GCM IV for the manifest payload.ciphertext: Base64 encrypted manifest payload.
The decrypted manifest contains:
version: Schema version.projectId,projectName,createdAt.files: Array of files with name, type, size, and per-file IV.
Crypto choices
- Key derivation: PBKDF2 (SHA-256, 250k iterations).
- Encryption: AES-GCM (256-bit) with random 12-byte IVs.
- Where encryption happens: In the browser/CLI before upload.
API responsibilities
- Create project metadata.
- Issue presigned upload URLs.
- Store encrypted manifest.
- Serve encrypted blobs back to the viewer.
No plaintext is handled by the server.
GitHub sync (automation)
The GitHub Action downloads preview-sync.js from /api/preview-sync on every push to a selected folder. It encrypts files in the runner and posts ciphertext + manifest to /api/sync. The Preview Vault server stores the encrypted blobs in MinIO and serves them back to viewers.
Sync requests authenticate with a per-project sync token stored (hashed) in Postgres. Only ciphertext is transmitted.
Auth + database
NextAuth with GitHub OAuth is used for authentication. Project metadata, collaborators, and sync logs are stored in Postgres via Prisma.
Security levels
- ZERO_TRUST: passphrase never stored.
- LOCAL_DEVICE: passphrase stored in the browser only.
- TEAM_SHARED: per-user encrypted project keys stored in Postgres.
- SERVER_MANAGED: passphrase encrypted with
PROJECT_KEY_SECRET. - PUBLIC_LINK: server-managed passphrase available via a public endpoint.