Technical Architecture
The QR Generator is built as a modern, client-side Progressive Web App using Vue 3 and Vite.
Technology Stack
Frontend Framework
- Vue 3.5+ with Composition API
- TypeScript for type safety
- Vite 5 for fast builds and HMR
- Vue Router for SPA navigation
UI & Styling
- Tailwind CSS 3 for utility-first styling
- Radix Vue for accessible components
- VueUse for composable utilities
- Dark mode support with system preference detection
QR Code Library
Custom fork of qr-code-styling with enhancements:
- Core:
qrcode-generatorlibrary - Rendering: Custom SVG renderer
- Styling: 6 dot styles, 4 corner styles
- Image overlay: Logo/image embedding
- Export: PNG, JPG, SVG, ASCII formats
Encryption
- Web Crypto API (native browser implementation)
- Algorithm: AES-GCM 256-bit
- Key Derivation: PBKDF2 with 100,000 iterations
- Zero dependencies: No external crypto libraries
PWA Features
- Vite PWA Plugin with Workbox
- Service Worker: Pre-caching and runtime caching
- Offline support: Full functionality offline after first visit
- Install prompts: Desktop and mobile app installation
Internationalization
- Vue I18n: Translation management
- 45+ languages: Including CJK, RTL, and emoji support
- Dynamic loading: Lazy-load language files
- Locale detection: Auto-detect user's preferred language
Architecture Patterns
Component Structure
App.vue (Root)
├── LanguageSelector.vue
├── MobileMenu.vue
└── Router
├── QRCodeCreate.vue (Main creation UI)
│ ├── StyledQRCode.vue (QR renderer)
│ ├── QRCodeFrame.vue (Frame overlay)
│ ├── DataTemplatesModal.vue (Templates)
│ ├── CopyImageModal.vue (Copy UI)
│ ├── TextExportModal.vue (ASCII export)
│ ├── BatchExportFieldsGuide.vue (CSV help)
│ └── ui/* (Reusable components)
│
└── QRCodeScan.vue (Scanning UI)
└── QRCodeCameraScanner.vue (Camera interface)
State Management
No Vuex/Pinia — Uses composition API with:
ref()andreactive()for local statecomputed()for derived statewatch()for side effectslocalStoragefor persistence- Event emitters for component communication
Data Flow
User Input → Vue Reactive State → QR Generation → Render to Canvas/SVG
↓
Display + Export
Key Modules
QR Code Generation (src/lib/qr-code/)
lib/qr-code/
├── core.ts # Main QR code instance & config
├── matrix.ts # Binary matrix generation
├── render/
│ ├── svg.ts # SVG rendering engine
│ └── canvas.ts # Canvas rasterization (PNG/JPG)
├── frame.ts # Frame overlay logic
├── types.ts # TypeScript type definitions
└── legacy-adapter.ts # Backward compatibility
Key functions:
createQRCode(config)— Main entry pointbuildMatrix(data, ecLevel)— Generate QR matrixrenderQrFragment()— Create SVG elementsrasterizeSvg()— Convert SVG to PNG/JPG
Encryption (src/utils/encryption.ts)
// Encrypt data with password
export async function encryptData(
data: string,
password: string
): Promise<string>
// Decrypt encrypted data
export async function decryptData(
encryptedData: string,
password: string
): Promise<string>
// Check if data is encrypted
export function isEncrypted(data: string): boolean
Presets (src/utils/qrCodePresets.ts)
Pre-configured style combinations:
- Color schemes
- Dot/corner styles
- Background colors
- Border radius
- Default logos
Built-in presets:
- Vercel Light/Dark
- Supabase Green/Purple
- VueJS
- Padlet
- UIlicious
- Scottsdale (custom)
- And more...
Data Encoding (src/utils/dataEncoding.ts)
Encode structured data types:
export const generateUrlData = (data: { url: string }): string
export const generateEmailData = (data: EmailData): string
export const generatePhoneData = (data: { phone: string }): string
export const generateSmsData = (data: SmsData): string
export const generateWifiData = (data: WifiData): string
export const generateVCardData = (data: VCardData): string
export const generateCalendarData = (data: CalendarData): string
export const generateLocationData = (data: LocationData): string
Batch Processing (src/utils/csvBatchProcessing.ts)
// Parse and validate CSV
export function processCsvDataForBatch(
csvData: CSVData[]
): BatchProcessingResult
// Generate unique filenames
export function generateBatchExportFilename(
dataString: string,
frameText: string,
customFileName: string,
index: number,
usedFilenames: Set<string>
): string
Build Process
Development
npm run dev
- Vite dev server on
http://localhost:5173 - Hot Module Replacement (HMR)
- TypeScript checking
- CSS preprocessing
Production Build
npm run build
Build outputs:
dist/
├── index.html # Entry point
├── manifest.webmanifest # PWA manifest
├── sw.js # Service worker
├── workbox-*.js # Workbox runtime
├── assets/
│ ├── index-[hash].js # Main JS bundle (~1.8MB)
│ ├── index-[hash].css # Compiled CSS (~86KB)
│ └── *.png/svg # Static assets
├── app_icons/ # PWA icons
├── batch_export_templates/ # CSV templates
└── presets/ # Preset logos
Optimizations:
- Code splitting (dynamic imports)
- Tree shaking (unused code removal)
- Minification (Terser)
- CSS purging (PurgeCSS via Tailwind)
- Asset optimization (images, fonts)
- Gzip compression (via .htaccess)
Deployment
Static Hosting
The app is fully static — no backend required.
Requirements:
- Web server (Apache, Nginx, Caddy, etc.)
- HTTPS (for camera access and PWA)
- URL rewriting for SPA routing
Hosted on:
- cPanel/Apache
- Domain: qr-generator.scottsdalemint.com
- Static files in
public_html/
.htaccess Configuration
# SPA routing - serve index.html for all routes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]
# Security headers
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
# Caching
<FilesMatch "\.(js|css|png|jpg|gif|svg|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
# Service worker - no cache
<Files "sw.js">
Header set Cache-Control "max-age=0, no-cache"
</Files>
Environment Variables
Build-time variables (via .env):
VITE_DEFAULT_DATA_TO_ENCODE=https://scottsdalemint.com
VITE_DEFAULT_PRESET=Default (lyqht)
Runtime: None required (all client-side)
Performance Characteristics
Bundle Size
| Asset | Uncompressed | Gzipped |
|---|---|---|
| JavaScript | ~1.8MB | ~670KB |
| CSS | ~86KB | ~13KB |
| Total (first load) | ~1.9MB | ~683KB |
Why large JS bundle?
- QR code generation library
- Image processing libraries
- QR scanning libraries (html5-qrcode, nimiq/qr-scanner)
- 45 language files
- PWA runtime
Mitigations:
- Lazy-load languages (only load active language)
- Service worker caching (loads once, cached forever)
- Offline-first (no subsequent network requests)
Load Performance
First Visit:
- Initial load: ~2-3 seconds (depends on network)
- Time to interactive: ~3-4 seconds
- PWA install prompt: After 5 seconds
Subsequent Visits:
- Instant load (service worker cache)
- ~100-200ms to interactive
- Full offline functionality
Runtime Performance
- QR generation: ~50-100ms per code
- Batch export (100 codes): ~30-60 seconds
- Encryption: ~50-100ms per operation
- Scanning: Real-time (30fps camera)
Browser Compatibility
Supported Browsers
| Browser | Minimum Version | Notes |
|---|---|---|
| Chrome | 76+ | Full support |
| Edge | 79+ | Full support |
| Firefox | 90+ | Full support |
| Safari | 13.1+ | Limited clipboard API |
| Chrome Mobile | 76+ | Full support |
| Safari iOS | 13.1+ | PWA installable |
| Samsung Internet | 12+ | Full support |
Required APIs
- ✅ ES6+ — Modern JavaScript
- ✅ Web Crypto API — Encryption
- ✅ Service Workers — PWA/offline
- ✅ IndexedDB — Local storage
- ✅ Media Devices API — Camera access
- ✅ Canvas API — Image generation
- ⚠️ Clipboard API — Limited Safari support
- ⚠️ Web Share API — Optional, mobile-mostly
Not supported:
- ❌ Internet Explorer
- ❌ Legacy Edge (before version 79)
- ❌ Older mobile browsers
Security Considerations
Client-Side Only
Advantages:
- ✅ No data leaves user's device
- ✅ No server-side vulnerabilities
- ✅ No database to compromise
- ✅ Privacy by design
Implications:
- All processing in browser memory
- No user accounts or authentication
- No server-side validation
- No telemetry or analytics
Encryption Security
- AES-GCM: Military-grade encryption
- 256-bit keys: Quantum-resistant
- PBKDF2: Brute-force resistant (100k iterations)
- Random salts/IVs: Unique per encryption
- No password storage: User must remember
Attack surface:
- Password phishing (social engineering)
- Weak passwords (user responsibility)
- Browser compromise (malware)
Content Security Policy
Recommended CSP headers:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'wasm-unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:;
font-src 'self' data:;
connect-src 'self';
media-src 'self' blob:;
Testing
Manual Testing
Test matrix:
- ✅ QR code creation (all data types)
- ✅ QR code scanning (camera + upload)
- ✅ Encryption/decryption flow
- ✅ Batch export (CSV processing)
- ✅ PWA installation
- ✅ Offline functionality
- ✅ Cross-browser compatibility
- ✅ Mobile responsiveness
- ✅ Accessibility (keyboard nav, screen readers)
Automated Testing
Not currently implemented:
- Unit tests (Vitest)
- E2E tests (Playwright)
- Component tests (Vue Test Utils)
Reason: MVP prioritized features over test coverage.
Future Enhancements
Planned Features
-
Advanced Batch Processing
- Per-row encryption passwords
- Variable error correction levels
- Preview mode before export
-
QR Code Templates
- Save custom templates
- Share templates via URL
- Template marketplace
-
Enhanced Encryption
- Multiple encryption algorithms
- Key sharing via QR code
- Password strength meter
-
Analytics (Privacy-Preserving)
- Local-only usage stats
- No tracking, no servers
- Exportable JSON reports
-
Advanced Customization
- Gradient colors
- Custom shapes (hearts, stars)
- Animation support (animated GIFs)
- 3D QR codes
Development Workflow
Local Development
# Clone repository
git clone [repo-url]
cd mini-qr
# Install dependencies
npm install
# Run dev server
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
Code Style
- ESLint for linting
- Prettier for formatting (auto-format on save)
- TypeScript strict mode
- Vue 3 best practices (Composition API)
Git Workflow
mainbranch for production- Feature branches for development
- Pull requests for code review
- Semantic commit messages