docs: rewrite spec.md to match current implementation
- Restructure document with clear status tables - Mark all implemented features with ✅ - Mark deferred features with ⏳ - Add complete data model with all entities - Add system architecture diagram - Add comprehensive API endpoints list - Document plan limits (Free/Pro/Business) - List all UI pages with routes - Add security checklist (implemented vs deferred) - Update remaining work section with priorities Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
525
docs/spec.md
525
docs/spec.md
@@ -1,283 +1,394 @@
|
||||
# QR-First URL Shortener SaaS (Designer + Short Links + Tracking)
|
||||
# TrakQR - QR-First URL Shortener SaaS
|
||||
|
||||
Note: These specs are a draft and need review.
|
||||
> Create branded short links and highly customizable QR codes, then track scans/clicks with actionable analytics.
|
||||
|
||||
## 0) Product Definition
|
||||
## Product Overview
|
||||
|
||||
One-liner: Create branded short links and highly customizable QR codes, then track scans/clicks with actionable analytics.
|
||||
|
||||
Primary users:
|
||||
**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.
|
||||
**Core value:** Beautiful QR designs + brandable short domains + trustworthy tracking in one place.
|
||||
|
||||
## 1) MVP Scope (what ships first)
|
||||
---
|
||||
|
||||
### 1.1 User Capabilities (MVP)
|
||||
## 1. MVP Features (Implemented)
|
||||
|
||||
Auth & Account
|
||||
- Sign up / sign in (email + password; optional SSO later)
|
||||
- Email verification
|
||||
- Password reset
|
||||
- Basic account settings
|
||||
### 1.1 Authentication & Account
|
||||
|
||||
Projects / Workspaces
|
||||
- Default workspace per user
|
||||
- Create “Projects” to organize links/QRs (e.g., “Restaurant menus”, “Flyers Q1”)
|
||||
| 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 |
|
||||
|
||||
Short Link Creation
|
||||
- Create short link: https://d.om/abc123 or custom slug …/menu
|
||||
- Destination URL validation
|
||||
- Optional UTM builder (preset templates)
|
||||
- Enable/disable link
|
||||
- Expiration date (optional)
|
||||
- Password protection (optional) — may be “Pro” if you want
|
||||
### 1.2 Workspaces & Projects
|
||||
|
||||
QR Code Designer
|
||||
- Generate QR from a short link (default) or direct URL
|
||||
- Styling:
|
||||
- Colors (foreground/background)
|
||||
- Error correction level (L/M/Q/H)
|
||||
- Quiet zone padding
|
||||
- Shape presets (modules/eyes) (start with a few presets)
|
||||
- Center logo upload (PNG/SVG) with size + margin controls
|
||||
- Export:
|
||||
- PNG and SVG
|
||||
- Size presets (e.g., 256/512/1024/2048)
|
||||
- Print-ready options (e.g., “high contrast” toggle)
|
||||
| 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 |
|
||||
|
||||
Tracking & Analytics (MVP)
|
||||
- Track events: click (short link) and scan (QR)
|
||||
- Dashboard:
|
||||
- Total events, uniques, last 24h / 7d / 30d
|
||||
- Time series
|
||||
- Top referrers (for clicks)
|
||||
- Geo (country) and device (desktop/mobile) high-level
|
||||
- Per-link analytics and per-QR analytics
|
||||
### 1.3 Short Link Management
|
||||
|
||||
Basic Admin
|
||||
- Subscription status
|
||||
- Usage quotas (links/QRs/events)
|
||||
| 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 |
|
||||
|
||||
## 2) Non-Goals for MVP (explicitly out)
|
||||
### 1.4 QR Code Designer
|
||||
|
||||
- Team roles/permissions (RBAC) beyond “owner”
|
||||
- A/B routing, smart rules, rotation, geo routing
|
||||
- Deep campaign automation
|
||||
- Enterprise SSO, SCIM
|
||||
- Offline QR scan tracking (impossible without network in most cases)
|
||||
| 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 |
|
||||
|
||||
## 3) Plans & Monetization (recommended)
|
||||
### 1.5 Tracking & Analytics
|
||||
|
||||
Free
|
||||
- 1 workspace
|
||||
- 25 short links
|
||||
- 25 QR designs
|
||||
- 10k events/month
|
||||
- 1 custom QR logo upload (or allow unlimited but watermark exports)
|
||||
| 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 |
|
||||
|
||||
Pro (individual/SMB)
|
||||
- Custom domains (1–3)
|
||||
- Higher limits
|
||||
- No watermark
|
||||
- UTM templates
|
||||
- Expiring links / password links (if Pro)
|
||||
### 1.6 Domain Management
|
||||
|
||||
Business
|
||||
- Multiple workspaces
|
||||
- Team seats (later)
|
||||
- Higher retention and export presets
|
||||
| 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 |
|
||||
|
||||
## 4) Core Entities (Data Model)
|
||||
### 1.7 Asset Management
|
||||
|
||||
### 4.1 Entities
|
||||
| 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, verified_at, created_at
|
||||
├── id, email, password_hash
|
||||
├── is_email_verified, created_at
|
||||
└── Relations: Workspaces, EmailVerificationTokens, PasswordResetTokens
|
||||
|
||||
Workspace
|
||||
- id, owner_user_id, name, plan, created_at
|
||||
├── id, owner_user_id, name, plan
|
||||
├── created_at
|
||||
└── Relations: Projects, ShortLinks, QRCodeDesigns, Domains, Assets, Events, ApiKeys
|
||||
|
||||
Project
|
||||
- id, workspace_id, name, created_at
|
||||
├── id, workspace_id, name, description
|
||||
└── created_at
|
||||
|
||||
Domain
|
||||
- id, workspace_id, hostname, status (pending/verified/active), verification_token, created_at
|
||||
├── id, workspace_id, hostname
|
||||
├── status (Pending/Verified), verification_token
|
||||
└── created_at
|
||||
|
||||
ShortLink
|
||||
- id
|
||||
- workspace_id, project_id (nullable)
|
||||
- domain_id (nullable; else default platform domain)
|
||||
- slug
|
||||
- destination_url
|
||||
- title (nullable)
|
||||
- status (active/disabled)
|
||||
- expires_at (nullable)
|
||||
- password_hash (nullable)
|
||||
- created_at, updated_at
|
||||
├── 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)
|
||||
- shortlink_id (nullable; recommended default)
|
||||
- style_json (colors, shapes, ecc level, etc.)
|
||||
- logo_asset_id (nullable)
|
||||
- created_at, updated_at
|
||||
├── id, workspace_id, project_id (nullable), link_id
|
||||
├── name, style_json, logo_asset_id (nullable)
|
||||
└── created_at, updated_at
|
||||
|
||||
Event
|
||||
- id (or bigint)
|
||||
- workspace_id
|
||||
- shortlink_id
|
||||
- qrcode_id (nullable but strongly recommended to tag scans)
|
||||
- type: click | scan
|
||||
- ts
|
||||
- ip_hash (privacy-safe)
|
||||
- user_agent
|
||||
- referrer
|
||||
- country_code (nullable)
|
||||
- device_type (nullable)
|
||||
- dedupe_key (nullable)
|
||||
- raw_json (optional for debug, or drop)
|
||||
├── 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, type (logo), storage_key, mime, size, created_at
|
||||
├── id, workspace_id, filename, storage_key
|
||||
├── content_type, size_bytes
|
||||
└── created_at
|
||||
|
||||
### 4.2 Key Design Choice
|
||||
ApiKey
|
||||
├── id, workspace_id, name, key_hash, key_prefix
|
||||
├── scopes, expires_at, last_used_at, is_active
|
||||
└── created_at
|
||||
|
||||
How do we distinguish “scan” vs “click”?
|
||||
EmailVerificationToken
|
||||
├── id, user_id, token, expires_at, used_at
|
||||
└── created_at
|
||||
|
||||
When exporting a QR, embed a URL like:
|
||||
https://d.om/s/abc123?qr=<qrcode_id>
|
||||
PasswordResetToken
|
||||
├── id, user_id, token, expires_at, used_at
|
||||
└── created_at
|
||||
```
|
||||
|
||||
The redirect endpoint records scan when it detects qr=<id>, then redirects to destination, which will also produce a click unless you decide “scan implies click” and record only one.
|
||||
---
|
||||
|
||||
Recommendation: record one event per redirect request:
|
||||
- If qr present → type=scan
|
||||
- Else → type=click
|
||||
## 4. System Architecture
|
||||
|
||||
## 5) System Behavior (Routes & Flows)
|
||||
### Components
|
||||
|
||||
### 5.1 Public Redirect
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Vue 3 SPA │────▶│ ASP.NET Core │────▶│ PostgreSQL │
|
||||
│ + Pinia │ │ FastEndpoints │ │ │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ External APIs │
|
||||
│ - Stripe │
|
||||
│ - SMTP │
|
||||
│ - MaxMind │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
GET /{slug}
|
||||
### Key Design Decisions
|
||||
|
||||
Resolve domain + slug → short link
|
||||
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
|
||||
|
||||
Validate:
|
||||
- exists
|
||||
- active
|
||||
- not expired
|
||||
- if password-protected → show password page
|
||||
### Public Redirect Flow
|
||||
|
||||
Log event (scan/click)
|
||||
```
|
||||
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 │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Redirect 301/302 (configurable later; MVP use 302)
|
||||
---
|
||||
|
||||
### 5.2 QR Export
|
||||
## 5. API Endpoints
|
||||
|
||||
QR code is generated from:
|
||||
### 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
|
||||
|
||||
Redirect URL including qrcode id: https://{domain}/{slug}?qr={qrcode_id}
|
||||
### 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
|
||||
|
||||
## 6) Functional Requirements (MVP checklist)
|
||||
### 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
|
||||
|
||||
Link Management
|
||||
- Create, edit, disable, delete (soft delete preferred)
|
||||
- Slug uniqueness per domain
|
||||
- Auto-slug generator (base62)
|
||||
- Destination URL allowlist/denylist (prevent abuse)
|
||||
### 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
|
||||
|
||||
QR Designer
|
||||
- Live preview
|
||||
- Save design
|
||||
- Export SVG/PNG
|
||||
- Logo upload with validation (size/mime)
|
||||
### 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
|
||||
- Views for:
|
||||
- Workspace overview
|
||||
- Project overview
|
||||
- Per short link
|
||||
- Per QR design
|
||||
- Time filters: 24h / 7d / 30d / custom range
|
||||
- Unique definition:
|
||||
- Unique per day per link based on ip_hash + UA hash (privacy-safe and approximate)
|
||||
### Analytics & Usage
|
||||
- `GET /workspaces/{id}/analytics` - Workspace analytics
|
||||
- `GET /usage` - Usage stats and limits
|
||||
|
||||
## 7) Non-Functional Requirements
|
||||
### 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
|
||||
|
||||
Performance
|
||||
- Redirect endpoint P95 < 100ms (excluding DNS/TLS)
|
||||
- Event write must not block redirect (use async queue if possible)
|
||||
### API Keys
|
||||
- `GET/POST /workspaces/{id}/api-keys` - List/Create keys
|
||||
- `DELETE /workspaces/{id}/api-keys/{kid}` - Delete key
|
||||
|
||||
Availability
|
||||
- Redirect is the critical path; should stay up even if dashboard is down
|
||||
- Graceful degradation: if analytics store is down, still redirect
|
||||
### Public
|
||||
- `GET /{slug}` - Redirect to destination
|
||||
- `POST /{slug}` - Redirect with password
|
||||
|
||||
Security
|
||||
- Rate limit public endpoints
|
||||
- Abuse prevention: phishing/malware reporting flow (later), basic filters now
|
||||
- Domain verification to prevent takeover
|
||||
- Strict CSP on app pages
|
||||
---
|
||||
|
||||
Privacy & Compliance (Canada / Quebec friendly baseline)
|
||||
- Avoid storing raw IP; store hashed IP with rotating salt (e.g., monthly)
|
||||
- Provide retention configuration per plan (e.g., 30/180/365 days)
|
||||
## 6. UI Pages
|
||||
|
||||
## 8) Architecture (pragmatic MVP)
|
||||
| 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` | ✅ |
|
||||
|
||||
Components
|
||||
- Web App: dashboard + designer (Vue/React)
|
||||
- API: CRUD for links/qr/projects/domains, analytics queries
|
||||
- Redirect Edge: fastest path for /{slug} (can be same API initially)
|
||||
---
|
||||
|
||||
Storage
|
||||
- PostgreSQL for core entities
|
||||
- Analytics:
|
||||
- MVP: PostgreSQL events table partitioned by month
|
||||
- Later: ClickHouse/BigQuery for scale
|
||||
## 7. Security & Performance
|
||||
|
||||
Background Jobs
|
||||
- Domain verification checks
|
||||
- Event enrichment (geo/device parsing)
|
||||
- Cleanup & retention tasks
|
||||
### 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
|
||||
|
||||
## 9) API Surface (minimal)
|
||||
### Deferred
|
||||
- [ ] Strict CSP headers
|
||||
- [ ] Monthly rotating IP salt
|
||||
- [ ] URL allowlist/denylist
|
||||
- [ ] Abuse reporting flow
|
||||
|
||||
- POST /auth/register|login|forgot|reset
|
||||
- GET/POST /workspaces
|
||||
- GET/POST /projects
|
||||
- GET/POST /links
|
||||
- GET/POST /qrcodes
|
||||
- POST /domains + verification status
|
||||
- GET /analytics/overview
|
||||
- GET /analytics/link/{id}
|
||||
- GET /analytics/qrcode/{id}
|
||||
---
|
||||
|
||||
## 10) UI Pages (MVP)
|
||||
## 8. Remaining Work
|
||||
|
||||
- Login / Register / Reset
|
||||
- Workspace switcher
|
||||
- Projects list
|
||||
- Links list + create/edit
|
||||
- QR designer (create/edit) with preview
|
||||
- Analytics dashboard (overview + per link + per QR)
|
||||
- Domains page (add/verify)
|
||||
### 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
|
||||
|
||||
## 11) Pricing/Quotas Enforcement
|
||||
### 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
|
||||
|
||||
Enforce at API level:
|
||||
- max links, max QR codes, max events/month, max custom domains
|
||||
### 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
|
||||
|
||||
Stripe integration later; MVP can be “manual Pro” toggle or Stripe from day 1 if you want.
|
||||
---
|
||||
|
||||
## 12) Implementation Notes (key decisions)
|
||||
## 9. Non-Goals (Post-MVP)
|
||||
|
||||
- Use one redirect URL as canonical; QR adds ?qr= for attribution.
|
||||
- Event logging should be non-blocking:
|
||||
- MVP: write to DB async (background queue) or “fire-and-forget” with retry
|
||||
- Plan for domain verification:
|
||||
- Require DNS TXT record or CNAME to verify ownership
|
||||
- Short link collision:
|
||||
- Slug uniqueness per domain enforced in DB
|
||||
- Team roles/permissions (RBAC)
|
||||
- A/B routing, smart rules, geo routing
|
||||
- Deep campaign automation
|
||||
- Enterprise SSO, SCIM
|
||||
- Offline QR scan tracking
|
||||
|
||||
Reference in New Issue
Block a user