Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 80 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,80 @@
OPENAI_API_KEY=your_key_here
# Escolha um provedor (opcional): openai | anthropic | google
# Se não definir, usa o primeiro com chave configurada.
# DARSHAN_AI_PROVIDER=openai

# ========== USO GRATUITO (recomendado para dev) ==========
# Google Gemini tem tier gratuito com limite de requisições/dia.
# 1. Acesse https://aistudio.google.com/apikey
# 2. Crie uma API key (conta Google)
# 3. Defina só a chave abaixo; o app usará Gemini automaticamente.
# GOOGLE_AI_API_KEY=sua_chave_gemini_aqui
# DARSHAN_AI_PROVIDER=google

# ========== OpenAI (GPT) – pago após créditos iniciais ==========
# OPENAI_API_KEY=your_openai_key_here
# OPENAI_MODEL=gpt-4o-mini

# ========== Anthropic (Claude) – pago ==========
# ANTHROPIC_API_KEY=your_anthropic_key_here
# ANTHROPIC_MODEL=claude-sonnet-4-20250514

# ========== Google (Gemini) – tier gratuito disponível ==========
# GOOGLE_AI_API_KEY=your_google_key_here
# GOOGLE_MODEL=gemini-2.5-flash

# ========== Configuração editável (sementes da IA) ==========
# Chave para acessar /config e GET|PUT /api/config. Defina para usar a página de configuração.
# CONFIG_SECRET=your_secret_key_here
# Pasta onde será criado data/config.json (opcional; padrão: ./data)
# DATA_DIR=./data

# ========== reCAPTCHA v2 (página /config) ==========
# Chaves em https://www.google.com/recaptcha/admin (tipo reCAPTCHA v2 "Não sou um robô").
# Se não definir, a página /config aceita apenas o código secreto (sem captcha).
# NEXT_PUBLIC_RECAPTCHA_SITE_KEY=your_site_key_here
# RECAPTCHA_SECRET_KEY=your_secret_key_here

# ========== Log e auditoria ==========
# Pasta base para logs (app.log e audit.log em <LOG_DIR>/logs/). Se não definir, usa DATA_DIR ou ./data.
# LOG_DIR=./data
# Nível mínimo de log: debug | info | warn | error (em produção o padrão é info).
# LOG_LEVEL=info

# ========== Login com Google (SSO) ==========
# Crie credenciais em https://console.cloud.google.com/apis/credentials (tipo "Aplicativo da Web").
# URIs de redirecionamento autorizados: https://seu-dominio.com/api/auth/callback/google e http://localhost:3000/api/auth/callback/google
# GOOGLE_CLIENT_ID=your_google_oauth_client_id
# GOOGLE_CLIENT_SECRET=your_google_oauth_client_secret

# ========== E-mail (Resend) – código de login ==========
# Em produção, send-code envia o código por e-mail. Crie API key em https://resend.com
# RESEND_API_KEY=re_xxxxxxxxxxxx
# E-mail remetente (domínio verificado no Resend)
# RESEND_FROM=Darshan <noreply@seu-dominio.com>

# ========== Pagamento (Stripe Checkout – cartão, Google Pay, Link) ==========
# Chave secreta em https://dashboard.stripe.com/apikeys. Em checkout/create, defina success/cancel URLs.
# STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxx
# Webhook: em https://dashboard.stripe.com/webhooks adicione o endpoint (ex.: https://seu-dominio.com/api/webhooks/stripe)
# e selecione o evento checkout.session.completed. Use o signing secret (whsec_...) em STRIPE_WEBHOOK_SECRET.
# STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx

# ========== Pagamento (Mercado Pago – PIX, cartão, etc.) ==========
# Access Token em https://www.mercadopago.com.br/developers/panel/app (credenciais da aplicação).
# O modal de créditos tenta Mercado Pago primeiro; se não configurado, usa Stripe.
# MERCADOPAGO_ACCESS_TOKEN=APP_USR-xxxxxxxxxxxx

# ========== Taxa da plataforma (margem) ==========
# Percentual 0–100 usado em descrições e meta de custo IA vs faturamento. Padrão: 30.
# PLATFORM_FEE_PERCENT=30

# ========== Limites de consumo de IA (docs/PRECIFICACAO_CREDITOS.md) ==========
# Requisições por minuto por usuário. 0 = desativado. Padrão: 5.
# RATE_LIMIT_PER_MINUTE=5
# Respostas de IA por dia por usuário. 0 = desativado. Padrão: 30.
# DAILY_AI_LIMIT=30

# ========== Módulo financeiro (Supabase) ==========
# Para log de uso de IA, ledger de créditos e exportação CSV. Sem isso, créditos continuam só em cookie.
# SUPABASE_URL=https://seu-projeto.supabase.co
# SUPABASE_SERVICE_KEY=eyJhbG... (service role key no Dashboard > Settings > API)
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals"]
}
78 changes: 78 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Esteira CI: lint, test e build em todo push e PR
name: CI

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

defaults:
run:
working-directory: .

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install
run: npm ci

- name: Lint
run: npm run lint

test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install
run: npm ci

- name: Test
run: npm run test

build:
name: Build
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install
run: npm ci

- name: Build
run: npm run build
env:
# Build sem env sensíveis; variáveis vazias para não quebrar
NEXT_PUBLIC_VERCEL_URL: ""

- name: Upload build
uses: actions/upload-artifact@v4
with:
name: build
path: build/
retention-days: 1
86 changes: 86 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Esteira Deploy: push em main → build + deploy Vercel (produção)
name: Deploy

on:
push:
branches: [main, master]
workflow_dispatch:

defaults:
run:
working-directory: .

env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

jobs:
deploy:
name: Build & Deploy (Vercel)
runs-on: ubuntu-latest
steps:
- name: Check secrets
id: secrets
run: |
if [ -z "${{ secrets.VERCEL_TOKEN }}" ]; then
echo "::error title=Secret ausente::VERCEL_TOKEN não configurado. Em Settings > Secrets and variables > Actions, adicione VERCEL_TOKEN (token em https://vercel.com/account/tokens)."
echo "ok=false" >> $GITHUB_OUTPUT
elif [ -z "${{ secrets.VERCEL_ORG_ID }}" ]; then
echo "::error title=Secret ausente::VERCEL_ORG_ID não configurado. Obtenha em Vercel Dashboard > Settings do projeto (ou vercel link)."
echo "ok=false" >> $GITHUB_OUTPUT
elif [ -z "${{ secrets.VERCEL_PROJECT_ID }}" ]; then
echo "::error title=Secret ausente::VERCEL_PROJECT_ID não configurado. Obtenha em Vercel Dashboard > Settings do projeto."
echo "ok=false" >> $GITHUB_OUTPUT
else
echo "ok=true" >> $GITHUB_OUTPUT
fi

- name: Checkout
if: steps.secrets.outputs.ok == 'true'
uses: actions/checkout@v4

- name: Setup Node
if: steps.secrets.outputs.ok == 'true'
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Restore Next.js cache
if: steps.secrets.outputs.ok == 'true'
uses: actions/cache@v4
with:
path: .next/cache
key: next-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx', '!node_modules/**') }}
restore-keys: |
next-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-

- name: Install
if: steps.secrets.outputs.ok == 'true'
run: npm ci

- name: Build
if: steps.secrets.outputs.ok == 'true'
run: npm run build
env:
NEXT_PUBLIC_VERCEL_URL: ""

- name: Deploy to Vercel (production)
if: steps.secrets.outputs.ok == 'true'
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: ./
vercel-args: "--prod"

- name: Fail (secrets ausentes)
if: steps.secrets.outputs.ok != 'true'
run: |
echo "Configure os secrets do repositório (Settings > Secrets and variables > Actions):"
echo " - VERCEL_TOKEN"
echo " - VERCEL_ORG_ID"
echo " - VERCEL_PROJECT_ID"
echo "Ver docs/DEPLOY_WORKFLOWS.md para obter os valores."
exit 1
103 changes: 103 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Esteira Release: build + artefato + deploy (falha se config ausente)
name: Release

on:
release:
types: [published]
push:
tags:
- "v*"

jobs:
build-and-bundle:
name: Build & Bundle
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install
run: npm ci

- name: Get version
id: version
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT

- name: Build
run: npm run build
env:
NEXT_PUBLIC_VERCEL_URL: ""

- name: Bundle artifact
run: node scripts/bundle-artifact.js --no-archive

- name: Create archive
run: |
VERSION=${{ steps.version.outputs.version }}
FOLDER=$(ls -d dist/darshan-* 2>/dev/null | head -1)
if [ -z "$FOLDER" ]; then echo "Pasta do artefato não encontrada"; exit 1; fi
BASENAME=$(basename "$FOLDER")
tar czf "dist/darshan-${VERSION}.tar.gz" -C dist "$BASENAME"
echo "ARTIFACT_PATH=dist/darshan-${VERSION}.tar.gz" >> $GITHUB_ENV

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: release-artifact
path: dist/darshan-*.tar.gz
retention-days: 30

# Deploy opcional: só roda se VERCEL_* estiverem configurados (release/tag)
deploy:
name: Deploy (Vercel)
runs-on: ubuntu-latest
needs: build-and-bundle
if: success()
steps:
- name: Check deploy config
id: check
run: |
if [ -n "${{ secrets.VERCEL_TOKEN }}" ] && [ -n "${{ secrets.VERCEL_ORG_ID }}" ] && [ -n "${{ secrets.VERCEL_PROJECT_ID }}" ]; then
echo "skip=false" >> $GITHUB_OUTPUT
else
echo "skip=true" >> $GITHUB_OUTPUT
fi

- name: Checkout
if: steps.check.outputs.skip != 'true'
uses: actions/checkout@v4

- name: Setup Node
if: steps.check.outputs.skip != 'true'
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install & Build
if: steps.check.outputs.skip != 'true'
run: npm ci && npm run build
env:
NEXT_PUBLIC_VERCEL_URL: ""

- name: Deploy to Vercel (production)
if: steps.check.outputs.skip != 'true'
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: ./
vercel-args: "--prod"

- name: Deploy skipped (secrets ausentes)
if: steps.check.outputs.skip == 'true'
run: |
echo "::notice title=Deploy não executado::Para deploy em release/tag, configure VERCEL_TOKEN, VERCEL_ORG_ID e VERCEL_PROJECT_ID. Ver docs/DEPLOY_WORKFLOWS.md"
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
node_modules
.next
build
dist
.env
.env.local
.env.production
.DS_Store
coverage
data
tsconfig.tsbuildinfo
build.log
*.log
Loading