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:
- Convenient SaaS: (e.g., Notion, Keep) store user data in plaintext or use server-managed keys, leaving data vulnerable to internal leaks or database breaches.
- Self-Hosted: (e.g., Obsidian, Nextcloud) offer 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 nothing but 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.
- Frontend: React (Vite) with Material UI. Responsibilities include UI rendering and client-side cryptographic operations (encryption/decryption).
-
Backend: Node.js and Express, following a Hybrid Architecture
- Local Development: Runs as a fully dockerized monolithic container, ensuring a consistent development environment that mirrors production dependencies.
- Production Deployment: Deployed to Vercel as stateless Serverless Functions, allowing the API to scale to zero when idle (cost-efficient) while maintaining a single Express codebase.
Database: MongoDB Atlas for storing encrypted metadata and ciphertext.
Authentication: Clerk. Delegating identity management reduced the attack surface for auth flows (MFA, session management).
Storage: Supabase Storage, used strictly for isolating binary objects (images and PDFs) via signed URLs.
Security by Design: The Zero-Trust Vault
Security was not an optional feature; it was the primary architectural constraint.
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 were to expose environment variables, they could decrypt everyone's data. The key was visible, which violated the core concept of Zero-Trust.
2. The Solution: User-Derived Cryptography
To fix this, I removed the static key entirely. I 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 and exists only transiently in the client’s memory.
- The browser runs PBKDF2 to derive a temporary 256-bit AES key in memory.
- This key is used to encrypt notes, titles, and file paths before the network request is even 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: This URL allows access 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)
To solve the deployment cost problem, I re-architected the stack to run for $0/month:
-
Local Development (Dockerized): I kept the convenience of a containerized environment. A single
docker-compose upspins up the Frontend, Backend, and Database services. This ensures that the development environment is isolated and reproducible on any machine. - Production Deployment (Serverless): Instead of paying for a permanently running container (which costs money even when idle), I refactored the Express application to run on Vercel Serverless Functions.
- The Result: I effectively have a "Serverless Monolith." I develop it like a standard monolithic app (easy to debug, easy to run locally in Docker) but deploy it as distributed functions. This gives me the best of both worlds: Zero infrastructure management and Zero cost for personal use.
I intentionally avoided microservices, as the domain does not yet justify multiple bounded contexts, and premature service decomposition would increase complexity and attack surface without tangible benefits.
Technical Challenges & Solutions
1. Environment Variable Visibility
As mentioned, relying on .env files for security was a mistake. The migration to user-derived keys solved this, but it required handling edge cases like "Lost Passwords." Since I no longer had the key, I had to implement a "Nuclear Reset" feature. This allows users to wipe their unrecoverable data and start fresh, prioritizing security over recovery.
2. Monorepo Build Contexts
Vercel initially failed to build the project because it couldn't locate vite.config.js within the monorepo structure. I resolved this by explicitly configuring the "Root Directory" in Vercel settings and rewriting the build command to ensure dependencies were installed from the correct path.
3. The Docker vs. Serverless Routing Mismatch
One of the most complex challenges was reconciling the difference between a running Docker container and Vercel's file-system routing.
The Problem: In my local Docker container, Express handled all routing internally. However, when deployed to Vercel, the platform treated the API as static files. Requests to sub-paths (like
/api/info/nuke) were hitting Vercel's 404 handler before reaching my Express app, which the browser misinterpreted as a CORS failure.The Solution: I implemented a Hybrid Routing Strategy. I created a Vercel-compatible entry point (
api/info.js) and configured a vercel.json rewrite rule. This acts as a bridge, telling Vercel to pipe all sub-route traffic directly into the Express instance. This fixed the CORS issues and allowed the exact same code to run inside Docker (locally) and as a Function (in production).
Future Roadmap
While InfoStuffs is fully functional, I plan to explore:
- Redis Caching: To reduce database reads for frequently accessed (encrypted) metadata.
- React Native Mobile App: Wrapping the existing logic to allow biometric vault unlocking (FaceID) instead of typing the password.
- Offline Mode: Using PWA capabilities to allow read-only access to cached encrypted notes.
Closing Thoughts
InfoStuffs is more than a note-taking application. It is a practical exploration of Zero-Trust Engineering.
By addressing the real-world problems of data visibility and cloud costs, I built a system where privacy is enforced by mathematics, not by policy. It satisfies a real user need while serving as a valuable learning experience in full-stack security and DevOps.
Repository: GitHub
Live Deployment: Link
Note: The live deployment requires authentication and a vault password. The core security properties are enforced client-side and are best understood via the architecture discussion above.


Top comments (0)