A comprehensive, privacy-focused digital services platform built with cutting-edge web technologies
Developed by @7ttp
Repository: github.com/7ttp/erypt-web
Features • Architecture • Tech Stack • Quick Start • Documentation
- Overview
- Core Features
- System Architecture
- Privacy Workflows
- Technology Stack
- Project Structure
- Installation & Setup
- Development Guide
- Component Documentation
- API Reference
- Security Implementation
- Performance Optimization
- Testing Strategy
- Deployment Guide
- Environment Configuration
- Troubleshooting
- Best Practices
- Contributing
- License
Erypt-Web is a modern, enterprise-grade web application that prioritizes user privacy and anonymity above all else. Built on Next.js 15 with the App Router, this platform delivers a comprehensive suite of privacy-focused digital services including anonymous eSIMs, virtual payment cards, encrypted email, VPN/proxy services, and encrypted voice calling.
In an era where digital privacy is constantly under threat, Erypt-Web stands as a fortress for user anonymity:
- Zero Personal Data Collection: We don't ask for, collect, or store any personally identifiable information
- End-to-End Encryption: All data is encrypted before leaving your device
- Cryptocurrency Payments Only: No credit cards, no banks, no payment trails
- No Surveillance: No analytics, tracking, cookies, or fingerprinting
- Open Source: Full transparency in our codebase and security practices
- Self-Sovereign Identity: You own and control your digital identity completely
- Privacy by Design: Privacy is not an afterthought but the foundation of every feature
- User Anonymity: Users can access all services without revealing their identity
- Zero-Knowledge Architecture: We cannot access or decrypt user data
- Transparency: All code, security measures, and policies are open for review
- User Control: Users have complete control over their data and services
Global Cellular Connectivity Without Identity Verification
Our eSIM service revolutionizes mobile connectivity by eliminating the need for identity verification, physical SIM cards, and personal information disclosure.
- Instant Activation: eSIM profiles generated and delivered within 60 seconds
- No Registration Required: Purchase and activate without providing any personal details
- Global Coverage: 150+ countries with partnerships with major MNOs
- Flexible Plans: Data-only, voice+data, and regional/global packages
- Multiple Durations: From 1-day passes to annual subscriptions
- Auto-Renewal: Optional automatic top-up using crypto wallet balance
- QR Code Delivery: Instant eSIM profile delivery via encrypted QR code
- Multi-Device Support: Manage multiple eSIMs across devices
Regional Data Plans:
North America (USA, Canada, Mexico)
- 1GB / 7 days: $15
- 3GB / 30 days: $30
- 5GB / 30 days: $45
- 10GB / 30 days: $80
Europe (30+ countries)
- 1GB / 7 days: $20
- 3GB / 30 days: $35
- 5GB / 30 days: $50
- 10GB / 30 days: $90
Asia-Pacific (25+ countries)
- 1GB / 7 days: $18
- 3GB / 30 days: $33
- 5GB / 30 days: $48
- 10GB / 30 days: $85
Global (150+ countries)
- 1GB / 7 days: $50
- 3GB / 30 days: $90
- 5GB / 30 days: $140
- 10GB / 30 days: $250
- 20GB / 30 days: $450
Voice + Data Plans:
USA/Canada
- 100 min + 1GB: $25/month
- 500 min + 3GB: $45/month
- Unlimited min + 10GB: $90/month
Europe
- 100 min + 1GB: $30/month
- 500 min + 3GB: $55/month
- Unlimited min + 10GB: $110/month
- Standard: GSMA eSIM Remote Provisioning (RSP) v2.4
- Encryption: End-to-end encrypted provisioning
- Compatibility:
- iPhone: XS, XS Max, XR, 11, 12, 13, 14, 15, 16 series
- Samsung: Galaxy S20, S21, S22, S23, S24, Z Fold/Flip series
- Google: Pixel 3, 4, 5, 6, 7, 8, 9 series
- Others: Most devices released after 2019 with eSIM support
- Activation Methods:
- QR Code scanning
- Manual SM-DP+ address entry
- Direct profile download via app
- Profile Management: Add, activate, deactivate, delete profiles
- Network Technology: 4G LTE, 5G where available
- International Travel: Stay connected without roaming charges
- Privacy Protection: Use separate number for online services
- Business: Separate work and personal lines
- Testing: Developers testing multi-region apps
- Remote Work: Access region-specific services
Anonymous Payment Cards Funded with Cryptocurrency
Generate virtual payment cards that work with any online merchant while keeping your identity and crypto holdings completely private.
- Instant Issuance: Cards generated in under 30 seconds
- Crypto Funding: Load cards with BTC, ETH, SOL, USDT, USDC, or other cryptocurrencies
- Unlimited Cards: Create as many virtual cards as you need
- Merchant Category Controls: Set spending limits per merchant category
- Single-Use Cards: Disposable cards for one-time purchases
- Multi-Use Cards: Reusable cards for subscriptions and recurring payments
- Global Acceptance: Visa/Mastercard accepted worldwide
- No Credit Check: No personal information or credit history required
- Real-Time Notifications: Optional transaction alerts via encrypted channel
Single-Use Virtual Card
Purpose: One-time purchases
Validity: 24 hours after first use
Max Amount: $500
Ideal For: One-time purchases, untrusted merchants
Price: $2 per card
Multi-Use Virtual Card
Purpose: Recurring payments, subscriptions
Validity: 1-12 months (customizable)
Max Amount: $5,000 per month
Ideal For: Netflix, Spotify, SaaS subscriptions
Price: $5/month
Premium Virtual Card
Purpose: High-value transactions
Validity: 12 months
Max Amount: $50,000 per month
Ideal For: Business expenses, large purchases
Price: $25/month
Physical Card (Coming Soon)
Purpose: In-person payments
Validity: 5 years
Max Amount: $100,000 per month
Ideal For: ATM withdrawals, retail purchases
Price: $100 one-time + $10/month
- Dynamic CVV: CVV code changes every 10 minutes
- 3D Secure 2.0: Full support for Strong Customer Authentication (SCA)
- Merchant Locks: Restrict card to specific merchants
- Spending Controls: Set limits by:
- Transaction amount
- Daily/weekly/monthly totals
- Merchant category (MCC codes)
- Geographic region
- Freeze/Unfreeze: Instantly disable and re-enable cards
- Transaction History: Encrypted transaction logs
- Withdrawal Limits: Customize ATM withdrawal limits (physical cards)
Bitcoin (BTC)
- Network: Lightning Network for instant settlements
- Min Load: $50
- Fees: 0.5%
Ethereum (ETH)
- Network: Ethereum Mainnet
- Min Load: $50
- Fees: Gas + 0.5%
Solana (SOL)
- Network: Solana Mainnet
- Min Load: $20
- Fees: 0.1% (ultra-low)
Stablecoins (USDT, USDC, DAI)
- Networks: Ethereum, Solana, Polygon, BSC
- Min Load: $20
- Fees: 0.3%
Other Supported:
- Litecoin (LTC)
- Bitcoin Cash (BCH)
- Monero (XMR) - Maximum privacy
- Online Shopping: Shop on any website without exposing credit card
- Subscription Services: Pay for Netflix, Spotify, etc. with crypto
- Business Expenses: Separate business spending from personal
- Privacy Protection: Prevent merchant tracking and data breaches
- International Payments: Avoid currency conversion fees
- Trial Subscriptions: Use single-use cards for free trials
End-to-End Encrypted Email with Zero-Knowledge Architecture
Our email service provides true privacy with end-to-end encryption, self-destructing messages, and zero-access encryption where even we cannot read your emails.
- End-to-End Encryption: OpenPGP (RFC 4880) encryption with 4096-bit RSA keys
- Zero-Access Encryption: Your emails are encrypted on your device; we cannot decrypt them
- Self-Destructing Messages: Set expiration times from 1 hour to 30 days
- Anonymous Aliases: Create unlimited email aliases ([email protected])
- Custom Domains: Bring your own domain with full encryption support
- No IP Logging: We don't log IP addresses or connection metadata
- Encrypted Attachments: Send files up to 50MB with full encryption
- PGP Key Management: Import/export your own PGP keys
- Encrypted Contacts: Your address book is encrypted end-to-end
- Two-Factor Authentication: Optional TOTP 2FA for account security
Free Plan
Storage: 1GB
Daily Email Limit: 100 emails/day
Aliases: 5 email aliases
Attachments: 10MB per file
Self-Destruct: Yes
Custom Domain: No
Support: Community
Price: FREE (crypto-funded)
Pro Plan
Storage: 10GB
Daily Email Limit: Unlimited
Aliases: 50 email aliases
Attachments: 50MB per file
Self-Destruct: Yes (custom times)
Custom Domain: Yes (1 domain)
Encrypted Calendar: Yes
Support: Priority email support
Price: $5/month (SOL)
Business Plan
Storage: 100GB per user
Daily Email Limit: Unlimited
Aliases: Unlimited
Attachments: 100MB per file
Self-Destruct: Yes (custom times)
Custom Domains: Yes (unlimited)
Encrypted Calendar: Yes
Encrypted Drive: 50GB
Team Management: Yes
Support: 24/7 priority support
Price: $15/month per user
Enterprise Plan
Storage: Custom (1TB+)
All Business features plus:
- Dedicated infrastructure
- Custom encryption options
- Compliance tools
- Advanced admin controls
- SLA guarantees
- Dedicated account manager
Price: Custom (contact sales)
Encryption Standards:
Email Body: OpenPGP (RFC 4880)
Key Size: 4096-bit RSA or Curve25519
Attachments: AES-256-GCM
Storage: Zero-knowledge encryption
Transport: TLS 1.3
Protocols Supported:
- SMTP (Secure SMTP)
- IMAP (Encrypted IMAP)
- POP3 (Encrypted POP3)
- Webmail (PWA)
- Bridge Protocol (for desktop clients)
Client Compatibility:
- Desktop: Thunderbird, Apple Mail, Outlook (via bridge)
- Mobile: Native iOS/Android apps
- Web: Progressive Web App (PWA)
- CLI: Command-line email client
Self-Destructing Messages:
interface SelfDestructConfig {
enabled: boolean;
expiresAfter: '1h' | '24h' | '7d' | '30d' | 'custom';
deleteOnRead: boolean;
recipientCanReply: boolean;
notifyBeforeExpiration: boolean;
}Email Aliases:
- Simple Aliases: [email protected]
- Random Aliases: [email protected]
- Custom Aliases: [email protected]
- Domain Aliases: [email protected]
Spam Protection:
- Sender reputation scoring
- SPF, DKIM, DMARC validation
- Bayesian filtering
- User-defined rules
- Encrypted spam folder
Anonymous Browsing with Audited No-Log Policy
Our VPN service provides military-grade encryption and true privacy with an independently audited no-logging policy.
- Zero-Log Policy: Independently audited by third-party security firms
- 50+ Server Locations: Optimized servers across 5 continents
- Unlimited Bandwidth: No data caps, no throttling, ever
- Kill Switch: Automatic disconnect if VPN connection drops
- Split Tunneling: Route specific apps/domains through VPN
- Ad & Tracker Blocking: Built-in DNS-level blocking
- Malware Protection: Block malicious domains in real-time
- Multi-Hop: Route through multiple servers for extra privacy
- Port Forwarding: For P2P and remote access
- IPv6 Support: Full IPv6 leak protection
- 10 Simultaneous Connections: Connect up to 10 devices
Americas (15 locations)
North America:
- USA: New York, Los Angeles, Chicago, Miami, Seattle
- Canada: Toronto, Vancouver
- Mexico: Mexico City
South America:
- Brazil: São Paulo
- Argentina: Buenos Aires
- Chile: Santiago
Europe (20 locations)
Western Europe:
- UK: London, Manchester
- France: Paris
- Germany: Frankfurt, Berlin
- Netherlands: Amsterdam
- Switzerland: Zurich
Eastern Europe:
- Poland: Warsaw
- Czech Republic: Prague
- Romania: Bucharest
Nordic:
- Sweden: Stockholm
- Finland: Helsinki
- Norway: Oslo
- Denmark: Copenhagen
Southern Europe:
- Spain: Madrid
- Italy: Milan
- Portugal: Lisbon
Asia-Pacific (10 locations)
East Asia:
- Japan: Tokyo, Osaka
- South Korea: Seoul
- Hong Kong
- Taiwan: Taipei
Southeast Asia:
- Singapore
- Thailand: Bangkok
- Vietnam: Ho Chi Minh
South Asia:
- India: Mumbai
Oceania:
- Australia: Sydney
Middle East & Africa (5 locations)
Middle East:
- UAE: Dubai
- Israel: Tel Aviv
- Turkey: Istanbul
Africa:
- South Africa: Johannesburg
- Egypt: Cairo
WireGuard (Recommended)
Speed: ⭐⭐⭐⭐⭐
Security: ⭐⭐⭐⭐⭐
Encryption: ChaCha20-Poly1305
Use Case: General browsing, streaming
Platforms: All
OpenVPN
Speed: ⭐⭐⭐⭐
Security: ⭐⭐⭐⭐⭐
Encryption: AES-256-GCM
Use Case: Maximum compatibility
Platforms: All
IKEv2/IPSec
Speed: ⭐⭐⭐⭐
Security: ⭐⭐⭐⭐
Encryption: AES-256-GCM
Use Case: Mobile devices
Platforms: iOS, macOS, Windows
Server Speed: Up to 10 Gbps
Latency: < 50ms average
Uptime: 99.9% SLA
Bandwidth: Unlimited
Concurrent Connections: 10 devices
Server Load Balancing: Automatic
Multi-Hop VPN: Route your connection through multiple servers:
You → Server 1 (USA) → Server 2 (Switzerland) → Internet
Split Tunneling:
interface SplitTunnelConfig {
mode: 'whitelist' | 'blacklist';
apps: string[]; // App-based routing
domains: string[]; // Domain-based routing
ipRanges: string[]; // IP-based routing
}DNS Configuration:
- Private DNS servers (no logging)
- DNS-over-HTTPS (DoH)
- DNS-over-TLS (DoT)
- Custom DNS servers
- Ad/tracker blocking at DNS level
Encrypted Voice Calls with Disposable Phone Numbers
Make voice calls with temporary phone numbers that provide complete anonymity and end-to-end encryption.
- Temporary Numbers: Get disposable phone numbers in 60+ countries
- End-to-End Encryption: SRTP encryption for all voice calls
- HD Voice Quality: Opus codec with 48 kHz audio sampling
- Call Recording: Optional encrypted call recording
- Voicemail: Anonymous voicemail with transcription
- SMS Support: Send and receive SMS messages
- Number Forwarding: Forward calls to any phone number
- Conference Calling: Up to 10 participants per call
- Call Screening: See caller ID before answering
- Do Not Disturb: Schedule quiet hours
- Spam Protection: Automatic spam call blocking
Local Numbers
North America (USA/Canada)
- Any area code: $5/month
- Toll-free (800, 888, etc.): $15/month
United Kingdom
- Local: $7/month
- Toll-free (0800): $18/month
Europe (30+ countries)
- Local: $8/month
- Toll-free: $20/month
Asia-Pacific (25+ countries)
- Local: $6/month
- Toll-free: $18/month
Latin America (15+ countries)
- Local: $7/month
- Toll-free: $20/month
Premium Numbers
Vanity Numbers (e.g., 555-PRIVACY)
- USA: $50/month
- International: $75/month
Short Codes (for business)
- 5-digit: $500/month
- 6-digit: $300/month
Audio Codec:
Primary: Opus (Variable bitrate)
- Sample Rate: 48 kHz
- Bitrate: 6-510 kbps
- Latency: < 50ms
Fallback: G.722, G.711
Encryption:
Protocol: SRTP (Secure Real-time Transport Protocol)
Cipher: AES-256-GCM
Key Exchange: DTLS-SRTP
Perfect Forward Secrecy: Yes
Network Quality:
Jitter Buffer: Adaptive
Packet Loss Concealment: Yes
Echo Cancellation: Yes
Noise Suppression: Yes
Automatic Gain Control: Yes
Mobile Apps
- iOS 14+ (iPhone, iPad)
- Android 8.0+ (Phone, Tablet)
Desktop Apps
- Windows 10/11
- macOS 11+
- Linux (AppImage, Snap)
Web App
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- WebRTC-enabled browsers
Hardware Support
- USB Headsets
- Bluetooth Devices
- Desk Phones (SIP)
- Business: Separate work number without second device
- Online Dating: Give out temporary number for safety
- Craigslist/Marketplace: Protect personal number in transactions
- Travel: Local number in foreign countries
- Privacy: Different numbers for different contexts
- Two-Factor Auth: Receive SMS codes anonymously
| Feature | eSIM | Virtual Card | VPN | Voice | |
|---|---|---|---|---|---|
| Anonymous Signup | ✓ | ✓ | ✓ | ✓ | ✓ |
| Crypto Payment Only | ✓ | ✓ | ✓ | ✓ | ✓ |
| No KYC/Identity Verification | ✓ | ✓ | ✓ | ✓ | ✓ |
| Instant Activation | ✓ (60s) | ✓ (30s) | ✓ (instant) | ✓ (instant) | ✓ (5min) |
| End-to-End Encryption | ✓ | ✓ | ✓ | ✓ | ✓ |
| Multiple Instances | ✓ | ✓ (unlimited) | ✓ (aliases) | ✓ (10 devices) | ✓ (multiple) |
| Global Coverage | 150+ countries | Worldwide | Worldwide | 50+ countries | 60+ countries |
| Data Privacy Level | Maximum | Maximum | Maximum | Maximum | Maximum |
| Open Source Client | N/A | N/A | ✓ | ✓ | ✓ |
| Third-Party Audits | ✓ | ✓ | ✓ | ✓ | ✓ |
| Customer Support | Email/Chat | Email/Chat | Email/Chat |
graph TB
subgraph "Client Layer"
A[Web Browser] --> B[Next.js 15 Frontend]
B --> C[React 19 Components]
B --> D[Smooth Scroll Provider]
B --> E[Authentication Context]
end
subgraph "Presentation Layer"
C --> F[Hero Section]
C --> G[Services Section]
C --> H[Pricing Section]
C --> I[Benefits Section]
F --> J[GSAP Animations]
G --> J
H --> J
end
subgraph "Security Layer"
E --> K[Cloudflare Turnstile]
E --> L[JWT Token Manager]
L --> M[HttpOnly Cookies]
K --> N[Bot Protection]
end
subgraph "API Layer"
B --> O[Next.js API Routes]
O --> P[Authentication API]
O --> Q[Services API]
O --> R[Payment API]
end
subgraph "Business Logic Layer"
P --> S[User Registration]
P --> T[User Login]
Q --> U[eSIM Management]
Q --> V[Card Management]
Q --> W[Email Management]
R --> X[Crypto Payment Gateway]
end
subgraph "Data Layer"
S --> Y[(Encrypted Database)]
T --> Y
U --> Y
V --> Y
W --> Y
X --> Z[Blockchain Explorer]
end
subgraph "External Services"
K --> AA[Cloudflare Network]
X --> AB[Solana Blockchain]
U --> AC[Telecom Provider API]
V --> AD[Card Issuer API]
end
style B fill:#0070f3
style Y fill:#ff0080
style AB fill:#14F195
style K fill:#F38020
graph LR
subgraph "Atomic Design Pattern"
A[Atoms] --> B[Molecules]
B --> C[Organisms]
C --> D[Templates]
D --> E[Pages]
end
subgraph "Atoms"
A --> F[Button]
A --> G[Heading]
A --> H[TagLine]
A --> I[AnimatedButton]
end
subgraph "Layout Components"
C --> J[Navbar]
C --> K[Footer]
C --> L[Section]
C --> M[BottomNavbar]
end
subgraph "Section Components"
C --> N[Hero]
C --> O[Benefits]
C --> P[Services]
C --> Q[Pricing]
C --> R[Roadmap]
C --> S[Collaboration]
end
subgraph "Utility Components"
T[Providers] --> U[SmoothScrollProvider]
V[Support] --> W[CrispChat]
V --> X[LiveChatBubble]
Y[UI] --> Z[ScrollToTop]
end
sequenceDiagram
participant User
participant Browser
participant NextJS
participant API
participant Crypto
participant Service
User->>Browser: Visit Website
Browser->>NextJS: Request Page
NextJS->>Browser: Return Static HTML + JS
Browser->>User: Display Landing Page
User->>Browser: Click "Sign Up"
Browser->>NextJS: Navigate to /register
NextJS->>Browser: Registration Form
User->>Browser: Submit Form
Browser->>Browser: Hash Password (bcrypt)
Browser->>API: POST /api/auth/register
API->>API: Validate with Turnstile
API->>API: Encrypt User Data
API->>API: Store in Database
API->>Browser: Return JWT Token
Browser->>Browser: Store Token in Cookie
User->>Browser: Purchase eSIM
Browser->>API: POST /api/purchase
API->>Crypto: Verify Payment
Crypto->>API: Payment Confirmed
API->>Service: Provision eSIM
Service->>API: eSIM Profile
API->>Browser: Return QR Code
Browser->>User: Display eSIM QR
sequenceDiagram
participant User
participant Client
participant Turnstile
participant API
participant DB
User->>Client: Enter Credentials
Note over User,Client: No email required<br/>Optional anonymous signup
Client->>Client: Validate Input
Client->>Client: Hash Password (bcrypt, 12 rounds)
Client->>Turnstile: Request Challenge
Turnstile->>Client: Return Challenge Token
Client->>API: POST /api/auth/register
Note over Client,API: username, passwordHash, turnstileToken
API->>Turnstile: Verify Token
Turnstile->>API: Verification Result
alt Token Invalid
API->>Client: 403 Forbidden
Client->>User: Show Error
else Token Valid
API->>API: Generate UUID
API->>API: Encrypt Metadata
API->>DB: Store User Record
DB->>API: Success
API->>API: Generate JWT
API->>Client: Return JWT + Set Cookie
Client->>User: Redirect to Dashboard
end
sequenceDiagram
participant User
participant Client
participant API
participant JWT
participant DB
User->>Client: Enter Credentials
Client->>Client: Hash Password
Client->>API: POST /api/auth/login
Note over Client,API: username, passwordHash
API->>DB: Query User by Username
DB->>API: Return User Record
alt User Not Found
API->>Client: 404 Not Found
else User Found
API->>API: Compare Password Hashes
alt Password Mismatch
API->>Client: 401 Unauthorized
Client->>User: Show Error
else Password Match
API->>JWT: Generate Token
Note over JWT: Payload: userId, iat, exp<br/>No PII included
JWT->>API: Return Signed Token
API->>Client: Set HttpOnly Cookie
Note over API,Client: Cookie Attributes:<br/>HttpOnly, Secure<br/>SameSite: Strict<br/>MaxAge: 7 days
API->>Client: 200 OK + User Data
Client->>User: Redirect to Dashboard
end
end
sequenceDiagram
participant User
participant Client
participant API
participant Payment
participant Blockchain
participant Provider
participant DB
User->>Client: Select Service (eSIM)
Client->>API: GET /api/services/esim/plans
API->>Client: Return Available Plans
User->>Client: Choose Plan
Client->>API: POST /api/purchase/initiate
Note over Client,API: serviceType, planId
API->>API: Calculate Price
API->>Payment: Generate Payment Address
Payment->>Blockchain: Create SOL Address
Blockchain->>Payment: Return Address
Payment->>API: Return Payment Details
API->>Client: Return Payment Info
Note over API,Client: address, amount, timeout
Client->>User: Display Payment QR
User->>User: Send Crypto
loop Check Payment Status
Client->>API: GET /api/purchase/status/id
API->>Blockchain: Query Transaction
alt Payment Confirmed
Blockchain->>API: Transaction Found
API->>Provider: Provision Service
Provider->>API: Return Service Details
API->>DB: Store Purchase Record
API->>Client: Service Activated
Client->>User: Display Service Info
else Payment Pending
Blockchain->>API: Not Found
API->>Client: Still Pending
end
end
sequenceDiagram
participant User
participant Client
participant API
participant Encryption
participant DB
User->>Client: Submit Sensitive Data
Note over User,Client: Email, Phone, Notes
Client->>Client: Generate Random Salt
Client->>Encryption: Encrypt Data (AES-256-GCM)
Note over Client,Encryption: Key derived from password<br/>plus master key
Encryption->>Client: Return Encrypted Blob
Note over Encryption,Client: ciphertext, iv, tag, salt
Client->>API: POST /api/data/store
API->>API: Validate Authentication
API->>DB: Store Encrypted Blob
DB->>API: Success
API->>Client: 200 OK
Note over User,DB: Data stored encrypted<br/>Server cannot decrypt
User->>Client: Request Data
Client->>API: GET /api/data/retrieve
API->>DB: Query Encrypted Data
DB->>API: Return Encrypted Blob
API->>Client: Return Blob
Client->>Client: Derive Decryption Key
Client->>Encryption: Decrypt Data
Encryption->>Client: Return Plaintext
Client->>User: Display Data
sequenceDiagram
participant User
participant Client
participant API
participant PaymentGateway
participant Solana
participant PriceOracle
participant DB
User->>Client: Initiate Purchase
Client->>API: POST /api/payment/create
API->>PriceOracle: Get Current SOL Price
PriceOracle->>API: Return Price (USD/SOL)
API->>API: Calculate SOL Amount
Note over API: USD Price / SOL Price = SOL Amount
API->>PaymentGateway: Generate Payment Address
PaymentGateway->>Solana: Create New Keypair
Solana->>PaymentGateway: Return Public Key
PaymentGateway->>API: Return Payment Details
Note over PaymentGateway,API: address, amount, memo, timeout
API->>DB: Store Payment Record
Note over API,DB: Status: PENDING<br/>Expires: now + 30min
API->>Client: Return Payment Info
Client->>User: Show QR Code + Address
User->>User: Send SOL from Wallet
User->>Solana: Submit Transaction
loop Monitor Payment (30 min timeout)
PaymentGateway->>Solana: Query Address Balance
alt Transaction Found
Solana->>PaymentGateway: Transaction Details
PaymentGateway->>PaymentGateway: Verify Amount & Memo
alt Amount Correct
PaymentGateway->>API: Payment Confirmed
API->>DB: Update Status: CONFIRMED
API->>API: Trigger Service Provisioning
API->>Client: WebSocket: Payment Success
Client->>User: Redirect to Service
else Amount Incorrect
PaymentGateway->>API: Amount Mismatch
API->>Client: Request Additional Payment
end
else No Transaction
Solana->>PaymentGateway: No Transaction
PaymentGateway->>API: Still Pending
end
end
alt Timeout Exceeded
API->>DB: Update Status: EXPIRED
API->>Client: Payment Timeout
Client->>User: Show Error + Retry Option
end
sequenceDiagram
participant Admin
participant Client
participant API
participant Auth
participant DB
participant Services
Admin->>Client: Access Admin Panel
Client->>API: GET /api/admin/dashboard
API->>Auth: Verify Admin Role
Note over API,Auth: Check JWT for admin claim
alt Not Admin
Auth->>API: Unauthorized
API->>Client: 403 Forbidden
Client->>Admin: Access Denied
else Is Admin
Auth->>API: Authorized
API->>DB: Query Statistics
Note over API,DB: Total Users, Active Services<br/>Revenue, System Health
DB->>API: Return Aggregated Data
API->>Client: Return Dashboard Data
Client->>Admin: Display Dashboard
Admin->>Client: View User Management
Client->>API: GET /api/admin/users
API->>DB: Query Users (Paginated)
DB->>API: Return User List
Note over DB,API: UUID, Created Date<br/>Active Services, Last Login
API->>Client: Return Users
Client->>Admin: Display User List
Admin->>Client: Manage Service
Client->>API: POST /api/admin/service/action
API->>Services: Execute Action
Services->>DB: Update Service Status
DB->>Services: Success
Services->>API: Action Complete
API->>Client: 200 OK
Client->>Admin: Show Success Message
end
Features & Benefits:
- App Router: Modern routing with React Server Components
- Server-Side Rendering (SSR): Dynamic content with SEO optimization
- Static Site Generation (SSG): Pre-rendered pages for maximum performance
- Incremental Static Regeneration (ISR): Update static content without full rebuild
- API Routes: Built-in serverless API endpoints
- Image Optimization: Automatic image optimization and lazy loading via next/image
- Font Optimization: Automatic web font optimization with next/font
- Edge Middleware: Authentication, redirects, and A/B testing at the edge
- Streaming: Progressive rendering with React Suspense
- Code Splitting: Automatic code splitting for optimal bundle size
Project Structure:
app/
├── layout.tsx - Root layout with providers
├── page.tsx - Homepage (landing page)
├── not-found.tsx - 404 error page
├── globals.css - Global styles
├── about/ - About page
├── contact/ - Contact page
├── products/ - Product pages
│ ├── esims/
│ ├── cards/
│ ├── emails/
│ └── proxy/
├── pricing/ - Pricing page
├── support/ - Support page
├── privacy/ - Privacy policy
├── terms/ - Terms of service
└── cookies/ - Cookie policy
Advanced Features:
- Concurrent Rendering: Non-blocking UI updates
- Server Components: Zero JavaScript for static content
- Suspense Boundaries: Granular loading states
- Automatic Batching: Optimized state updates
- Transitions: Smooth UI updates with useTransition
- Error Boundaries: Graceful error handling
Component Patterns:
"use client";
import { useState, useTransition } from 'react';
export function ServicePurchase() {
const [isPending, startTransition] = useTransition();
const [service, setService] = useState(null);
const handlePurchase = () => {
startTransition(async () => {
const result = await fetch('/api/purchase', {
method: 'POST',
body: JSON.stringify({ serviceId: 'esim-1gb' }),
});
setService(await result.json());
});
};
return (
<button onClick={handlePurchase} disabled={isPending}>
{isPending ? 'Processing...' : 'Purchase'}
</button>
);
}Configuration (tsconfig.json):
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowJs": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"],
"@/components/*": ["./components/*"],
"@/lib/*": ["./lib/*"],
"@/constants/*": ["./constants/*"],
"@/app/*": ["./app/*"],
"@/public/*": ["./public/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}Type Definitions:
export interface User {
id: string;
username: string;
createdAt: number;
services: UserService[];
}
export interface UserService {
id: string;
type: 'esim' | 'card' | 'email' | 'vpn' | 'voice';
status: 'active' | 'suspended' | 'expired';
expiresAt: number;
metadata: Record<string, unknown>;
}
export interface PurchaseRequest {
serviceType: string;
planId: string;
paymentMethod: 'sol' | 'btc' | 'eth';
}
export interface PaymentResponse {
paymentId: string;
address: string;
amount: number;
currency: string;
expiresAt: number;
qrCode: string;
}Full Configuration (tailwind.config.ts):
import type { Config } from 'tailwindcss';
const config: Config = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
color: {
1: '#AC6AFF',
2: '#FFC876',
3: '#FF776F',
4: '#7ADB78',
5: '#858DFF',
6: '#FF98E2',
},
stroke: {
1: '#26242C',
},
n: {
1: '#FFFFFF',
2: '#CAC6DD',
3: '#ADA8C3',
4: '#757185',
5: '#3F3A52',
6: '#252134',
7: '#15131D',
8: '#0E0C15',
9: '#474060',
10: '#43435C',
11: '#1B1B2E',
12: '#2E2A41',
13: '#6C7275',
},
},
fontFamily: {
sans: ['var(--font-sora)', 'sans-serif'],
code: ['var(--font-code)', 'monospace'],
inter: ['var(--font-inter)', 'sans-serif'],
},
spacing: {
0.25: '0.0625rem',
7.5: '1.875rem',
15: '3.75rem',
},
opacity: {
15: '.15',
},
transitionDuration: {
DEFAULT: '200ms',
},
transitionTimingFunction: {
DEFAULT: 'linear',
},
zIndex: {
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
},
borderWidth: {
DEFAULT: '0.0625rem',
},
backgroundImage: {
'radial-gradient': 'radial-gradient(var(--tw-gradient-stops))',
'conic-gradient':
'conic-gradient(from 225deg, #FFC876, #79FFF7, #9F53FF, #FF98E2, #FFC876)',
'benefit-card-1': 'url(/assets/benefits/card-1.svg)',
'benefit-card-2': 'url(/assets/benefits/card-2.svg)',
'benefit-card-3': 'url(/assets/benefits/card-3.svg)',
'benefit-card-4': 'url(/assets/benefits/card-4.svg)',
'benefit-card-5': 'url(/assets/benefits/card-5.svg)',
'benefit-card-6': 'url(/assets/benefits/card-6.svg)',
},
boxShadow: {
'glow': '0 0 20px rgba(172, 106, 255, 0.5)',
'glow-lg': '0 0 40px rgba(172, 106, 255, 0.6)',
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('tailwindcss-animate'),
],
};
export default config;Usage Examples:
<div className="bg-n-8 rounded-2xl border border-n-6">
<h2 className="text-n-1 font-bold text-2xl">Privacy First</h2>
<p className="text-n-3 text-base">Your data, your control</p>
<button className="bg-color-1 hover:bg-color-1/90 text-n-1 px-6 py-3 rounded-xl transition-all">
Get Started
</button>
</div>Installation:
npm install gsapImplementation Examples:
"use client";
import { useEffect, useRef } from 'react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
export function AnimatedHero() {
const heroRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const ctx = gsap.context(() => {
gsap.from('.hero-title', {
opacity: 0,
y: 100,
duration: 1,
ease: 'power3.out',
});
gsap.from('.hero-subtitle', {
opacity: 0,
y: 50,
duration: 1,
delay: 0.3,
ease: 'power3.out',
});
gsap.from('.hero-cta', {
opacity: 0,
scale: 0.8,
duration: 0.8,
delay: 0.6,
ease: 'back.out(1.7)',
});
}, heroRef);
return () => ctx.revert();
}, []);
return (
<div ref={heroRef}>
<h1 className="hero-title">Erypt-Web</h1>
<p className="hero-subtitle">Privacy-First Digital Services</p>
<button className="hero-cta">Get Started</button>
</div>
);
}Scroll-Triggered Animations:
useEffect(() => {
const features = gsap.utils.toArray('.feature-card');
features.forEach((feature: any) => {
gsap.from(feature, {
scrollTrigger: {
trigger: feature,
start: 'top 80%',
end: 'top 50%',
scrub: 1,
markers: false,
},
opacity: 0,
y: 100,
scale: 0.9,
});
});
}, []);Parallax Effects:
gsap.to('.background-gradient', {
scrollTrigger: {
trigger: '.section',
start: 'top top',
end: 'bottom top',
scrub: true,
},
y: (i, target) => -ScrollTrigger.maxScroll(window) * 0.5,
ease: 'none',
});Installation & Setup:
npm install @studio-freight/lenisImplementation:
"use client";
import { ReactNode, useEffect } from 'react';
import Lenis from '@studio-freight/lenis';
export function SmoothScrollProvider({ children }: { children: ReactNode }) {
useEffect(() => {
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
direction: 'vertical',
gestureDirection: 'vertical',
smooth: true,
mouseMultiplier: 1,
smoothTouch: false,
touchMultiplier: 2,
infinite: false,
});
function raf(time: number) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
return () => {
lenis.destroy();
};
}, []);
return <>{children}</>;
}Privacy-Friendly Bot Protection:
import { Turnstile } from '@marsidev/react-turnstile';
export function RegistrationForm() {
const [token, setToken] = useState<string>('');
const handleSubmit = async () => {
const response = await fetch('/api/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username,
password,
turnstileToken: token,
}),
});
};
return (
<form onSubmit={handleSubmit}>
<input type="text" name="username" />
<input type="password" name="password" />
<Turnstile
siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}
onSuccess={setToken}
/>
<button type="submit">Register</button>
</form>
);
}Server-Side Verification:
export async function POST(request: Request) {
const { username, password, turnstileToken } = await request.json();
const verifyResponse = await fetch(
'https://challenges.cloudflare.com/turnstile/v0/siteverify',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: process.env.TURNSTILE_SECRET_KEY,
response: turnstileToken,
}),
}
);
const verifyData = await verifyResponse.json();
if (!verifyData.success) {
return Response.json({ error: 'Invalid captcha' }, { status: 403 });
}
}Client-Side Hashing:
import bcrypt from 'bcryptjs';
export async function hashPassword(password: string): Promise<string> {
const salt = await bcrypt.genSalt(12);
const hash = await bcrypt.hash(password, salt);
return hash;
}
export async function verifyPassword(
password: string,
hash: string
): Promise<boolean> {
return await bcrypt.compare(password, hash);
}Token Generation:
import jwt from 'jsonwebtoken';
interface TokenPayload {
userId: string;
username: string;
role: 'user' | 'admin';
}
export function generateToken(payload: TokenPayload): string {
return jwt.sign(payload, process.env.JWT_SECRET!, {
expiresIn: '7d',
algorithm: 'HS256',
});
}
export function verifyToken(token: string): TokenPayload | null {
try {
return jwt.verify(token, process.env.JWT_SECRET!) as TokenPayload;
} catch {
return null;
}
}Cookie Management:
import { cookies } from 'next/headers';
export function setAuthCookie(token: string) {
cookies().set('auth_token', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 60 * 60 * 24 * 7,
path: '/',
});
}
export function getAuthToken(): string | undefined {
return cookies().get('auth_token')?.value;
}
export function clearAuthCookie() {
cookies().delete('auth_token');
}Setup:
"use client";
import { useEffect } from 'react';
export function CrispChat() {
useEffect(() => {
window.$crisp = [];
window.CRISP_WEBSITE_ID = process.env.NEXT_PUBLIC_CRISP_WEBSITE_ID;
const script = document.createElement('script');
script.src = 'https://client.crisp.chat/l.js';
script.async = true;
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
};
}, []);
return null;
}erypt-web/
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Homepage / Landing page
│ ├── globals.css # Global styles and Tailwind directives
│ ├── not-found.tsx # Custom 404 page
│ ├── favicon.ico # Site favicon
│ ├── about/ # About page
│ │ └── page.tsx
│ ├── app/ # App-specific routes
│ │ └── page.tsx
│ ├── contact/ # Contact page
│ │ └── page.tsx
│ ├── cookies/ # Cookie policy
│ │ └── page.tsx
│ ├── esims/ # eSIM service page
│ │ └── page.tsx
│ ├── pricing/ # Pricing page
│ │ └── page.tsx
│ ├── privacy/ # Privacy policy
│ │ └── page.tsx
│ ├── products/ # Product pages
│ │ ├── cards/ # Virtual cards
│ │ │ └── page.tsx
│ │ ├── emails/ # Private email
│ │ │ └── page.tsx
│ │ ├── esims/ # eSIM details
│ │ │ └── page.tsx
│ │ └── proxy/ # VPN/Proxy
│ │ └── page.tsx
│ ├── support/ # Support page
│ │ └── page.tsx
│ ├── terms/ # Terms of service
│ │ └── page.tsx
│ ├── topup/ # Top-up page
│ │ └── page.tsx
│ └── voice-calling/ # Voice calling service
│ └── page.tsx
├── components/ # React components
│ ├── atoms/ # Atomic design: smallest components
│ │ ├── animated-button.tsx # Button with animation
│ │ ├── button.tsx # Base button component
│ │ ├── generating.tsx # Loading/generating indicator
│ │ ├── heading.tsx # Typography heading
│ │ └── tag-line.tsx # Subtitle/tagline component
│ ├── design/ # Design system components
│ │ ├── benefits.tsx # Benefits section component
│ │ ├── collaboration.tsx # Collaboration section
│ │ ├── hero.tsx # Hero section
│ │ ├── navbar.tsx # Navigation bar
│ │ ├── pricing.tsx # Pricing component
│ │ ├── roadmap.tsx # Roadmap timeline
│ │ └── services.tsx # Services showcase
│ ├── layout/ # Layout components
│ │ ├── bottom-navbar.tsx # Mobile bottom navigation
│ │ ├── footer.tsx # Site footer
│ │ ├── navbar.tsx # Main navigation
│ │ └── section.tsx # Section wrapper
│ ├── providers/ # Context providers
│ │ └── smooth-scroll-provider.tsx # Lenis smooth scroll
│ ├── sections/ # Page sections
│ │ ├── benefits/ # Benefits section
│ │ │ └── index.tsx
│ │ ├── collaboration/ # Collaboration section
│ │ │ └── index.tsx
│ │ ├── features/ # Features section
│ │ │ └── scrolling-features.tsx
│ │ ├── hero/ # Hero section
│ │ │ ├── company-logos.tsx # Partner logos
│ │ │ ├── hero-lite.tsx # Lightweight hero
│ │ │ ├── index.tsx # Main hero
│ │ │ └── notification.tsx # Notification component
│ │ ├── pricing/ # Pricing section
│ │ │ ├── index.tsx
│ │ │ └── pricing-list.tsx # Pricing cards
│ │ ├── roadmap/ # Roadmap section
│ │ │ └── index.tsx
│ │ └── services/ # Services section
│ │ └── index.tsx
│ ├── support/ # Support components
│ │ ├── crisp-chat.tsx # Crisp live chat
│ │ └── live-chat-bubble.tsx # Chat bubble UI
│ ├── svg/ # SVG components
│ │ ├── arrow.tsx # Arrow icon
│ │ ├── brackets.tsx # Bracket decorations
│ │ ├── button-svg.tsx # Button decorations
│ │ ├── chat-bubble-wing.tsx # Chat bubble decoration
│ │ ├── clip-path.tsx # Clip path utilities
│ │ ├── erypt-logo.tsx # Erypt logo
│ │ ├── lightning-logo.tsx # Lightning icon
│ │ ├── menu-svg.tsx # Menu icon
│ │ ├── modern-logo.tsx # Modern logo variant
│ │ ├── phone-mockup.tsx # Phone mockup
│ │ ├── plus-svg.tsx # Plus icon
│ │ └── section-svg.tsx # Section decorations
│ └── ui/ # UI utilities
│ └── scroll-to-top.tsx # Scroll to top button
├── constants/ # Constants and data
│ └── index.ts # Centralized constants
├── lib/ # Utility libraries
│ └── utils.ts # Helper functions (cn, etc.)
├── public/ # Static assets
│ ├── next.svg # Next.js logo
│ ├── vercel.svg # Vercel logo
│ └── assets/ # Image assets
│ ├── 4-small.png
│ ├── background.jpg
│ ├── check-02.svg
│ ├── check.svg
│ ├── chrome-cast.svg
│ ├── disc-02.svg
│ ├── erypt-symbol-white.svg # White logo
│ ├── erypt-symbol.svg # Main logo
│ ├── esim-phone.png
│ ├── file-02.svg
│ ├── gradient.png
│ ├── grid.png
│ ├── hero-phone.png
│ ├── home-smile.svg
│ ├── loading-01.svg
│ ├── loading.png
│ ├── play.svg
│ ├── plus-square.svg
│ ├── recording-01.svg
│ ├── recording-03.svg
│ ├── search-md.svg
│ ├── sliders-04.svg
│ ├── telefon-logo.svg
│ ├── benefits/ # Benefit images
│ ├── collaboration/ # Collaboration images
│ ├── hero/ # Hero images
│ ├── notification/ # Notification images
│ ├── pricing/ # Pricing images
│ ├── roadmap/ # Roadmap images
│ ├── services/ # Service images
│ └── socials/ # Social media icons
├── middleware.ts # Next.js middleware
├── next.config.mjs # Next.js configuration
├── next-env.d.ts # Next.js TypeScript declarations
├── package.json # Dependencies and scripts
├── postcss.config.mjs # PostCSS configuration
├── tailwind.config.ts # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── .gitignore # Git ignore rules
├── LICENSE # MIT License
├── README.md # This file
├── SUBDOMAIN_SETUP.md # Subdomain deployment guide
├── deploy-subdomains.sh # Deployment script
└── dns-config-xyz.txt # DNS configuration example
app/layout.tsx - Root Layout
import { SmoothScrollProvider } from '@/components/providers/smooth-scroll-provider';
import { CrispChat } from '@/components/support/crisp-chat';
import './globals.css';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<SmoothScrollProvider>
{children}
<CrispChat />
</SmoothScrollProvider>
</body>
</html>
);
}middleware.ts - Edge Middleware
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth_token');
const { pathname } = request.nextUrl;
if (pathname.startsWith('/dashboard') && !token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*'],
};constants/index.ts - Application Constants
export const SITE_NAME = 'Erypt-Web';
export const SITE_DESCRIPTION = 'Privacy-First Digital Services Platform';
export const SERVICES = [
{
id: 'esim',
name: 'Anonymous eSIM',
description: 'Global cellular connectivity without identity verification',
icon: '📱',
url: '/products/esims',
},
{
id: 'cards',
name: 'Virtual Cards',
description: 'Anonymous payment cards funded with cryptocurrency',
icon: '💳',
url: '/products/cards',
},
{
id: 'email',
name: 'Private Email',
description: 'End-to-end encrypted email with zero-knowledge architecture',
icon: '📧',
url: '/products/emails',
},
{
id: 'vpn',
name: 'VPN/Proxy',
description: 'Anonymous browsing with audited no-log policy',
icon: '🔒',
url: '/products/proxy',
},
{
id: 'voice',
name: 'Voice Calling',
description: 'Encrypted calls with disposable phone numbers',
icon: '📞',
url: '/voice-calling',
},
];
export const FEATURES = [
'Zero-Knowledge Infrastructure',
'Anonymous Authentication',
'End-to-End Encryption',
'No Tracking or Analytics',
'Cryptocurrency Payments',
'Open Source',
];Ensure you have the following installed on your system:
Node.js >= 18.17.0
npm >= 9.0.0 (or yarn >= 1.22.0 or pnpm >= 8.0.0)
Git >= 2.30.0Check your versions:
node --version
npm --version
git --versiongit clone https://github.com/7ttp/erypt-web.git
cd erypt-webOr if you prefer SSH:
git clone [email protected]:7ttp/erypt-web.git
cd erypt-webUsing npm:
npm installUsing yarn:
yarn installUsing pnpm (recommended for speed):
pnpm installDependencies installed:
{
"dependencies": {
"next": "15.5.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"gsap": "^3.12.5",
"@studio-freight/lenis": "^1.0.42",
"@marsidev/react-turnstile": "^1.0.2",
"bcryptjs": "^2.4.3",
"jsonwebtoken": "^9.0.2",
"clsx": "^2.1.1",
"tailwind-merge": "^2.5.5"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@types/bcryptjs": "^2.4.6",
"@types/jsonwebtoken": "^9.0.6",
"tailwindcss": "^3.4.1",
"postcss": "^8.4.35",
"autoprefixer": "^10.4.17",
"eslint": "^8.0.0",
"eslint-config-next": "15.5.2"
}
}Create a .env.local file in the root directory:
cp .env.example .env.localRequired Environment Variables:
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_TURNSTILE_SITE_KEY=your_turnstile_site_key
TURNSTILE_SECRET_KEY=your_turnstile_secret_key
JWT_SECRET=your_super_secret_jwt_key_min_32_chars
NEXT_PUBLIC_CRISP_WEBSITE_ID=your_crisp_website_id
DATABASE_URL=postgresql://user:password@localhost:5432/erypt
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
SOLANA_PRIVATE_KEY=your_solana_private_key
ENCRYPTION_KEY=your_32_byte_encryption_key
NODE_ENV=developmentGenerate secure keys:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"npm run devThe application will be available at:
Development features:
- Hot Module Replacement (HMR)
- Fast Refresh for instant updates
- Error overlay for debugging
- Automatic TypeScript checking
npm run buildThis will:
- Type-check all TypeScript files
- Compile and optimize JavaScript bundles
- Generate static pages (SSG)
- Optimize images
- Create production build in
.next/directory
Build output:
Route (app) Size First Load JS
┌ ○ / 8.2 kB 95 kB
├ ○ /about 2.1 kB 89 kB
├ ○ /contact 1.8 kB 88 kB
├ ○ /pricing 5.4 kB 92 kB
├ ○ /products/esims 4.2 kB 91 kB
└ ○ /products/cards 3.9 kB 90 kB
○ (Static) prerendered as static content
npm run startServer runs on http://localhost:3000
- Create a new branch:
git checkout -b feature/your-feature-name-
Make your changes
-
Test locally:
npm run dev- Type-check:
npm run type-check- Lint code:
npm run lint- Build:
npm run build- Commit changes:
git add .
git commit -m "feat: add your feature"- Push to GitHub:
git push origin feature/your-feature-name{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"type-check": "tsc --noEmit",
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,css,md}\"",
"clean": "rm -rf .next node_modules",
"analyze": "ANALYZE=true next build"
}
}Atomic Component (Button):
// components/atoms/custom-button.tsx
interface CustomButtonProps {
children: React.ReactNode;
variant?: 'primary' | 'secondary';
onClick?: () => void;
}
export function CustomButton({
children,
variant = 'primary',
onClick
}: CustomButtonProps) {
return (
<button
onClick={onClick}
className={`px-6 py-3 rounded-xl transition-all ${
variant === 'primary'
? 'bg-color-1 hover:bg-color-1/90'
: 'bg-n-6 hover:bg-n-5'
}`}
>
{children}
</button>
);
}Page Component:
// app/new-page/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'New Page | Erypt-Web',
description: 'Description of the new page',
};
export default function NewPage() {
return (
<div className="container mx-auto px-4">
<h1 className="text-4xl font-bold text-n-1">New Page</h1>
<p className="text-n-3">Content goes here</p>
</div>
);
}Next.js uses file-based routing. Create a new folder in app/:
app/
└── new-route/
├── page.tsx # Main page component
├── layout.tsx # Optional layout
└── loading.tsx # Optional loading state
Use Tailwind utility classes:
<div className="bg-n-8 rounded-2xl border border-n-6 p-6">
<h2 className="text-n-1 font-bold text-2xl mb-4">Title</h2>
<p className="text-n-3 text-base leading-relaxed">Content</p>
</div>Responsive design:
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* Cards */}
</div>Dark mode support:
<div className="bg-white dark:bg-n-8 text-gray-900 dark:text-n-1">
Content
</div>Fade in on scroll:
useEffect(() => {
gsap.from('.animate-in', {
scrollTrigger: {
trigger: '.animate-in',
start: 'top 80%',
},
opacity: 0,
y: 50,
duration: 1,
});
}, []);Stagger animation:
useEffect(() => {
gsap.from('.stagger-item', {
opacity: 0,
y: 30,
stagger: 0.1,
duration: 0.8,
});
}, []);Register a new user with anonymous credentials.
Request:
POST /api/auth/register
Content-Type: application/json
{
"username": "anonymous_user_123",
"password": "hashed_password_bcrypt",
"turnstileToken": "cloudflare_turnstile_token"
}Response (Success):
{
"success": true,
"user": {
"id": "uuid-v4",
"username": "anonymous_user_123",
"createdAt": 1699401600000
},
"token": "jwt_token_here"
}Response (Error):
{
"success": false,
"error": "Username already exists"
}Authenticate existing user.
Request:
POST /api/auth/login
Content-Type: application/json
{
"username": "anonymous_user_123",
"password": "hashed_password_bcrypt"
}Response:
{
"success": true,
"user": {
"id": "uuid-v4",
"username": "anonymous_user_123",
"services": []
},
"token": "jwt_token_here"
}Logout current user and clear session.
Request:
POST /api/auth/logout
Cookie: auth_token=jwt_tokenResponse:
{
"success": true,
"message": "Logged out successfully"
}Get available eSIM plans.
Response:
{
"plans": [
{
"id": "esim_usa_1gb_7d",
"name": "USA 1GB - 7 Days",
"region": "North America",
"countries": ["USA", "Canada", "Mexico"],
"data": "1GB",
"duration": 7,
"price": {
"usd": 15,
"sol": 0.15,
"btc": 0.00035
}
}
]
}Initiate a service purchase.
Request:
POST /api/purchase/initiate
Authorization: Bearer jwt_token
Content-Type: application/json
{
"serviceType": "esim",
"planId": "esim_usa_1gb_7d",
"paymentMethod": "sol"
}Response:
{
"purchaseId": "purchase_uuid",
"payment": {
"address": "solana_address",
"amount": 0.15,
"currency": "SOL",
"qrCode": "data:image/png;base64,...",
"expiresAt": 1699403400000
},
"status": "pending"
}Check payment status.
Response:
{
"purchaseId": "purchase_uuid",
"status": "confirmed",
"service": {
"type": "esim",
"qrCode": "data:image/png;base64,...",
"activationCode": "LPA:1$...",
"expiresAt": 1700006200000
}
}Verify cryptocurrency payment.
Request:
POST /api/payment/verify
Content-Type: application/json
{
"purchaseId": "purchase_uuid",
"txHash": "transaction_hash"
}Response:
{
"verified": true,
"amount": 0.15,
"confirmations": 15,
"status": "confirmed"
}Data at Rest:
- Algorithm: AES-256-GCM
- Key Derivation: PBKDF2 with 100,000 iterations
- Salt: Random 32-byte salt per user
- IV: Random 16-byte initialization vector per message
Implementation:
import crypto from 'crypto';
export function encrypt(plaintext: string, password: string): EncryptedData {
const salt = crypto.randomBytes(32);
const key = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const encrypted = Buffer.concat([
cipher.update(plaintext, 'utf8'),
cipher.final(),
]);
const tag = cipher.getAuthTag();
return {
ciphertext: encrypted.toString('base64'),
iv: iv.toString('base64'),
salt: salt.toString('base64'),
tag: tag.toString('base64'),
};
}
export function decrypt(data: EncryptedData, password: string): string {
const key = crypto.pbkdf2Sync(
password,
Buffer.from(data.salt, 'base64'),
100000,
32,
'sha256'
);
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key,
Buffer.from(data.iv, 'base64')
);
decipher.setAuthTag(Buffer.from(data.tag, 'base64'));
const decrypted = Buffer.concat([
decipher.update(Buffer.from(data.ciphertext, 'base64')),
decipher.final(),
]);
return decrypted.toString('utf8');
}Data in Transit:
- Protocol: TLS 1.3
- Cipher Suites:
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- HSTS: Enabled with 1-year max-age
- Certificate: Let's Encrypt with automatic renewal
Hashing:
- Algorithm: bcrypt
- Cost Factor: 12 rounds (2^12 iterations)
- Salt: Automatically generated per password
import bcrypt from 'bcryptjs';
export async function hashPassword(password: string): Promise<string> {
const salt = await bcrypt.genSalt(12);
return await bcrypt.hash(password, salt);
}
export async function verifyPassword(
password: string,
hash: string
): Promise<boolean> {
return await bcrypt.compare(password, hash);
}Password Requirements:
- Minimum 12 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character
- No common passwords (checked against list)
JWT Configuration:
{
algorithm: 'HS256',
expiresIn: '7d',
issuer: 'erypt-web',
audience: 'erypt-users'
}Cookie Security:
{
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 604800000,
path: '/',
domain: '.erypt.com'
}Zod Schema Example:
import { z } from 'zod';
export const RegisterSchema = z.object({
username: z
.string()
.min(3, 'Username must be at least 3 characters')
.max(20, 'Username must be at most 20 characters')
.regex(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores'),
password: z
.string()
.min(12, 'Password must be at least 12 characters')
.regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
.regex(/[a-z]/, 'Password must contain at least one lowercase letter')
.regex(/[0-9]/, 'Password must contain at least one number')
.regex(/[^A-Za-z0-9]/, 'Password must contain at least one special character'),
turnstileToken: z.string().min(1, 'Captcha verification required'),
});Implementation:
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'),
});
export async function checkRateLimit(identifier: string): Promise<boolean> {
const { success } = await ratelimit.limit(identifier);
return success;
}Rate Limits:
- Authentication: 10 requests per 10 seconds
- API Calls: 100 requests per minute
- Payment Creation: 5 requests per minute
- Registration: 3 requests per hour per IP
const corsOptions = {
origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400,
};Dynamic Imports:
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('@/components/heavy-component'), {
loading: () => <div>Loading...</div>,
ssr: false,
});Route-Based Splitting: Next.js automatically splits code by route. Each page only loads its required JavaScript.
Using next/image:
import Image from 'next/image';
<Image
src="/assets/hero-phone.png"
alt="Hero Phone"
width={800}
height={600}
priority
quality={85}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>Optimization Features:
- Automatic WebP/AVIF conversion
- Responsive images with srcset
- Lazy loading by default
- Blur-up placeholders
- CDN delivery via Vercel
import { Inter, Sora } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
});
const sora = Sora({
subsets: ['latin'],
weight: ['400', '600', '700'],
display: 'swap',
variable: '--font-sora',
});
export { inter, sora };Run bundle analyzer:
ANALYZE=true npm run buildOptimization Targets:
- First Contentful Paint (FCP): < 1.8s
- Largest Contentful Paint (LCP): < 2.5s
- Time to Interactive (TTI): < 3.9s
- Total Blocking Time (TBT): < 300ms
- Cumulative Layout Shift (CLS): < 0.1
Static Assets:
Cache-Control: public, max-age=31536000, immutable
API Responses:
export async function GET() {
return Response.json(data, {
headers: {
'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=30',
},
});
}ISR (Incremental Static Regeneration):
export const revalidate = 3600;
export async function generateStaticParams() {
return [{ slug: 'esims' }, { slug: 'cards' }, { slug: 'email' }];
}Setup:
npm install --save-dev jest @testing-library/react @testing-library/jest-domjest.config.js:
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
},
};Example Test:
import { render, screen } from '@testing-library/react';
import { Button } from '@/components/atoms/button';
describe('Button Component', () => {
it('renders with correct text', () => {
render(<Button>Click Me</Button>);
expect(screen.getByText('Click Me')).toBeInTheDocument();
});
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click Me</Button>);
screen.getByText('Click Me').click();
expect(handleClick).toHaveBeenCalledTimes(1);
});
});API Route Testing:
import { POST } from '@/app/api/auth/register/route';
describe('Registration API', () => {
it('creates new user successfully', async () => {
const request = new Request('http://localhost:3000/api/auth/register', {
method: 'POST',
body: JSON.stringify({
username: 'testuser',
password: 'hashedpassword',
turnstileToken: 'valid_token',
}),
});
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(200);
expect(data.success).toBe(true);
expect(data.user).toHaveProperty('id');
});
});Installation:
npm install --save-dev @playwright/testExample Test:
import { test, expect } from '@playwright/test';
test('complete registration flow', async ({ page }) => {
await page.goto('http://localhost:3000');
await page.click('text=Sign Up');
await page.fill('input[name="username"]', 'testuser');
await page.fill('input[name="password"]', 'SecurePass123!');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toContainText('Welcome');
});Step 1: Install Vercel CLI
npm install -g vercelStep 2: Login to Vercel
vercel loginStep 3: Deploy
vercel --prodEnvironment Variables:
Add all variables from .env.local to Vercel dashboard:
- Project Settings → Environment Variables
vercel.json Configuration:
{
"buildCommand": "npm run build",
"devCommand": "npm run dev",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"],
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "Strict-Transport-Security",
"value": "max-age=31536000; includeSubDomains"
}
]
}
]
}Dockerfile:
FROM node:20-alpine AS base
FROM base AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- JWT_SECRET=${JWT_SECRET}
- DATABASE_URL=${DATABASE_URL}
restart: unless-stopped
networks:
- erypt-network
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
networks:
- erypt-network
networks:
erypt-network:
driver: bridgeBuild and Run:
docker-compose up -dStep 1: Install Dependencies
sudo apt update
sudo apt install nodejs npm nginx certbot python3-certbot-nginxStep 2: Clone and Build
git clone https://github.com/7ttp/erypt-web.git
cd erypt-web
npm install
npm run buildStep 3: Configure Nginx
server {
listen 80;
server_name erypt.com www.erypt.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name erypt.com www.erypt.com;
ssl_certificate /etc/letsencrypt/live/erypt.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/erypt.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}Step 4: Setup SSL
sudo certbot --nginx -d erypt.com -d www.erypt.comStep 5: Start Application
npm run startOptional: PM2 for Process Management
npm install -g pm2
pm2 start npm --name "erypt-web" -- start
pm2 save
pm2 startupNODE_ENV=development
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_TURNSTILE_SITE_KEY=1x00000000000000000000AA
TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA
JWT_SECRET=dev_secret_key_min_32_characters_long
NEXT_PUBLIC_CRISP_WEBSITE_ID=your_crisp_id
DATABASE_URL=postgresql://user:pass@localhost:5432/erypt_dev
SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_PRIVATE_KEY=your_dev_wallet_private_key
ENCRYPTION_KEY=dev_encryption_key_32_bytes_long
NEXT_PUBLIC_ENABLE_ANALYTICS=falseNODE_ENV=production
NEXT_PUBLIC_APP_URL=https://erypt.com
NEXT_PUBLIC_TURNSTILE_SITE_KEY=your_production_site_key
TURNSTILE_SECRET_KEY=your_production_secret_key
JWT_SECRET=production_secret_min_32_chars_random
NEXT_PUBLIC_CRISP_WEBSITE_ID=your_crisp_id
DATABASE_URL=postgresql://user:pass@prod-db:5432/erypt_prod
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
SOLANA_PRIVATE_KEY=your_production_wallet_key
ENCRYPTION_KEY=production_key_32_bytes_random
NEXT_PUBLIC_ENABLE_ANALYTICS=falseError:
Error: listen EADDRINUSE: address already in use :::3000
Solution:
lsof -ti:3000 | xargs kill -9
netstat -ano | findstr :3000
taskkill /PID <process_id> /FOr use a different port:
PORT=3001 npm run devError:
Module not found: Can't resolve '@/components/...'
Solution:
- Check
tsconfig.jsonpaths configuration - Restart TypeScript server:
Ctrl+Shift+P→ "TypeScript: Restart TS Server" - Delete
.nextand rebuild:
rm -rf .next
npm run devProblem: Environment variables are undefined
Solution:
- Ensure
.env.localexists in root directory - Variables for client must start with
NEXT_PUBLIC_ - Restart development server after adding variables
- Check variable names don't have typos
console.log(process.env.NEXT_PUBLIC_APP_URL);Error:
Warning: Text content did not match. Server: "..." Client: "..."
Solution:
- Don't use browser-only APIs in server components
- Use
useEffectfor client-only rendering:
'use client';
import { useState, useEffect } from 'react';
export function ClientOnly({ children }: { children: React.ReactNode }) {
const [hasMounted, setHasMounted] = useState(false);
useEffect(() => {
setHasMounted(true);
}, []);
if (!hasMounted) {
return null;
}
return <>{children}</>;
}Problem: Animations don't trigger on scroll
Solution:
'use client';
import { useEffect } from 'react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
export function AnimatedComponent() {
useEffect(() => {
gsap.registerPlugin(ScrollTrigger);
ScrollTrigger.refresh();
const animation = gsap.from('.element', {
scrollTrigger: {
trigger: '.element',
start: 'top 80%',
},
opacity: 0,
y: 50,
});
return () => {
animation.kill();
ScrollTrigger.getAll().forEach(trigger => trigger.kill());
};
}, []);
return <div className="element">Content</div>;
}Error:
Type error: Property 'x' does not exist on type 'Y'
Solution:
- Fix type errors in code
- Or temporarily disable type checking in build:
module.exports = {
typescript: {
ignoreBuildErrors: true,
},
};Better approach - add proper types:
interface Props {
x: string;
y?: number;
}
export function Component({ x, y }: Props) {
}Problem: Images show broken icon
Solution:
- Check file path is correct (case-sensitive)
- Ensure images are in
public/directory - Use absolute paths:
/assets/image.png - Configure
next.config.mjsfor external images:
const nextConfig = {
images: {
domains: ['external-domain.com'],
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
},
],
},
};Problem: Tailwind classes not working
Solution:
- Check
tailwind.config.tscontent paths - Ensure
globals.cssimports Tailwind:
@tailwind base;
@tailwind components;
@tailwind utilities;- Clear Next.js cache:
rm -rf .next
npm run devProblem: /api/... returns 404
Solution:
- Ensure file is in
app/api/directory - File must be named
route.ts - Export named functions:
GET,POST, etc.
export async function GET(request: Request) {
return Response.json({ message: 'Hello' });
}Error:
Error: Command "npm run build" exited with 1
Solution:
- Check build logs for specific errors
- Ensure all environment variables are set in Vercel
- Test build locally:
npm run build - Check Node.js version matches:
{
"engines": {
"node": ">=18.17.0"
}
}Solutions:
- Enable static optimization
- Use dynamic imports for heavy components
- Optimize images with next/image
- Enable compression in production
- Use CDN for static assets
Solutions:
- Set explicit width/height for images
- Reserve space for dynamic content
- Use
aspect-ratioCSS - Avoid inserting content above existing content
<div className="aspect-video">
<Image src="..." fill className="object-cover" alt="..." />
</div>1. Component Structure
components/
├── atoms/ # Small, reusable components
├── molecules/ # Combinations of atoms
├── organisms/ # Complex components
├── templates/ # Page layouts
└── pages/ # Full page components
2. File Naming
- Components:
PascalCase.tsx - Utilities:
camelCase.ts - Constants:
SCREAMING_SNAKE_CASE.ts - Types:
PascalCase.types.ts
3. Import Order
import React from 'react';
import { useState, useEffect } from 'react';
import { ExternalLib } from 'external-lib';
import { InternalComponent } from '@/components';
import { utility } from '@/lib/utils';
import { CONSTANT } from '@/constants';
import type { CustomType } from './types';
import './styles.css';1. Define Proper Types
interface User {
id: string;
username: string;
createdAt: number;
}
type UserWithServices = User & {
services: Service[];
};
type ApiResponse<T> = {
success: boolean;
data?: T;
error?: string;
};2. Use Type Guards
function isUser(obj: unknown): obj is User {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'username' in obj
);
}3. Avoid any
function processData(data: unknown) {
if (typeof data === 'string') {
return data.toUpperCase();
}
if (typeof data === 'number') {
return data * 2;
}
throw new Error('Unsupported data type');
}1. Use Proper Hooks
'use client';
import { useState, useEffect, useCallback, useMemo } from 'react';
export function OptimizedComponent() {
const [data, setData] = useState<Data[]>([]);
const fetchData = useCallback(async () => {
const result = await api.fetch();
setData(result);
}, []);
const filteredData = useMemo(() => {
return data.filter(item => item.active);
}, [data]);
useEffect(() => {
fetchData();
}, [fetchData]);
return <div>{filteredData.map(...)}</div>;
}2. Proper Error Boundaries
'use client';
import { Component, ReactNode } from 'react';
interface Props {
children: ReactNode;
}
interface State {
hasError: boolean;
}
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error caught:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <div>Something went wrong.</div>;
}
return this.props.children;
}
}1. Input Sanitization
import DOMPurify from 'isomorphic-dompurify';
export function sanitizeHTML(dirty: string): string {
return DOMPurify.sanitize(dirty);
}
export function sanitizeInput(input: string): string {
return input
.trim()
.replace(/[<>]/g, '')
.substring(0, 1000);
}2. Rate Limiting
const rateLimits = new Map<string, number[]>();
export function checkRateLimit(ip: string, maxRequests: number, windowMs: number): boolean {
const now = Date.now();
const requests = rateLimits.get(ip) || [];
const recentRequests = requests.filter(time => now - time < windowMs);
if (recentRequests.length >= maxRequests) {
return false;
}
recentRequests.push(now);
rateLimits.set(ip, recentRequests);
return true;
}3. Secure API Routes
import { NextRequest } from 'next/server';
import { verify } from 'jsonwebtoken';
export async function authenticate(request: NextRequest) {
const token = request.cookies.get('auth_token')?.value;
if (!token) {
throw new Error('Unauthorized');
}
try {
const payload = verify(token, process.env.JWT_SECRET!);
return payload;
} catch {
throw new Error('Invalid token');
}
}
export async function POST(request: NextRequest) {
try {
const user = await authenticate(request);
} catch (error) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
}1. Code Splitting
import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('@/components/heavy-chart'), {
loading: () => <div>Loading chart...</div>,
ssr: false,
});2. Memoization
import { memo } from 'react';
export const ExpensiveComponent = memo(function ExpensiveComponent({ data }: Props) {
return <div>{data}</div>;
});3. Virtualization for Long Lists
npm install react-windowimport { FixedSizeList } from 'react-window';
export function VirtualList({ items }: { items: string[] }) {
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index]}</div>
)}
</FixedSizeList>
);
}We welcome contributions from the community! Here's how you can help:
1. Fork the Repository
gh repo fork 7ttp/erypt-web
git clone https://github.com/YOUR_USERNAME/erypt-web.git
cd erypt-web2. Create a Branch
git checkout -b feature/amazing-feature3. Make Your Changes
- Write clean, readable code
- Follow existing code style
- Add comments for complex logic
- Update documentation if needed
4. Test Your Changes
npm run dev
npm run build
npm run lint5. Commit Your Changes
git add .
git commit -m "feat: add amazing feature"Commit Message Convention:
feat:New featurefix:Bug fixdocs:Documentation changesstyle:Code style changes (formatting)refactor:Code refactoringperf:Performance improvementstest:Adding testschore:Maintenance tasks
6. Push to Your Fork
git push origin feature/amazing-feature7. Open a Pull Request
- Go to the original repository
- Click "New Pull Request"
- Select your fork and branch
- Describe your changes
- Submit the PR
Code Style:
- Use TypeScript for type safety
- Follow ESLint configuration
- Use Prettier for formatting
- Write meaningful variable names
- Add JSDoc comments for public APIs
Documentation:
- Update README if adding features
- Add inline comments for complex logic
- Update API documentation
- Include examples when possible
Testing:
- Write tests for new features
- Ensure all tests pass
- Maintain or improve coverage
Pull Request Guidelines:
- One feature per PR
- Clear description of changes
- Reference related issues
- Include screenshots for UI changes
- Ensure CI/CD passes
High Priority:
- Multi-language support (i18n)
- Additional payment methods
- Mobile app development
- API documentation expansion
- Performance optimizations
Features:
- Two-factor authentication (2FA)
- Account recovery system
- Referral program
- Service bundles
- Admin dashboard enhancements
Bug Fixes:
- Check open issues labeled
bug - Test edge cases
- Improve error handling
Documentation:
- Tutorial videos
- Code examples
- API references
- Troubleshooting guides
- Translations
Get Help:
- GitHub Discussions
- Discord Server (Coming Soon)
- Twitter: @7ttp
Code of Conduct:
- Be respectful and inclusive
- Provide constructive feedback
- Help others learn and grow
- Focus on what's best for the community
At Erypt-Web, privacy isn't just a feature—it's our foundation. We are committed to:
We Cannot Access Your Data:
- All sensitive data encrypted on your device before transmission
- Encryption keys derived from your password (never stored on our servers)
- Even if compelled by law, we cannot decrypt your data
We Don't Collect:
- Real names or personal information
- Email addresses (optional, encrypted if provided)
- Phone numbers
- Physical addresses
- Payment card details
- Government IDs
- Biometric data
We Only Store:
- Anonymous user ID (UUID)
- Hashed password (bcrypt)
- Encrypted service metadata
- Blockchain transaction IDs (public anyway)
We Don't Use:
- Google Analytics or similar services
- Tracking cookies
- Browser fingerprinting
- IP address logging (except temporary for DDoS protection)
- Third-party advertising networks
- Social media pixels
- Full source code available on GitHub
- Regular security audits
- Community code reviews
- Transparent security practices
Jurisdiction: Privacy-friendly jurisdiction Data Retention: Minimal (30-day logs for security only) Government Requests: Publish transparency report annually User Rights: Full data export and deletion on request
Cloudflare Turnstile:
- Privacy-friendly CAPTCHA alternative
- No Google reCAPTCHA tracking
- Minimal data collection
Crisp Chat:
- Optional support chat
- Can be disabled in settings
- Conversations encrypted
Cryptocurrency Payments:
- Blockchain-based (public by design)
- No KYC/AML requirements
- Maximum anonymity possible
Hosting:
- DDoS protection via Cloudflare
- Automatic SSL/TLS encryption
- Regular security patches
- Isolated environments
Database:
- Encrypted at rest (AES-256)
- Encrypted in transit (TLS 1.3)
- Regular automated backups
- Access control and monitoring
Authentication:
- bcrypt password hashing (12 rounds)
- JWT with HttpOnly cookies
- Session expiration (7 days)
- Optional 2FA (TOTP)
Authorization:
- Role-based access control
- Principle of least privilege
- Regular permission audits
Input Validation:
- Zod schema validation
- SQL injection prevention
- XSS protection
- CSRF tokens
Headers:
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
Referrer-Policy: no-referrer
Permissions-Policy: geolocation=(), microphone=(), camera=()
Rate Limiting:
- 100 requests per minute per IP
- Exponential backoff for failed auth
- DDoS protection
Standards:
- GDPR compliant (data minimization)
- CCPA compliant (California Privacy Rights)
- SOC 2 Type II (in progress)
- ISO 27001 (planned)
Audits:
- Annual third-party security audit
- Regular penetration testing
- Bug bounty program
- Responsible disclosure policy
In Case of Breach:
- Immediate notification to affected users
- Public disclosure within 72 hours
- Full transparency report
- Free credit monitoring (if applicable)
- Root cause analysis and remediation
- Launch MVP with eSIM service
- Implement Solana payments
- Deploy to production
- Add Bitcoin payment support
- Mobile-responsive design improvements
- Virtual Card service launch
- Private Email service beta
- Multi-language support (10+ languages)
- iOS mobile app
- Android mobile app
- VPN/Proxy service launch
- Voice calling service beta
- Referral program
- Service bundles
- API for developers
- Desktop applications (Windows, Mac, Linux)
- Enterprise features
- Custom domain email
- Advanced analytics dashboard
- White-label solutions
- Decentralized infrastructure
- DAO governance
- Token launch (optional)
- Peer-to-peer services
- Global expansion
This project is licensed under the MIT License.
MIT License
Copyright (c) 2025 @7ttp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
See LICENSE file for full details.
Built by:
- @7ttp - Creator & Lead Developer
Technologies:
- Next.js - React Framework
- React - UI Library
- Tailwind CSS - CSS Framework
- GSAP - Animation Library
- Solana - Blockchain Platform
- Cloudflare - Security & CDN
- Vercel - Hosting Platform
Inspiration: Privacy-focused services that respect user anonymity and digital rights.
Need Help?
- 📧 Email: [email protected]
- 💬 Live Chat: Available on website
- 🐛 Bug Reports: GitHub Issues
- 💡 Feature Requests: GitHub Discussions
Documentation:
If you find this project useful, please consider giving it a ⭐ on GitHub!