346 lines
8.2 KiB
Markdown
346 lines
8.2 KiB
Markdown
# 📊 QR Code Analytics - Premium Feature
|
|
|
|
Sistema de rastreamento de leituras de QR codes para usuários premium.
|
|
|
|
## 🎯 Visão Geral
|
|
|
|
Permite que usuários premium acompanhem quantas vezes seus QR codes foram escaneados, com timestamps e histórico completo.
|
|
|
|
### Como Funciona
|
|
|
|
1. **Usuário premium** gera QR code com analytics habilitado
|
|
2. QR code aponta para URL de redirect: `https://qrrapido.site/t/{trackingId}`
|
|
3. Ao escanear, o sistema:
|
|
- Incrementa contador de leituras (`scanCount`)
|
|
- Atualiza timestamp da última leitura (`lastAccessedAt`)
|
|
- Redireciona para URL original (HTTP 302)
|
|
|
|
---
|
|
|
|
## 🔧 Implementação Técnica
|
|
|
|
### Novos Componentes
|
|
|
|
#### 1. **TrackingController** (`Controllers/TrackingController.cs`)
|
|
|
|
Endpoints:
|
|
- `GET /t/{trackingId}` - Redireciona e contabiliza leitura
|
|
- `GET /t/analytics/{trackingId}` - Retorna analytics (requer autenticação)
|
|
|
|
#### 2. **Campos no MongoDB**
|
|
|
|
**QRCodeHistory** (campos já existentes, agora em uso):
|
|
```csharp
|
|
public int ScanCount { get; set; } = 0; // Contador de leituras
|
|
public DateTime LastAccessedAt { get; set; } // Última leitura
|
|
public bool IsDynamic { get; set; } = false; // Se é trackable
|
|
public string? TrackingId { get; set; } // ID público (novo)
|
|
```
|
|
|
|
#### 3. **QRGenerationRequest** (novo campo)
|
|
```csharp
|
|
public bool EnableTracking { get; set; } = false; // Premium feature
|
|
```
|
|
|
|
#### 4. **UserService** (novos métodos)
|
|
```csharp
|
|
Task<QRCodeHistory?> GetQRByTrackingIdAsync(string trackingId);
|
|
Task IncrementQRScanCountAsync(string trackingId);
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Como Usar
|
|
|
|
### Backend (já implementado)
|
|
|
|
#### Gerar QR com Analytics
|
|
|
|
```csharp
|
|
var request = new QRGenerationRequest
|
|
{
|
|
Type = "url",
|
|
Content = "https://google.com",
|
|
IsPremium = true,
|
|
EnableTracking = true // ✅ Habilita analytics
|
|
};
|
|
|
|
var result = await _qrService.GenerateRapidAsync(request);
|
|
|
|
// result.TrackingId conterá o ID para analytics
|
|
// QR code aponta para: https://qrrapido.site/t/{trackingId}
|
|
```
|
|
|
|
#### Consultar Analytics
|
|
|
|
```csharp
|
|
// Via UserService
|
|
var qr = await _userService.GetQRByTrackingIdAsync("abc123def456");
|
|
Console.WriteLine($"Leituras: {qr.ScanCount}");
|
|
Console.WriteLine($"Última leitura: {qr.LastAccessedAt}");
|
|
|
|
// Via API (requer autenticação)
|
|
GET /t/analytics/abc123def456
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"trackingId": "abc123def456",
|
|
"scanCount": 42,
|
|
"createdAt": "2025-10-19T10:00:00Z",
|
|
"lastAccessedAt": "2025-10-20T15:30:00Z",
|
|
"content": "https://google.com",
|
|
"type": "url"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Frontend (ainda não implementado)
|
|
|
|
#### Opção 1: Checkbox no Gerador
|
|
|
|
```html
|
|
<!-- Em Views/Home/Index.cshtml -->
|
|
<div class="form-check premium-feature">
|
|
<input type="checkbox" id="enableTracking" class="form-check-input">
|
|
<label for="enableTracking">
|
|
<i class="fas fa-chart-line"></i> Habilitar Analytics
|
|
<span class="badge bg-warning">Premium</span>
|
|
</label>
|
|
</div>
|
|
```
|
|
|
|
```javascript
|
|
// Em wwwroot/js/qr-speed-generator.js
|
|
const enableTracking = document.getElementById('enableTracking');
|
|
|
|
formData.append('EnableTracking', enableTracking?.checked && this.isPremium);
|
|
```
|
|
|
|
#### Opção 2: Dashboard de Analytics
|
|
|
|
```html
|
|
<!-- Nova view: Views/Premium/Analytics.cshtml -->
|
|
<div class="analytics-dashboard">
|
|
<h2>Meus QR Codes com Analytics</h2>
|
|
|
|
<div class="qr-list">
|
|
@foreach (var qr in Model.TrackableQRs)
|
|
{
|
|
<div class="qr-card">
|
|
<h3>@qr.Content</h3>
|
|
<p><strong>Leituras:</strong> @qr.ScanCount</p>
|
|
<p><strong>Última leitura:</strong> @qr.LastAccessedAt.ToString("dd/MM/yyyy HH:mm")</p>
|
|
<a href="/t/analytics/@qr.TrackingId">Ver detalhes</a>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 Limitações Conhecidas
|
|
|
|
### 1. **Apenas QR codes de URL**
|
|
- Tracking funciona apenas para `Type = "url"`
|
|
- WiFi, vCard, SMS, etc. **não suportam** redirect
|
|
|
|
**Razão**: Esses tipos não aceitam URLs customizadas
|
|
|
|
**Solução futura**: Implementar pixel de tracking invisível ou API de scan manual
|
|
|
|
### 2. **Redirect adiciona ~50-200ms**
|
|
- Usuário experimenta pequeno delay ao escanear
|
|
- Impacto: Mínimo para maioria dos casos
|
|
|
|
**Otimização**: Redirect é assíncrono, contador atualiza em background
|
|
|
|
### 3. **Bloqueadores de ads podem afetar**
|
|
- Alguns bloqueadores podem marcar `/t/` como tracking
|
|
- Probabilidade: Baixa (não usa cookies ou JS)
|
|
|
|
---
|
|
|
|
## 🔐 Segurança
|
|
|
|
### Proteções Implementadas
|
|
|
|
1. **Tracking ID não-sequencial**: GUID truncado (12 chars)
|
|
2. **Validação de ownership**: Endpoint `/t/analytics/` verifica se QR pertence ao usuário
|
|
3. **Fire-and-forget counting**: Não bloqueia redirect se MongoDB estiver lento
|
|
4. **Logging completo**: Todas as leituras são logadas
|
|
|
|
### Considerações de Privacidade
|
|
|
|
- **Não coleta**: IP, device, localização (por enquanto)
|
|
- **Apenas conta**: Quantidade de leituras + timestamp
|
|
- **LGPD compliant**: Usuário premium pode deletar histórico a qualquer momento
|
|
|
|
---
|
|
|
|
## 📊 Exemplos de Uso
|
|
|
|
### Caso 1: Rastreamento de Campanha
|
|
|
|
```csharp
|
|
// Gerar QR para campanha de marketing
|
|
var campaign = new QRGenerationRequest
|
|
{
|
|
Type = "url",
|
|
Content = "https://minhaloja.com/promo-verao",
|
|
IsPremium = true,
|
|
EnableTracking = true
|
|
};
|
|
|
|
var qr = await _qrService.GenerateRapidAsync(campaign);
|
|
|
|
// Distribuir QR em materiais impressos
|
|
// Depois consultar: await _userService.GetQRByTrackingIdAsync(qr.TrackingId);
|
|
```
|
|
|
|
### Caso 2: Validação de Engajamento
|
|
|
|
```csharp
|
|
// Verificar se QR code em outdoor teve leituras
|
|
var qr = await _userService.GetQRByTrackingIdAsync("abc123def456");
|
|
|
|
if (qr.ScanCount > 100)
|
|
{
|
|
Console.WriteLine("Outdoor teve boa visibilidade!");
|
|
}
|
|
else if (qr.ScanCount == 0)
|
|
{
|
|
Console.WriteLine("QR pode estar ilegível ou mal posicionado");
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠️ Configuração
|
|
|
|
### appsettings.json
|
|
|
|
```json
|
|
{
|
|
"App": {
|
|
"BaseUrl": "https://qrrapido.site" // ✅ Usado para gerar URLs de tracking
|
|
}
|
|
}
|
|
```
|
|
|
|
### appsettings.Development.json
|
|
|
|
```json
|
|
{
|
|
"App": {
|
|
"BaseUrl": "https://localhost:52428" // ✅ Para testes locais
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testando Localmente
|
|
|
|
### 1. Gerar QR com Tracking
|
|
|
|
```bash
|
|
# POST /api/QR/GenerateRapid
|
|
curl -X POST https://localhost:52428/api/QR/GenerateRapid \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"type": "url",
|
|
"content": "https://google.com",
|
|
"isPremium": true,
|
|
"enableTracking": true
|
|
}'
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"qrCodeBase64": "iVBORw0KG...",
|
|
"trackingId": "a1b2c3d4e5f6",
|
|
"success": true
|
|
}
|
|
```
|
|
|
|
### 2. Simular Leitura do QR
|
|
|
|
```bash
|
|
# Abrir no navegador (ou curl)
|
|
curl -L https://localhost:52428/t/a1b2c3d4e5f6
|
|
# Deve redirecionar para https://google.com
|
|
```
|
|
|
|
### 3. Verificar Contador
|
|
|
|
```bash
|
|
# Acessar MongoDB ou via API
|
|
curl https://localhost:52428/t/analytics/a1b2c3d4e5f6 \
|
|
-H "Authorization: Bearer {token}"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"trackingId": "a1b2c3d4e5f6",
|
|
"scanCount": 1,
|
|
"lastAccessedAt": "2025-10-20T10:00:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📈 Próximos Passos (Features Futuras)
|
|
|
|
### Analytics Avançado
|
|
- [ ] Gráfico de leituras por dia/semana/mês
|
|
- [ ] Geo-localização (IP → País/Cidade)
|
|
- [ ] Tipo de device (mobile/desktop)
|
|
- [ ] Browser/OS usado para escanear
|
|
|
|
### UI/UX
|
|
- [ ] Dashboard de analytics no painel premium
|
|
- [ ] Exportar dados para CSV/Excel
|
|
- [ ] Notificações quando QR atingir X leituras
|
|
|
|
### Performance
|
|
- [ ] Cache Redis para evitar queries MongoDB em cada scan
|
|
- [ ] Batch updates (atualizar contador a cada N leituras)
|
|
|
|
---
|
|
|
|
## 📚 Referências
|
|
|
|
- **Tracking URLs**: Mesma estratégia usada por bit.ly, tinyurl, etc.
|
|
- **HTTP 302 Redirect**: Padrão para preservar SEO e funcionalidade
|
|
- **Fire-and-forget**: Pattern do ASP.NET Core para operações assíncronas não-bloqueantes
|
|
|
|
---
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
### Problema: "QR code not found"
|
|
- Verificar se `trackingId` existe no MongoDB
|
|
- Verificar se QR foi salvo com `IsDynamic = true`
|
|
|
|
### Problema: Contador não incrementa
|
|
- Verificar logs do `TrackingController`
|
|
- Verificar conectividade MongoDB
|
|
- Verificar se `IncrementQRScanCountAsync` está sendo chamado
|
|
|
|
### Problema: Redirect não funciona
|
|
- Verificar se URL original está salva em `Content`
|
|
- Verificar se `BaseUrl` está configurado corretamente
|
|
- Verificar logs de erro no controller
|
|
|
|
---
|
|
|
|
**Implementado em**: 2025-10-20
|
|
**Versão**: 1.0.0
|
|
**Status**: ✅ Backend completo, Frontend pendente
|