# TrakQR - QR-First URL Shortener SaaS > Create branded short links and highly customizable QR codes, then track scans/clicks with actionable analytics. ## Product Overview **Primary users:** - Solo creators / small businesses - Marketing teams in SMB/PME - Agencies managing multiple clients **Core value:** Beautiful QR designs + brandable short domains + trustworthy tracking in one place. --- ## 1. MVP Features (Implemented) ### 1.1 Authentication & Account | Feature | Status | Notes | |---------|--------|-------| | Email + password signup | ✅ | With auto-created default workspace | | Email verification | ✅ | Token-based, resend support | | Login with JWT | ✅ | Rate-limited | | Password reset | ✅ | Email-based token flow | | Profile management | ✅ | Update email, change password | | Delete account | ✅ | With password confirmation | | SSO | ⏳ | Deferred to post-MVP | ### 1.2 Workspaces & Projects | Feature | Status | Notes | |---------|--------|-------| | Default workspace on signup | ✅ | Auto-created | | Multiple workspaces | ✅ | Based on plan limits | | Workspace CRUD | ✅ | Create, update, delete | | Projects for organization | ✅ | Full CRUD with descriptions | | Workspace switcher UI | ✅ | With create/manage modals | ### 1.3 Short Link Management | Feature | Status | Notes | |---------|--------|-------| | Create short link | ✅ | Custom or auto-generated slug | | Destination URL validation | ✅ | URL format validation | | UTM builder | ✅ | Presets for Google, Facebook, Email, Social | | Enable/disable link | ✅ | Status field (Active/Disabled) | | Expiration date | ✅ | Optional datetime | | Password protection | ✅ | Optional, with POST endpoint for auth | | Soft delete + restore | ✅ | Trash view with restore | | Bulk import | ✅ | CSV-style paste with titles | | URL allowlist/denylist | ⏳ | Deferred - abuse prevention | ### 1.4 QR Code Designer | Feature | Status | Notes | |---------|--------|-------| | Generate from short link | ✅ | Required link association | | Foreground/background colors | ✅ | Hex color pickers | | Error correction levels | ✅ | L/M/Q/H options | | Quiet zone padding | ✅ | Configurable | | Module shapes | ✅ | Square, Rounded, Dots | | Eye shapes | ✅ | Square, Rounded, Circle | | Style presets | ✅ | 6 built-in presets | | Logo upload | ✅ | PNG/JPG, select from assets or upload new | | Logo size controls | ⚠️ | Fixed 20% - user controls deferred | | Live preview | ✅ | Real-time updates | | Export PNG | ✅ | Configurable size (256-2048px) | | Export SVG | ✅ | Vector output | | Print-ready options | ⏳ | High contrast toggle deferred | | Scan attribution | ✅ | Exports include `?qr={id}` param | ### 1.5 Tracking & Analytics | Feature | Status | Notes | |---------|--------|-------| | Click events | ✅ | From redirect endpoint | | Scan events | ✅ | When `?qr=` param present | | Async event logging | ✅ | Non-blocking, fire-and-forget | | IP hashing | ✅ | SHA256 with daily salt | | Dedupe (30-min window) | ✅ | Prevents duplicate counts | | User agent parsing | ✅ | Device type detection | | GeoIP lookup | ✅ | MaxMind GeoIP2 integration | | Workspace analytics | ✅ | Totals, time series, breakdowns | | Per-link analytics | ✅ | Individual link stats | | Per-QR analytics | ✅ | Individual QR stats | | Time filters | ✅ | 24h, 7d, 30d | | Custom date range | ⚠️ | Backend ready, frontend UI needed | | Referrer breakdown | ✅ | Top referrers list | | Device breakdown | ✅ | Desktop/Mobile/Tablet | | Country breakdown | ✅ | With flags and names | | Monthly IP salt rotation | ⏳ | Deferred - privacy enhancement | | Event retention config | ⏳ | Deferred - per-plan cleanup | ### 1.6 Domain Management | Feature | Status | Notes | |---------|--------|-------| | Add custom domain | ✅ | Pro/Business plans | | DNS TXT verification | ✅ | Token-based | | CNAME setup instructions | ✅ | UI guide | | Domain status tracking | ✅ | Pending → Verified | | Delete domain | ✅ | With warning | ### 1.7 Asset Management | Feature | Status | Notes | |---------|--------|-------| | Upload assets | ✅ | For QR logos | | List workspace assets | ✅ | Gallery view | | Delete assets | ✅ | With cleanup | | Public asset URL | ✅ | For rendering | ### 1.8 Plans & Billing | Feature | Status | Notes | |---------|--------|-------| | Plan tiers (Free/Pro/Business) | ✅ | Configured limits | | Usage tracking | ✅ | Links, QRs, domains, events | | Plan limits enforcement | ✅ | In create endpoints | | Stripe checkout | ✅ | Session-based | | Stripe customer portal | ✅ | Manage subscription | | Webhook handling | ✅ | Subscription events | | Billing UI | ✅ | Plan comparison, upgrade flow | ### 1.9 API Keys | Feature | Status | Notes | |---------|--------|-------| | Create API key | ✅ | With name and expiry | | List API keys | ✅ | Shows prefix, last used | | Delete API key | ✅ | Revoke access | | API key authentication | ⏳ | Middleware needed | --- ## 2. Plan Limits | Feature | Free | Pro | Business | |---------|------|-----|----------| | Workspaces | 1 | 5 | Unlimited | | Links per workspace | 50 | 5,000 | Unlimited | | QR codes per workspace | 25 | 1,000 | Unlimited | | Custom domains | 0 | 3 | Unlimited | | Events per month | 10,000 | 100,000 | Unlimited | | Custom domains feature | ❌ | ✅ | ✅ | | Password protection | ❌ | ✅ | ✅ | | Analytics | ✅ | ✅ | ✅ | --- ## 3. Data Model ### Core Entities ``` User ├── id, email, password_hash ├── is_email_verified, created_at └── Relations: Workspaces, EmailVerificationTokens, PasswordResetTokens Workspace ├── id, owner_user_id, name, plan ├── created_at └── Relations: Projects, ShortLinks, QRCodeDesigns, Domains, Assets, Events, ApiKeys Project ├── id, workspace_id, name, description └── created_at Domain ├── id, workspace_id, hostname ├── status (Pending/Verified), verification_token └── created_at ShortLink ├── id, workspace_id, project_id (nullable), domain_id (nullable) ├── slug, destination_url, title ├── status (Active/Disabled), expires_at, password_hash ├── click_count, is_deleted, deleted_at └── created_at, updated_at QRCodeDesign ├── id, workspace_id, project_id (nullable), link_id ├── name, style_json, logo_asset_id (nullable) └── created_at, updated_at Event ├── id, workspace_id, link_id, qr_code_id (nullable) ├── type (Click/Scan), timestamp ├── ip_hash, user_agent, referrer ├── country_code, device_type, dedupe_key └── (partitioned by month for scale) Asset ├── id, workspace_id, filename, storage_key ├── content_type, size_bytes └── created_at ApiKey ├── id, workspace_id, name, key_hash, key_prefix ├── scopes, expires_at, last_used_at, is_active └── created_at EmailVerificationToken ├── id, user_id, token, expires_at, used_at └── created_at PasswordResetToken ├── id, user_id, token, expires_at, used_at └── created_at ``` --- ## 4. System Architecture ### Components ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Vue 3 SPA │────▶│ ASP.NET Core │────▶│ PostgreSQL │ │ + Pinia │ │ FastEndpoints │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ │ External APIs │ │ - Stripe │ │ - SMTP │ │ - MaxMind │ └─────────────────┘ ``` ### Key Design Decisions 1. **Vertical Slice Architecture**: Features organized in `Features/{Feature}/` folders 2. **FastEndpoints**: Lightweight alternative to MVC controllers 3. **Pinia State Management**: Centralized frontend state with persistence 4. **Non-blocking Event Logging**: Fire-and-forget to not slow redirects 5. **Soft Delete**: Links can be restored from trash 6. **Scan Attribution**: QR exports embed `?qr={id}` for tracking ### Public Redirect Flow ``` GET /{slug}?qr={id} │ ▼ ┌─────────────────────────────────────┐ │ 1. Resolve domain + slug → link │ │ 2. Validate: exists, active, !expired│ │ 3. If password → return 401 │ │ 4. Log event async (scan if ?qr=) │ │ 5. Return 302 redirect │ └─────────────────────────────────────┘ ``` --- ## 5. API Endpoints ### Authentication - `POST /auth/register` - Create account - `POST /auth/login` - Get JWT token - `POST /auth/forgot` - Request password reset - `POST /auth/reset` - Reset password with token - `POST /auth/verify-email` - Verify email - `POST /auth/resend-verification` - Resend verification email - `GET /auth/profile` - Get current user - `PUT /auth/profile` - Update profile - `POST /auth/change-password` - Change password - `DELETE /auth/account` - Delete account ### Workspaces & Projects - `GET/POST /workspaces` - List/Create workspaces - `GET/PUT/DELETE /workspaces/{id}` - Workspace operations - `GET/POST /workspaces/{id}/projects` - List/Create projects - `GET/PUT/DELETE /workspaces/{id}/projects/{pid}` - Project operations ### Links - `GET/POST /workspaces/{id}/links` - List/Create links - `POST /workspaces/{id}/links/bulk` - Bulk create - `GET/PUT/DELETE /workspaces/{id}/links/{lid}` - Link operations - `POST /workspaces/{id}/links/{lid}/restore` - Restore deleted - `GET /workspaces/{id}/links/{lid}/analytics` - Link analytics ### QR Codes - `GET/POST /workspaces/{id}/qrcodes` - List/Create QR codes - `GET/PUT/DELETE /workspaces/{id}/qrcodes/{qid}` - QR operations - `GET /workspaces/{id}/qrcodes/{qid}/preview` - Get preview (data URL) - `GET /workspaces/{id}/qrcodes/{qid}/export` - Export PNG/SVG - `GET /workspaces/{id}/qrcodes/{qid}/analytics` - QR analytics ### Domains & Assets - `GET/POST /workspaces/{id}/domains` - List/Add domains - `DELETE /workspaces/{id}/domains/{did}` - Delete domain - `POST /workspaces/{id}/domains/{did}/verify` - Verify domain - `GET/POST /workspaces/{id}/assets` - List/Upload assets - `DELETE /workspaces/{id}/assets/{aid}` - Delete asset - `GET /assets/{storageKey}` - Public asset URL ### Analytics & Usage - `GET /workspaces/{id}/analytics` - Workspace analytics - `GET /usage` - Usage stats and limits ### Billing - `POST /billing/checkout` - Create Stripe checkout - `POST /billing/portal` - Create Stripe portal session - `GET /workspaces/{id}/subscription` - Get subscription - `POST /billing/webhook` - Stripe webhooks ### API Keys - `GET/POST /workspaces/{id}/api-keys` - List/Create keys - `DELETE /workspaces/{id}/api-keys/{kid}` - Delete key ### Public - `GET /{slug}` - Redirect to destination - `POST /{slug}` - Redirect with password --- ## 6. UI Pages | Page | Route | Status | |------|-------|--------| | Landing | `/` | ✅ | | Login | `/login` | ✅ | | Register | `/register` | ✅ | | Forgot Password | `/forgot-password` | ✅ | | Reset Password | `/reset-password` | ✅ | | Verify Email | `/verify-email` | ✅ | | Dashboard | `/dashboard` | ✅ | | Links List | `/links` | ✅ | | Link Detail | `/links/:id` | ✅ | | QR Codes List | `/qrcodes` | ✅ | | QR Designer | `/qrcodes/new`, `/qrcodes/:id` | ✅ | | QR Analytics | `/qrcodes/:id/analytics` | ✅ | | Analytics | `/analytics` | ✅ | | Projects | `/projects` | ✅ | | Domains | `/domains` | ✅ | | Settings | `/settings` | ✅ | | Billing | `/billing` | ✅ | --- ## 7. Security & Performance ### Implemented - [x] JWT authentication with expiry - [x] Rate limiting on auth endpoints (10 req/min) - [x] Rate limiting on redirect endpoint (100 req/min) - [x] Password hashing with BCrypt - [x] IP hashing for privacy - [x] CORS configuration - [x] Global exception handling - [x] Input validation with FluentValidation - [x] Ownership verification on all endpoints ### Deferred - [ ] Strict CSP headers - [ ] Monthly rotating IP salt - [ ] URL allowlist/denylist - [ ] Abuse reporting flow --- ## 8. Remaining Work ### High Priority 1. **API Key Authentication Middleware** - Enable programmatic access 2. **Bulk Create Plan Limits** - Check limits in bulk endpoint 3. **Custom Date Range UI** - Date picker for analytics ### Medium Priority 4. **Background Jobs** - Domain verification polling, event cleanup 5. **Logo Size Controls** - User-adjustable logo size/margin 6. **Additional Tests** - Auth, billing, API key endpoints ### Lower Priority 7. **Print-Ready QR** - High contrast mode 8. **Analytics Export** - CSV/JSON download 9. **Strict CSP** - Security headers 10. **IP Salt Rotation** - Monthly rotation for privacy --- ## 9. Non-Goals (Post-MVP) - Team roles/permissions (RBAC) - A/B routing, smart rules, geo routing - Deep campaign automation - Enterprise SSO, SCIM - Offline QR scan tracking