Even we can't read your notes - Built with modern web technologies and client-side encryption
- 🔐 Client-side AES-256-GCM encryption - Your notes are encrypted before leaving your device
- 🔑 Master password management - Change your master password with automatic key re-derivation
- 🛡️ Zero-knowledge architecture - Server never sees unencrypted data
- 🔄 Real-time sync - Access your notes from anywhere securely
- 📁 Nested folder organization - Create unlimited folder hierarchies with drag & drop
- 🔄 Move & organize - Move notes and folders between locations
- ⭐ Star, archive, and organize - Keep your important notes accessible
- 🙈 Hide sensitive notes - Keep private notes hidden from quick view
- 🏷️ Smart filtering & sorting - Filter by starred, hidden, with attachments, or sort by date/title
- 🔍 Full-text search - Find notes instantly (searches encrypted data locally)
- 📝 Modern rich text editing - Powered by TipTap with extensive formatting support
- 🎨 Comprehensive formatting - Bold, italic, underline, strikethrough, highlights
- 📋 Lists & structure - Bullet lists, numbered lists, task lists, blockquotes
- 🖼️ Smart image handling - Upload, resize, drag & drop images with visual controls
- 📑 Table of contents - Auto-generated TOC with smooth navigation
- ⚡ Slash commands - Quick formatting with
/
commands (headings, lists, images, etc.) - 📋 Note templates - Pre-built templates for meetings, projects, daily notes, research, and secure password storage
- 💾 Auto-save - Real-time saving with visual indicators
- 🔗 Links & references - Easy link insertion and management
- 🧮 Code support - Inline code and code blocks with syntax highlighting
- 📈 Real-time statistics - Word count, character count, reading time estimates
- 📜 Scroll tracking - Visual scroll position indicator
- 🔍 Zoom controls - Adjustable text size (50%-200%) with visual controls
- 💾 Save status - Live save status with visual feedback
- 🌙 Dark/Light mode - Easy on the eyes, day or night
- 📎 File attachments - Upload and encrypt files up to 10MB per file
- 📊 Usage tracking - Monitor storage and notes limits with visual progress indicators
- 📱 Responsive design - Works seamlessly on desktop and mobile
- 🖨️ Print support - Clean printing with proper formatting
Typelets uses industry-standard encryption:
- AES-256-GCM encryption algorithm
- 250,000 PBKDF2 iterations for key derivation
- Per-note salt - Each note has a unique encryption key
- File encryption - Attachments are encrypted with the same security as notes
- Zero-knowledge architecture - Server never sees unencrypted data
Your encryption keys are derived from your master password. Even if our database is compromised, your notes and files remain encrypted and unreadable.
- Mandatory Setup: You must set a master password on first use
- Client-Side Encryption: All encryption happens in your browser
- Encrypted Storage: Only encrypted data is sent to our servers
- No Recovery: We cannot recover forgotten passwords (by design)
For complete security details and technical implementation, see our Security Documentation →
- Node.js 20+ (LTS recommended)
- pnpm 9.15.0+
- A Clerk account for authentication
# Clone the repository
git clone https://github.com/typelets/typelets-app.git
cd typelets
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env.local
# Start the development server
pnpm dev
The app will be available at http://localhost:5173
Create .env.local
with your configuration:
# Required - Clerk Authentication
VITE_CLERK_PUBLISHABLE_KEY=pk_test_your_clerk_key
# API Configuration
VITE_API_URL=/api
# Proxy Configuration (for development)
# The proxy will forward /api requests to this target
VITE_PROXY_TARGET=https://dev.api.typelets.com
# Optional
VITE_APP_NAME=Typelets
VITE_APP_VERSION=0.5.0
Get your Clerk keys from dashboard.clerk.com
The development server includes a built-in proxy to avoid CORS issues during local development. The proxy automatically forwards all /api
requests to your backend server.
# Default: Use dev API server
pnpm dev
# Use local Docker API
VITE_PROXY_TARGET=http://localhost:8080 pnpm dev
# Use production API (for testing)
VITE_PROXY_TARGET=https://api.typelets.com pnpm dev
You can also create environment-specific files:
.env.local
- Default development.env.docker
- Local Docker API.env.production
- Production build
# Build Docker image
docker build -t typelets-app:latest \
--build-arg VITE_CLERK_PUBLISHABLE_KEY=your_clerk_key \
--build-arg VITE_API_URL=/api \
.
# Run with your backend
docker run -p 80:8080 \
-e BACKEND_URL=https://your-api-domain.com \
typelets-app:latest
Windows (PowerShell)
# Set your configuration
$env:AWS_ACCOUNT_ID = (aws sts get-caller-identity --query Account --output text)
$env:AWS_REGION = "us-east-1"
$env:ECR_REPOSITORY = "typelets-app"
$env:VITE_CLERK_PUBLISHABLE_KEY = "pk_live_your_key_here"
$env:VITE_API_URL = "/api"
# Create ECR repository (first time only)
aws ecr create-repository `
--repository-name $env:ECR_REPOSITORY `
--region $env:AWS_REGION `
--image-scanning-configuration scanOnPush=true
# Login to ECR
aws ecr get-login-password --region $env:AWS_REGION | docker login --username AWS --password-stdin "$env:AWS_ACCOUNT_ID.dkr.ecr.$env:AWS_REGION.amazonaws.com"
# Build the Docker image
docker build -t typelets-app:latest `
--build-arg VITE_CLERK_PUBLISHABLE_KEY=$env:VITE_CLERK_PUBLISHABLE_KEY `
--build-arg VITE_API_URL=$env:VITE_API_URL `
.
# Tag for ECR
docker tag typelets-app:latest `
"$env:AWS_ACCOUNT_ID.dkr.ecr.$env:AWS_REGION.amazonaws.com/${env:ECR_REPOSITORY}:latest"
# Push to ECR
docker push "$env:AWS_ACCOUNT_ID.dkr.ecr.$env:AWS_REGION.amazonaws.com/${env:ECR_REPOSITORY}:latest"
Mac/Linux
# Set your configuration
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export AWS_REGION=us-east-1
export ECR_REPOSITORY=typelets-app
export VITE_CLERK_PUBLISHABLE_KEY=pk_live_your_key_here
export VITE_API_URL=/api
# Create ECR repository (first time only)
aws ecr create-repository \
--repository-name $ECR_REPOSITORY \
--region $AWS_REGION \
--image-scanning-configuration scanOnPush=true
# Login to ECR
aws ecr get-login-password --region $AWS_REGION | \
docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
# Build the Docker image
docker build -t typelets-app:latest \
--build-arg VITE_CLERK_PUBLISHABLE_KEY=$VITE_CLERK_PUBLISHABLE_KEY \
--build-arg VITE_API_URL=$VITE_API_URL \
.
# Tag for ECR
docker tag typelets-app:latest \
$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:latest
# Push to ECR
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:latest
Argument | Description | Example |
---|---|---|
VITE_CLERK_PUBLISHABLE_KEY |
Clerk authentication key | pk_live_xxx |
VITE_API_URL |
API path for React app (MUST be /api ) |
/api |
Variable | Description | Default |
---|---|---|
BACKEND_URL |
Your backend API URL | https://api.typelets.com |
Variable | Description | Default |
---|---|---|
VITE_PROXY_TARGET |
Backend URL for development proxy | https://dev.api.typelets.com |
VITE_API_URL |
API path (keep as /api ) |
/api |
AWS ECS
{
"containerDefinitions": [{
"name": "typelets-app",
"image": "your-ecr-uri:latest",
"environment": [
{
"name": "BACKEND_URL",
"value": "https://your-api-domain.com"
}
],
"portMappings": [{
"containerPort": 8080
}]
}]
}
Docker Compose
version: '3.8'
services:
typelets-app:
image: typelets-app:latest
ports:
- "80:8080"
environment:
- BACKEND_URL=https://your-api-domain.com
# Development
pnpm dev # Start dev server with proxy
pnpm dev:docker # Start with local Docker API
pnpm build # Build for production
pnpm preview # Preview production build
# Code Quality
pnpm lint # Check for linting issues
pnpm lint:fix # Auto-fix linting issues
pnpm format # Format code with Prettier
pnpm type-check # Check TypeScript types
# Docker
pnpm docker:build # Build Docker image
pnpm docker:run # Run container locally
typelets/
├── src/
│ ├── components/ # React components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Utility functions & services
│ │ └── encryption/ # Client-side encryption
│ ├── types/ # TypeScript definitions
│ └── App.tsx # Main App component
├── public/ # Static assets
├── nginx.conf.template # Nginx configuration
├── vite.config.ts # Vite configuration with proxy
├── Dockerfile # Docker configuration
└── .env.example # Environment variables template
- Framework: React 19 with TypeScript
- Build Tool: Vite 7 with development proxy
- Styling: Tailwind CSS v4
- Editor: TipTap with code highlighting
- Authentication: Clerk
- UI Components: Radix UI
- Encryption: Web Crypto API with AES-256-GCM
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'feat: add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
MIT License - see LICENSE file for details