Skip to content

Commit 7e620bd

Browse files
committed
feat: Add Laravel DomPDF integration for PDF generation, enhance consulting report features with AI-generated insights, and improve user experience with new tour functionalities in the dashboard.
1 parent da656c1 commit 7e620bd

184 files changed

Lines changed: 13459 additions & 2966 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.production.example

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# =============================================================================
2+
# VERTEX CONTAS - Template para produção (sem credenciais reais)
3+
# =============================================================================
4+
# No servidor: copie para .env, preencha os valores e execute php artisan key:generate
5+
# Nunca commite o .env com senhas ou chaves reais.
6+
# =============================================================================
7+
8+
# -----------------------------------------------------------------------------
9+
# APLICAÇÃO
10+
# -----------------------------------------------------------------------------
11+
APP_NAME="Vertex Contas"
12+
APP_ENV=production
13+
APP_KEY=
14+
# Gere no servidor: php artisan key:generate
15+
16+
APP_DEBUG=false
17+
APP_URL=https://seu-dominio.com.br
18+
19+
APP_LOCALE=pt-BR
20+
APP_FALLBACK_LOCALE=pt-BR
21+
APP_FAKER_LOCALE=pt_BR
22+
APP_TIMEZONE=America/Sao_Paulo
23+
24+
APP_MAINTENANCE_DRIVER=file
25+
26+
BCRYPT_ROUNDS=12
27+
28+
# -----------------------------------------------------------------------------
29+
# LOG
30+
# -----------------------------------------------------------------------------
31+
LOG_CHANNEL=stack
32+
LOG_STACK=single
33+
LOG_DEPRECATIONS_CHANNEL=null
34+
LOG_LEVEL=error
35+
LOG_DAILY_DAYS=14
36+
37+
# -----------------------------------------------------------------------------
38+
# BANCO DE DADOS - Preencher no servidor
39+
# -----------------------------------------------------------------------------
40+
DB_CONNECTION=mysql
41+
DB_HOST=localhost
42+
DB_PORT=3306
43+
DB_DATABASE=
44+
DB_USERNAME=
45+
DB_PASSWORD=
46+
DB_CHARSET=utf8mb4
47+
DB_COLLATION=utf8mb4_unicode_ci
48+
49+
# -----------------------------------------------------------------------------
50+
# SESSÃO
51+
# -----------------------------------------------------------------------------
52+
SESSION_DRIVER=database
53+
SESSION_LIFETIME=120
54+
SESSION_ENCRYPT=true
55+
SESSION_PATH=/
56+
SESSION_DOMAIN=null
57+
SESSION_SECURE_COOKIE=true
58+
SESSION_SAME_SITE=lax
59+
SESSION_HTTP_ONLY=true
60+
61+
# -----------------------------------------------------------------------------
62+
# CACHE
63+
# -----------------------------------------------------------------------------
64+
CACHE_STORE=file
65+
CACHE_PREFIX=vertex-contas-cache-
66+
67+
# -----------------------------------------------------------------------------
68+
# ARQUIVOS
69+
# -----------------------------------------------------------------------------
70+
FILESYSTEM_DISK=local
71+
72+
# -----------------------------------------------------------------------------
73+
# FILA (database + cron a cada minuto para envio de e-mails)
74+
# -----------------------------------------------------------------------------
75+
QUEUE_CONNECTION=database
76+
77+
# -----------------------------------------------------------------------------
78+
# BROADCAST (Vertex Chat VIP - opcional)
79+
# -----------------------------------------------------------------------------
80+
BROADCAST_CONNECTION=log
81+
# BROADCAST_CONNECTION=pusher
82+
83+
# PUSHER_APP_ID=
84+
# PUSHER_APP_KEY=
85+
# PUSHER_APP_SECRET=
86+
# PUSHER_APP_CLUSTER=sa1
87+
88+
# -----------------------------------------------------------------------------
89+
# E-MAIL - SMTP - Preencher no servidor
90+
# -----------------------------------------------------------------------------
91+
MAIL_MAILER=smtp
92+
MAIL_HOST=
93+
MAIL_PORT=465
94+
MAIL_USERNAME=
95+
MAIL_PASSWORD=
96+
MAIL_ENCRYPTION=ssl
97+
MAIL_FROM_ADDRESS=
98+
MAIL_FROM_NAME="${APP_NAME}"
99+
100+
# -----------------------------------------------------------------------------
101+
# REDIS (opcional)
102+
# -----------------------------------------------------------------------------
103+
REDIS_CLIENT=phpredis
104+
REDIS_HOST=127.0.0.1
105+
REDIS_PASSWORD=null
106+
REDIS_PORT=6379
107+
108+
# -----------------------------------------------------------------------------
109+
# MEMCACHED (opcional)
110+
# -----------------------------------------------------------------------------
111+
MEMCACHED_HOST=127.0.0.1
112+
MEMCACHED_PORT=11211
113+
114+
# -----------------------------------------------------------------------------
115+
# AWS S3 (opcional)
116+
# -----------------------------------------------------------------------------
117+
AWS_ACCESS_KEY_ID=
118+
AWS_SECRET_ACCESS_KEY=
119+
AWS_DEFAULT_REGION=us-east-1
120+
AWS_BUCKET=
121+
AWS_USE_PATH_STYLE_ENDPOINT=false
122+
123+
# -----------------------------------------------------------------------------
124+
# VITE / FRONTEND
125+
# -----------------------------------------------------------------------------
126+
VITE_APP_NAME="${APP_NAME}"
127+
128+
# -----------------------------------------------------------------------------
129+
# reCAPTCHA v3 (Admin > Configurações > Segurança)
130+
# -----------------------------------------------------------------------------
131+
# RECAPTCHA_SITE_KEY=
132+
# RECAPTCHA_SECRET_KEY=
133+
134+
# -----------------------------------------------------------------------------
135+
# Google Gemini (Vertex Bot - Admin > Configurações > IA)
136+
# -----------------------------------------------------------------------------
137+
# GEMINI_API_KEY=
138+
139+
# -----------------------------------------------------------------------------
140+
# PAGAMENTOS - Preencher no servidor ou configurar no Admin (Gateways)
141+
# -----------------------------------------------------------------------------
142+
# STRIPE_KEY=
143+
# STRIPE_SECRET=
144+
# STRIPE_WEBHOOK_SECRET=
145+
# MERCADOPAGO_PUBLIC_KEY=
146+
# MERCADOPAGO_ACCESS_TOKEN=

Config.md

Lines changed: 83 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,92 @@
1-
@.cursorrules
2-
@Modules/Gamification
3-
@Modules/Core/Services/FinancialHealthService.php
4-
@Modules/Core/app/Services/SettingService.php
5-
@Modules/Gamification/resources/views/components/vertex-bot.blade.php
1+
### 1. O "Segredo" Técnico: Headless Chrome
2+
3+
Empresas profissionais usam ferramentas que rodam um "navegador escondido" (Chromium) no servidor. Ele renderiza o HTML exatamente como você desenhou e o transforma em PDF antes de enviar para o usuário.
4+
5+
**A Recomendação de Ouro:** Use o pacote **[Spatie Browsershot]()**.
6+
7+
* Ele usa o Puppeteer (Node.js) para controlar o Chrome.
8+
* É o que há de mais moderno: aceita Tailwind CSS v4, JavaScript, Gráficos (ApexCharts/Chart.js) e alinhamentos perfeitos.
9+
10+
### 2. O Segredo do Design: CSS de Impressão (@page)
11+
12+
Para o PDF não sair cortado e respeitar a folha A4, você precisa definir regras específicas de CSS que o navegador de renderização vai seguir:
13+
14+
```css
15+
@media print {
16+
@page {
17+
size: A4;
18+
margin: 1cm; /* Margens de segurança */
19+
}
20+
21+
/* Evita que um card ou linha de tabela seja cortada no meio entre duas páginas */
22+
.no-break {
23+
break-inside: avoid;
24+
}
25+
26+
/* Força o fundo das cores (Tailwind precisa disso no PDF) */
27+
* {
28+
-webkit-print-color-adjust: exact !important;
29+
print-color-adjust: exact !important;
30+
}
31+
}
32+
33+
/* Container fixo para simular o A4 no desenvolvimento */
34+
.a4-container {
35+
width: 210mm;
36+
min-height: 297mm;
37+
margin: auto;
38+
}
39+
40+
```
41+
42+
### 3. Anatomia de uma Invoice Profissional (Estilo Stripe)
643

7-
**Role:** Senior AI Engineer & UX Master.
8-
**Goal:** Replace the static insight system with the Google Gemini AI API to provide real-time, hyper-personalized financial coaching. Also, upgrade the Bot's visual design to a Premium "Fintech Elite" style.
44+
Para não parecer um "emaranhado de coisas", o layout deve seguir esta hierarquia:
45+
46+
1. **Header:** Logo à esquerda (em alta resolução ou SVG) e Status (Ex: PAGO em verde) à direita.
47+
2. **Meta Dados:** Número do relatório, Data e Cliente em blocos de 3 colunas.
48+
3. **Tabela de Itens:** Fundo branco, linhas alternadas (zebra) em cinza ultra claro, bordas apenas horizontais.
49+
4. **Resumo Financeiro:** Alinhado à direita no rodapé, com o Total em negrito e fonte maior.
50+
5. **Rodapé Legal:** Termos e identificação da Vertex Solutions em fonte pequena (8pt).
951

1052
---
1153

12-
### Phase 1: Gemini AI Integration (The New Brain)
13-
1. **API Setup:** Configure o cliente Guzzle para conectar à API do Google Gemini (utilize uma chave `GEMINI_API_KEY` no `.env`).
14-
2. **Context Provider:** No `GamificationService`, crie um método que gera um "Prompt Contextual":
15-
* Inclua: Percentuais 50/30/20 reais, Score Financeiro, e títulos dos últimos 3 posts do Blog.
16-
* **Segurança LGPD:** Use os helpers existentes para NUNCA enviar nomes reais ou CPFs para a API. Envie apenas métricas e números.
17-
3. **Logic:** Se a API falhar ou estiver sem internet, o sistema deve fazer fallback AUTOMÁTICO para as dicas locais da `insights_bank`.
18-
19-
### Phase 2: High-End UI Redesign (Visual Iron Man)
20-
1. **Component Update:** Refatore o `vertex-bot.blade.php`.
21-
* **Visual:** O balão deve ser maior, com `backdrop-blur-xl`, bordas arredondadas suaves e tipografia Inter 14px.
22-
* **Animations:** Use Tailwind v4 para criar uma entrada "Spring" (suave). Adicione um efeito de "pulsação de luz" no robô quando ele estiver "analisando dados".
23-
2. **Readability:** Garanta que o texto tenha contraste alto (Texto branco em fundo Slate-950/80).
24-
25-
### Phase 3: Strategic Behavior (Anti-Irritation)
26-
1. **Cooldown:** Implemente uma trava. O robô só aparece:
27-
* No primeiro login do dia.
28-
* OU se o usuário realizar uma transação que mude drasticamente um pilar do 50/30/20.
29-
2. **Typewriter Effect:** Adicione um efeito de "digitando" no balão para simular a resposta da IA em tempo real.
54+
### 🚀 Prompt Cursor: Criar Relatório PDF de Elite (Estilo Business Statement)
55+
56+
Para que o Cursor implemente isso para você, use este prompt detalhado:
57+
58+
```markdown
59+
@.cursorrules
60+
@Modules/Core/app/Services/ReportService.php
61+
@Modules/Core/resources/views/documents/
62+
63+
**Role:** Senior UI/UX Engineer & PDF Specialist.
64+
**Goal:** Create a world-class professional PDF template for "Consultoria PRO" and "Extratos". The design must follow the "Fintech Elite" style (Stripe/PayPal) and be optimized for A4 printing.
3065

3166
---
3267

33-
### Phase 4: Pro-Only Features
34-
1. **Diferenciação:** Para usuários FREE, o Gemini dá dicas curtas. Para usuários PRO, o Gemini faz uma análise profunda cruzando os gastos com os artigos do Blog.
68+
### Phase 1: Engine Setup (Information)
69+
1. Verifique se o sistema pode usar `Spatie/Browsershot` ou `Laravel-Snappy` para renderização via servidor. Se não for possível no ambiente atual, utilize `DomPDF` com configurações estritas de A4.
3570

36-
**Technical Constraints:**
37-
* Use FontAwesome 7.1 Pro Duotone.
38-
* Mantenha o processamento assíncrono para não travar o carregamento da página.
39-
* O robô deve sempre se identificar como "Vertex Bot - Seu Mentor de Elite".
71+
### Phase 2: Professional CSS Blueprint
72+
1. Crie um arquivo `resources/css/pdf-pro.css` ou injete no Blade:
73+
* Defina `@page { size: A4; margin: 1.5cm; }`.
74+
* Use a fonte 'Inter' ou 'Helvetica'.
75+
* Implemente classes `.break-before` e `.avoid-break`.
76+
* Garanta que as cores de fundo (bg-slate-50, etc.) sejam forçadas na impressão.
4077

41-
**Execute Phase 1 (Gemini Connection) and Phase 2 (New Design) first.**
78+
### Phase 3: High-End Layout Structure
79+
1. **Header:** Use a logo da Vertex via base64 para garantir o carregamento. Adicione o título do documento e a data de emissão em um grid elegante.
80+
2. **Typography:** O tamanho da fonte principal deve ser 10pt (padrão financeiro). Títulos em 14pt.
81+
3. **Tables:** Refatore as tabelas para terem padding generoso, bordas finas (#e2e8f0) e alinhamento decimal para valores monetários.
82+
4. **AI Conclusion:** A seção de "Conclusão Estratégica" deve vir em um box com borda lateral azul (indigo-600) para destacar a consultoria.
83+
84+
### Phase 4: Implementation
85+
1. Refatore a view `consulting-report.blade.php` para seguir este novo padrão "Business Statement".
86+
2. Remova elementos desnecessários (botões, menus de navegação) da versão de impressão.
87+
88+
---
89+
90+
**Technical Constraints:**
91+
* O PDF deve ser gerado via servidor, não pelo `window.print()` do usuário.
92+
* Garanta que o layout não "quebre" em relatórios com mais de 2 páginas.

Modules/Blog/database/seeders/BlogPostPremiumSeeder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class BlogPostPremiumSeeder extends Seeder
2525
*/
2626
public function run(): void
2727
{
28-
$author = User::where('email', 'admin@vertexcontas.com')->first();
28+
$author = User::role('admin')->first();
2929
if (! $author) {
30-
$this->command->warn('Admin user not found. Run DatabaseSeeder first.');
30+
$this->command->warn('Admin user not found. Run DatabaseSeeder (RolesAndPermissions + AdminUserSeeder) first.');
3131
return;
3232
}
3333

Modules/Blog/database/seeders/BlogPostSeeder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ class BlogPostSeeder extends Seeder
2323
*/
2424
public function run(): void
2525
{
26-
$author = User::where('email', 'admin@vertexcontas.com')->first();
26+
$author = User::role('admin')->first();
2727
if (! $author) {
28-
$this->command->warn('Admin user not found. Run DatabaseSeeder first.');
28+
$this->command->warn('Admin user not found. Run DatabaseSeeder (RolesAndPermissions + AdminUserSeeder) first.');
2929
return;
3030
}
3131

Modules/Blog/resources/views/show.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<x-icon name="crown" class="w-8 h-8 text-white" />
3232
</div>
3333
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">Conteúdo Exclusivo PRO</h2>
34-
<p class="text-gray-600 dark:text-gray-300 mb-6">Este artigo contém estratégias avançadas reservadas para assinantes Vertex PRO.</p>
34+
<p class="text-gray-600 dark:text-gray-300 mb-6">Este artigo contém estratégias avançadas reservadas para assinantes {{ plan_pro_name() }}.</p>
3535
<a href="{{ route('paneluser.subscription.index') }}" class="inline-block w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-lg transition-colors shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
3636
Desbloquear Acesso Agora
3737
</a>

Modules/Core/app/Http/Controllers/CategoryController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function create()
3333
$user = auth()->user();
3434
if (! $this->limitService->canCreate($user, 'category')) {
3535
return redirect()->route('core.categories.index')
36-
->with('error', $this->limitService->getLimitReachedMessage('category'));
36+
->with('error', $this->limitService->getLimitReachedMessage($user, 'category'));
3737
}
3838

3939
return view('core::categories.create');
@@ -44,7 +44,7 @@ public function store(StoreCategoryRequest $request)
4444
$user = auth()->user();
4545
if (! $this->limitService->canCreate($user, 'category')) {
4646
return redirect()->route('core.categories.index')
47-
->with('error', $this->limitService->getLimitReachedMessage('category'));
47+
->with('error', $this->limitService->getLimitReachedMessage($user, 'category'));
4848
}
4949

5050
$typeGroup = $request->type === 'expense' ? ($request->type_group ?? 'lifestyle') : null;

Modules/Core/app/Http/Controllers/CoreController.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,23 @@
1818
use Modules\Core\Services\FinancialHealthService;
1919
use Modules\Core\Services\InspectionGuard;
2020
use Modules\Core\Services\SubscriptionLimitService;
21+
use Modules\Core\Services\TemplateDocumentService;
2122

2223
class CoreController extends Controller
2324
{
2425
protected SubscriptionLimitService $limitService;
2526

2627
protected FinancialHealthService $financialHealthService;
2728

28-
public function __construct(SubscriptionLimitService $limitService, FinancialHealthService $financialHealthService)
29+
protected TemplateDocumentService $templateService;
30+
31+
public function __construct(SubscriptionLimitService $limitService, FinancialHealthService $financialHealthService, TemplateDocumentService $templateService)
2932
{
3033
$this->middleware(['auth', 'verified']);
3134
$this->middleware('permission:core.view');
3235
$this->limitService = $limitService;
3336
$this->financialHealthService = $financialHealthService;
37+
$this->templateService = $templateService;
3438
}
3539

3640
/**
@@ -135,6 +139,7 @@ public function dashboard()
135139

136140
// Projection data for Vertex AI card (PRO)
137141
$projectionData = $this->financialHealthService->getProjectionData($user);
142+
$aiReportUsage = $user->isPro() ? $this->templateService->getAiReportUsage($user) : null;
138143

139144
return view('core::dashboard', compact(
140145
'accounts',
@@ -152,7 +157,8 @@ public function dashboard()
152157
'recentTransactions',
153158
'monthlyCapacity',
154159
'incomeBreakdown',
155-
'projectionData'
160+
'projectionData',
161+
'aiReportUsage'
156162
));
157163
}
158164

0 commit comments

Comments
 (0)