Designing a Zero-Trust Personal Information Manager with Client-Side Encryption

Published: (December 20, 2025 at 11:25 AM EST)
6 min read
Source: Dev.to

Source: Dev.to

I am a B.Tech Computer Science undergraduate at Amrita Vishwa Vidyapeetham who enjoys building privacy‑focused systems and learning by deploying real software end‑to‑end.

The Motivation

The inception of InfoStuffs was not driven by a desire to build just another productivity application. It started with a very specific user requirement from my sister. She needed a digital space to organize personal documents and sensitive notes but refused to use standard cloud services such as Google Keep or Notion.

Her constraint was simple but technically demanding: she wanted the convenience of the cloud without trusting the cloud provider with her plaintext data.

This challenge became the foundation of InfoStuffs. My goal shifted from building a simple web application to architecting a Zero‑Trust Information Management System that prioritizes privacy by default.

The Problem Statement

Modern productivity tools generally fall into two categories:

CategoryExamplesDrawbacks
Convenient SaaSNotion, Google KeepStore user data in plaintext or use server‑managed keys, leaving data vulnerable to internal leaks or database breaches.
Self‑HostedObsidian, NextcloudOffer strong privacy but are difficult to access and maintain across multiple devices.

InfoStuffs bridges this gap. The system had to be secure enough that a complete server‑side compromise would yield only garbage data, yet accessible via a standard web browser on any device.

High‑Level Architecture

To satisfy these constraints, InfoStuffs uses a decoupled, cloud‑native architecture with clearly separated responsibilities.

System/Infrastructure Architecture

LayerTechnology / Details
FrontendReact (Vite) + Material‑UI. Handles UI rendering and client‑side cryptographic operations (encryption/decryption).
BackendNode.js + Express, following a Hybrid Architecture.
Local DevelopmentFully dockerized monolithic container, ensuring a consistent environment that mirrors production dependencies.
Production DeploymentDeployed to Vercel as stateless Serverless Functions, allowing the API to scale to zero when idle (cost‑efficient) while maintaining a single Express codebase.
DatabaseMongoDB Atlas – stores encrypted metadata and ciphertext.
AuthenticationClerk – delegating identity management reduces the attack surface for auth flows (MFA, session management).
StorageSupabase Storage – used strictly for isolating binary objects (images, PDFs) via signed URLs.

Security by Design: The Zero‑Trust Vault

Security was not an optional feature; it was the primary architectural constraint.

Zero‑Trust Architecture

1. The Problem with Static Keys

In my initial design I used a static encryption key stored in the server’s environment variables (VITE_SECRET_KEY). I quickly realized this was a critical flaw: if an attacker or a compromised hosting environment exposed the environment variables, they could decrypt everyone’s data. The key was visible, violating the core concept of Zero‑Trust.

2. The Solution: User‑Derived Cryptography

To fix this, I removed the static key entirely and implemented PBKDF2 (Password‑Based Key Derivation Function 2) on the client side.

  • When a user logs in, they enter a Vault Password. This password is never transmitted or stored; it exists only transiently in the client’s memory.
  • The browser runs PBKDF2 to derive a temporary 256‑bit AES key in memory.
  • This key encrypts notes, titles, and file paths before any network request is formed.

The server only ever sees (and stores) ciphertext. If the database administrator (me) were to look at the data, I would see nothing but unreadable strings.

The PBKDF2 parameters were chosen to balance resistance to brute‑force attacks with acceptable latency on low‑powered client devices.

3. Ephemeral Access to Media

For file storage I avoided public buckets entirely.

  • Encrypted Paths: The database stores an encrypted string pointing to the file path (e.g., "user/123/image.jpg" is encrypted).
  • On‑Demand Access: When a user unlocks their vault, the client decrypts the path and requests a Signed URL from Supabase.
  • Time‑Limited: The URL is valid for exactly 60 seconds before expiring. This prevents “link‑sharing” leaks and ensures that even if a URL is intercepted, it becomes useless almost immediately.

Infrastructure Evolution: Solving the Cost Problem

One of the most valuable learning experiences came from adapting the infrastructure to real‑world cost constraints.

Phase 1: The “Enterprise” Trap (GCP)

My initial deployment used Google Cloud Platform with Cloud Run and Cloud Build. While this was an industry‑standard “Enterprise” setup, it introduced significant problems for a personal project:

  • High Costs: Paying for load balancers, container‑registry storage, and compute time quickly added up.
  • Complexity: Managing IAM roles and build triggers for a simple app was overkill.

Phase 2: The Hybrid “Serverless Monolith” (Vercel)

Content for Phase 2 continues here – describe how the app was refactored into a single codebase deployed as serverless functions on Vercel, leveraging the cost‑effective scaling model while preserving the same development workflow.

Takeaways

  • Zero‑Trust by Design: Never store or transmit plaintext keys; derive them client‑side and keep them in memory only.
  • Cost‑Effective Architecture: A single Express codebase can serve both local Docker development and Vercel serverless production, dramatically reducing operational overhead.
  • Ephemeral Media Access: Signed URLs with short TTLs protect binary assets without sacrificing usability.

InfoStuffs demonstrates that privacy‑first, cloud‑native applications are feasible even for solo developers and small‑scale projects.

InfoStuffs – Zero‑Cost Serverless Monolith

Overview

To eliminate deployment costs, I re‑architected the stack to run for $0 /month:

EnvironmentApproach
Local Development (Dockerized)A single docker‑compose up spins up Frontend, Backend, and Database services. This keeps the development environment isolated and reproducible on any machine.
Production Deployment (Serverless)Refactored the Express app to run on Vercel Serverless Functions instead of a permanently running container.

Result: A Serverless Monolith – develop like a traditional monolith (easy debugging, Docker‑based local run) and deploy as distributed functions. This gives the best of both worlds: zero infrastructure management and zero cost for personal use.

I deliberately avoided micro‑services because the domain does not yet justify multiple bounded contexts; premature decomposition would add complexity and increase the attack surface without tangible benefits.

Technical Challenges & Solutions

1. Environment Variable Visibility

Relying on .env files for security proved problematic. Migrating to user‑derived keys solved the issue but introduced edge cases such as “Lost Passwords.”
Solution: Implemented a “Nuclear Reset” feature that lets users wipe unrecoverable data and start fresh, prioritising security over data recovery.

2. Monorepo Build Contexts

Vercel initially failed to locate vite.config.js inside the monorepo.
Solution: Explicitly set the Root Directory in Vercel settings and rewrote the build command so dependencies are installed from the correct path.

3. Docker vs. Serverless Routing Mismatch

ProblemDetails
Local DockerExpress handled all routing internally.
VercelTreated the API as static files; requests to sub‑paths (e.g., /api/info/nuke) hit Vercel’s 404 handler before reaching Express, causing the browser to report a CORS error.

Solution: Created a Hybrid Routing Strategy:

  1. Added a Vercel‑compatible entry point (api/info.js).
  2. Configured a vercel.json rewrite rule to pipe all sub‑route traffic directly into the Express instance.

This bridge lets the same code run inside Docker locally and as a Vercel Function in production, fixing CORS issues.

Future Roadmap

  • Redis Caching – Reduce database reads for frequently accessed (encrypted) metadata.
  • React Native Mobile App – Wrap existing logic to enable biometric vault unlocking (Face ID) instead of typing a password.
  • Offline Mode – Leverage PWA capabilities for read‑only access to cached encrypted notes.

Closing Thoughts

InfoStuffs is more than a note‑taking app; it’s a practical exploration of Zero‑Trust Engineering. By tackling real‑world problems of data visibility and cloud costs, I built a system where privacy is enforced by mathematics, not policy. It satisfies a genuine user need while serving as a valuable learning experience in full‑stack security and DevOps.

  • Repository:
  • Live Deployment:

Note: The live deployment requires authentication and a vault password. Core security properties are enforced client‑side and are best understood via the architecture discussion above.

Back to Blog

Related posts

Read more »