mirror of
https://github.com/melgarafael/DeskcommCRM.git
synced 2026-10-02 01:28:34 +08:00
chore(oss): Sentry opt-in configurável + licença MIT + política de suporte/LGPD
Sentry (modelo comunidade com guardrails): - DSN deixa de ser hardcoded; resolveSentryDsn() lê SENTRY_DSN em runtime (server/edge via process.env; browser via window.__PUBLIC_ENV__) - default = Sentry da comunidade; SENTRY_DSN=off desliga; <dsn> aponta pro próprio - opt-out vale no browser sem rebuild (via PublicEnvScript) - beforeSend sanitizado (CPF/telefone/e-mail) mantido Licença: adiciona LICENSE MIT (Copyright 2026 Rafael Melgaço). README: política de suporte 'as-is', responsabilidades self-host, disclaimer LGPD (quem hospeda é o controlador) e como ligar/desligar a telemetria. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHfaYtmvsCjiKfdWDLsMdK
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c890b4030f
commit
07eb106303
@@ -92,8 +92,12 @@ RESEND_API_KEY=
|
||||
RESEND_FROM_EMAIL=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 11) Observabilidade (opcional)
|
||||
# 11) Observabilidade (Sentry) — relatórios de erro
|
||||
# -----------------------------------------------------------------------------
|
||||
# Deixe VAZIO para enviar erros anonimizados ao Sentry da comunidade (ajuda a
|
||||
# melhorar o CRM; CPF/telefone/e-mail são removidos antes do envio).
|
||||
# SENTRY_DSN=off → desliga TODA a telemetria (nada é enviado)
|
||||
# SENTRY_DSN=<seu-dsn> → envia os erros pro SEU próprio Sentry
|
||||
SENTRY_DSN=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Rafael Melgaço
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -206,7 +206,32 @@ Detalhe wave-by-wave: [`docs/stories/epics/MASTER.md`](docs/stories/epics/MASTER
|
||||
|
||||
## 📜 Licença
|
||||
|
||||
> ⚠️ **A definir.** O projeto está sendo liberado pra comunidade — a licença final (MIT, Apache-2.0, AGPL-3.0 ou outra) será definida antes do release público. Por enquanto, considere "all rights reserved" até o `LICENSE` ser commitado.
|
||||
Distribuído sob a licença **MIT** — veja [`LICENSE`](LICENSE). Você pode usar, modificar
|
||||
e distribuir livremente, inclusive comercialmente. O software é fornecido **"como está",
|
||||
sem garantias** (ver cláusula de isenção no `LICENSE`).
|
||||
|
||||
---
|
||||
|
||||
## 🛟 Suporte & responsabilidades (self-host)
|
||||
|
||||
Este é um projeto **self-host**: cada pessoa roda o CRM na **própria infraestrutura**
|
||||
(VPS, banco Supabase e chave de IA próprios). Isso implica:
|
||||
|
||||
- **Suporte é comunitário e "as-is".** Dúvidas e bugs entram como
|
||||
[Issues](https://github.com/melgarafael/DeskcommCRM/issues) ou
|
||||
[Discussions](https://github.com/melgarafael/DeskcommCRM/discussions). Não há SLA nem
|
||||
suporte garantido — é open source mantido por boa vontade.
|
||||
- **Você é responsável pela sua instalação.** Atualizações não são automáticas
|
||||
(`bash hostgator-setup-kit/update.sh` quando quiser), e manter/backup do seu servidor
|
||||
é com você.
|
||||
- **LGPD — atenção:** quem **hospeda** a instância é o **controlador** dos dados pessoais
|
||||
ali tratados (clientes, conversas, pedidos), com as obrigações legais decorrentes. Os
|
||||
mantenedores do projeto **não têm acesso** aos seus dados e **não são** controladores
|
||||
nem operadores da sua instância.
|
||||
- **Telemetria (Sentry):** por padrão, erros **anonimizados** (CPF/telefone/e-mail
|
||||
removidos) são enviados ao Sentry da comunidade pra ajudar a corrigir bugs que afetam
|
||||
todos. Para **desligar**, use `SENTRY_DSN=off` no `.env`; para enviar ao **seu** Sentry,
|
||||
use `SENTRY_DSN=<seu-dsn>`. Ver [`lib/sentry/dsn.ts`](lib/sentry/dsn.ts).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ export async function PublicEnvScript() {
|
||||
const payload = JSON.stringify({
|
||||
NEXT_PUBLIC_SUPABASE_URL: env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
// Exposto pro Sentry do browser respeitar o opt-out (SENTRY_DSN=off) em runtime,
|
||||
// sem rebuild. DSN não é segredo. Ver lib/sentry/dsn.ts.
|
||||
SENTRY_DSN: env.SENTRY_DSN,
|
||||
})
|
||||
// Evita quebrar o </script> se algum valor contiver a sequência.
|
||||
.replace(/</g, "\\u003c");
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { resolveSentryDsn } from "./lib/sentry/dsn";
|
||||
|
||||
const SENSITIVE_HEADERS = [
|
||||
"authorization",
|
||||
@@ -21,7 +22,9 @@ function scrubMessage(input: string): string {
|
||||
}
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://58fabf8ad54504863d404a3647ef3714@o4509908078559232.ingest.us.sentry.io/4509908083212288",
|
||||
dsn: resolveSentryDsn(
|
||||
typeof window !== "undefined" ? window.__PUBLIC_ENV__?.SENTRY_DSN : undefined,
|
||||
),
|
||||
|
||||
integrations: [Sentry.replayIntegration()],
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* DSN do Sentry com opt-out em runtime — modelo "telemetria de comunidade".
|
||||
*
|
||||
* Por padrão, erros vão pro Sentry do projeto (DEFAULT_SENTRY_DSN): num open source
|
||||
* self-host, é o que dá visibilidade pra corrigir bugs que afetam todo mundo. Quem
|
||||
* hospeda controla isso pelo `.env`, SEM rebuild da imagem:
|
||||
*
|
||||
* SENTRY_DSN=off → desliga toda a telemetria (nada é enviado)
|
||||
* SENTRY_DSN=<seu-dsn> → manda os erros pro SEU Sentry
|
||||
* SENTRY_DSN= (vazio) → usa o Sentry da comunidade (padrão)
|
||||
*
|
||||
* Vale para servidor (process.env) e navegador (window.__PUBLIC_ENV__.SENTRY_DSN,
|
||||
* injetado em runtime pelo <PublicEnvScript/>). O DSN não é segredo — DSNs do Sentry
|
||||
* são públicos por design.
|
||||
*/
|
||||
export const DEFAULT_SENTRY_DSN =
|
||||
"https://58fabf8ad54504863d404a3647ef3714@o4509908078559232.ingest.us.sentry.io/4509908083212288";
|
||||
|
||||
export function resolveSentryDsn(value: string | undefined | null): string | undefined {
|
||||
const v = (value ?? "").trim().toLowerCase() === "off" ? "off" : (value ?? "").trim();
|
||||
if (v === "off" || v === "false" || v === "0") return undefined;
|
||||
return v.length > 0 ? v : DEFAULT_SENTRY_DSN;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { resolveSentryDsn } from "./lib/sentry/dsn";
|
||||
|
||||
const SENSITIVE_HEADERS = [
|
||||
"authorization",
|
||||
@@ -20,7 +21,7 @@ function scrubMessage(input: string): string {
|
||||
}
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://58fabf8ad54504863d404a3647ef3714@o4509908078559232.ingest.us.sentry.io/4509908083212288",
|
||||
dsn: resolveSentryDsn(process.env.SENTRY_DSN),
|
||||
|
||||
tracesSampleRate: 1,
|
||||
enableLogs: true,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { resolveSentryDsn } from "./lib/sentry/dsn";
|
||||
|
||||
const SENSITIVE_HEADERS = [
|
||||
"authorization",
|
||||
@@ -21,7 +22,7 @@ function scrubMessage(input: string): string {
|
||||
}
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://58fabf8ad54504863d404a3647ef3714@o4509908078559232.ingest.us.sentry.io/4509908083212288",
|
||||
dsn: resolveSentryDsn(process.env.SENTRY_DSN),
|
||||
|
||||
tracesSampleRate: 1,
|
||||
enableLogs: true,
|
||||
|
||||
Vendored
+1
@@ -9,6 +9,7 @@
|
||||
interface PublicEnv {
|
||||
NEXT_PUBLIC_SUPABASE_URL?: string;
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY?: string;
|
||||
SENTRY_DSN?: string;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
||||
Reference in New Issue
Block a user