@danhachuel/prodmaker 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/MANUAL-INSTALACAO.md +68 -0
- package/README.md +42 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/app/__init__.py +1 -0
- package/app/main.py +324 -0
- package/frontend/dist/assets/index-COSPz2F9.css +1 -0
- package/frontend/dist/assets/index-CoHrpz8h.js +67 -0
- package/frontend/dist/index.html +23 -0
- package/legal/index.html +58 -0
- package/legal/privacy.html +67 -0
- package/legal/terms.html +57 -0
- package/package.json +41 -4
- package/requirements.txt +4 -0
- package/scripts/cli.mjs +249 -0
- package/seed/campaign-defaults/google.json +24 -0
- package/seed/campaign-defaults/meta.json +18 -0
- package/seed/campaign-defaults/pinterest.json +8 -0
- package/seed/campaign-defaults/tiktok.json +14 -0
- package/seed/checklists/lancamento.md +29 -0
- package/seed/decision-rules/otimizacao.json +12 -0
- package/seed/negatives/google-words.txt +20 -0
- package/seed/prompts/criativos.md +12 -0
- package/seed/prompts/infoproduto.md +23 -0
- package/seed/prompts/keywords.md +12 -0
- package/seed/prompts/pagina-vendas.md +24 -0
- package/seed/prompts/pins.md +15 -0
- package/seed/prompts/pre-sell.md +18 -0
package/legal/index.html
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ProdMaker — Verificação de Aplicação</title>
|
|
7
|
+
<style>
|
|
8
|
+
*{margin:0;padding:0;box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
|
|
9
|
+
body{background:#f8fafc;color:#1e293b;line-height:1.6}
|
|
10
|
+
.container{max-width:820px;margin:0 auto;padding:48px 24px}
|
|
11
|
+
h1{color:#7C3AED;margin-bottom:8px;font-size:32px}
|
|
12
|
+
h2{margin-top:32px;margin-bottom:12px;font-size:20px}
|
|
13
|
+
p{margin-bottom:14px;color:#334155}
|
|
14
|
+
.card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:24px;margin:20px 0}
|
|
15
|
+
.badge{display:inline-block;background:#f3e8ff;color:#7C3AED;padding:4px 12px;border-radius:20px;font-size:13px;font-weight:600;margin-bottom:16px}
|
|
16
|
+
ul{padding-left:20px;color:#334155}
|
|
17
|
+
li{margin-bottom:6px}
|
|
18
|
+
a{color:#7C3AED}
|
|
19
|
+
footer{margin-top:40px;padding-top:20px;border-top:1px solid #e2e8f0;font-size:13px;color:#64748b}
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<div class="container">
|
|
24
|
+
<span class="badge">Página de verificação de aplicação</span>
|
|
25
|
+
<h1>🚀 ProdMaker</h1>
|
|
26
|
+
<p>O <strong>ProdMaker</strong> é uma ferramenta <strong>local</strong> de criação de infoprodutos,
|
|
27
|
+
geração de landing pages e gestão de campanhas de tráfego pago e orgânico, executada no
|
|
28
|
+
próprio computador do usuário via <code>npx</code> e acessada pelo navegador em
|
|
29
|
+
<code>http://localhost:8188</code>.</p>
|
|
30
|
+
|
|
31
|
+
<div class="card">
|
|
32
|
+
<h2>Integrações oficiais</h2>
|
|
33
|
+
<ul>
|
|
34
|
+
<li>Google Ads (campanhas Search e conversões offline via GCLID)</li>
|
|
35
|
+
<li>Meta Ads (Facebook/Instagram — Marketing API)</li>
|
|
36
|
+
<li>TikTok Ads (TikTok Business API)</li>
|
|
37
|
+
<li>Pinterest (criação e agendamento de Pins)</li>
|
|
38
|
+
<li>Gamma AI (geração premium de documentos)</li>
|
|
39
|
+
<li>NVIDIA NIM e Google Gemini (modelos de linguagem via API)</li>
|
|
40
|
+
<li>GitHub e Cloudflare Pages (publicação de páginas geradas)</li>
|
|
41
|
+
</ul>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="card">
|
|
45
|
+
<h2>Aviso de verificação</h2>
|
|
46
|
+
<p>Esta página existe para <strong>verificação da aplicação junto às plataformas</strong>
|
|
47
|
+
(Google, Meta, TikTok e outras) durante os processos de revisão de app. O ProdMaker
|
|
48
|
+
opera localmente; nenhuma informação de terceiros é coletada por este site.</p>
|
|
49
|
+
<ul>
|
|
50
|
+
<li><a href="privacy.html">Política de Privacidade (LGPD)</a></li>
|
|
51
|
+
<li><a href="terms.html">Termos de Serviço</a></li>
|
|
52
|
+
</ul>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<footer>© 2026 ProdMaker. Todos os direitos reservados.</footer>
|
|
56
|
+
</div>
|
|
57
|
+
</body>
|
|
58
|
+
</html>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ProdMaker — Política de Privacidade</title>
|
|
7
|
+
<style>
|
|
8
|
+
*{margin:0;padding:0;box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
|
|
9
|
+
body{background:#f8fafc;color:#1e293b;line-height:1.6}
|
|
10
|
+
.container{max-width:820px;margin:0 auto;padding:48px 24px}
|
|
11
|
+
h1{color:#7C3AED;margin-bottom:8px;font-size:28px}
|
|
12
|
+
h2{margin-top:28px;margin-bottom:10px;font-size:18px}
|
|
13
|
+
p,li{color:#334155;margin-bottom:10px}
|
|
14
|
+
ul{padding-left:20px}
|
|
15
|
+
a{color:#7C3AED}
|
|
16
|
+
footer{margin-top:40px;padding-top:20px;border-top:1px solid #e2e8f0;font-size:13px;color:#64748b}
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<div class="container">
|
|
21
|
+
<h1>Política de Privacidade</h1>
|
|
22
|
+
<p>Esta política descreve como o <strong>ProdMaker</strong> — aplicação local de criação de
|
|
23
|
+
infoprodutos e gestão de campanhas — trata dados pessoais, em conformidade com a
|
|
24
|
+
<strong>Lei Geral de Proteção de Dados (LGPD — Lei 13.709/2018)</strong>.</p>
|
|
25
|
+
|
|
26
|
+
<h2>1. Natureza local da aplicação</h2>
|
|
27
|
+
<p>O ProdMaker é executado localmente no computador do usuário. Os dados descritos abaixo
|
|
28
|
+
são armazenados <strong>exclusivamente no dispositivo do usuário</strong>, na pasta
|
|
29
|
+
<code>PRODMAKER_HOME/storage</code>, e não são transmitidos aos desenvolvedores.</p>
|
|
30
|
+
|
|
31
|
+
<h2>2. Dados tratados</h2>
|
|
32
|
+
<ul>
|
|
33
|
+
<li><strong>Tokens de API e credenciais de plataformas</strong> (Google Ads, Meta, TikTok,
|
|
34
|
+
Pinterest, GitHub, Cloudflare, Gamma, NVIDIA, Google Gemini): inseridos pelo próprio
|
|
35
|
+
usuário, guardados localmente e utilizados apenas para executar as ações solicitadas
|
|
36
|
+
(criação de campanhas, publicação de páginas etc.).</li>
|
|
37
|
+
<li><strong>Dados de conversão e rastreamento</strong> (GCLID, cliques, visitas, vendas):
|
|
38
|
+
coletados pelo pixel próprio nas páginas geradas pelo usuário e usados exclusivamente
|
|
39
|
+
para otimização das campanhas do próprio usuário.</li>
|
|
40
|
+
<li><strong>Conteúdo processado por LLMs</strong>: textos enviados pelo usuário aos
|
|
41
|
+
provedores de IA configurados (NVIDIA NIM e/ou Google Gemini) são regidos pelas
|
|
42
|
+
políticas de privacidade desses provedores.</li>
|
|
43
|
+
<li><strong>E-mail e código de ativação</strong>: usados apenas para a sessão local;
|
|
44
|
+
a validação ocorre no próprio dispositivo.</li>
|
|
45
|
+
</ul>
|
|
46
|
+
|
|
47
|
+
<h2>3. Finalidade e base legal</h2>
|
|
48
|
+
<p>O tratamento ocorre exclusivamente para execução das funcionalidades solicitadas pelo
|
|
49
|
+
titular (art. 7º, V e X da LGPD — execução de políticas e cumprimento de solicitação do titular).</p>
|
|
50
|
+
|
|
51
|
+
<h2>4. Compartilhamento</h2>
|
|
52
|
+
<p>O ProdMaker não compartilha dados com terceiros. As credenciais e conteúdos são enviados
|
|
53
|
+
somente às plataformas explicitamente integradas pelo usuário, quando o próprio usuário
|
|
54
|
+
aciona as ações correspondentes.</p>
|
|
55
|
+
|
|
56
|
+
<h2>5. Direitos do titular</h2>
|
|
57
|
+
<p>Como todos os dados ficam no dispositivo do usuário, o titular pode visualizar, corrigir
|
|
58
|
+
ou apagar seus dados a qualquer momento excluindo/editando os arquivos em
|
|
59
|
+
<code>PRODMAKER_HOME/storage</code>.</p>
|
|
60
|
+
|
|
61
|
+
<h2>6. Contato</h2>
|
|
62
|
+
<p>Dúvidas sobre esta política devem ser abertas no repositório oficial do projeto.</p>
|
|
63
|
+
|
|
64
|
+
<footer>© 2026 ProdMaker · <a href="index.html">Início</a> · <a href="terms.html">Termos de Serviço</a></footer>
|
|
65
|
+
</div>
|
|
66
|
+
</body>
|
|
67
|
+
</html>
|
package/legal/terms.html
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ProdMaker — Termos de Serviço</title>
|
|
7
|
+
<style>
|
|
8
|
+
*{margin:0;padding:0;box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
|
|
9
|
+
body{background:#f8fafc;color:#1e293b;line-height:1.6}
|
|
10
|
+
.container{max-width:820px;margin:0 auto;padding:48px 24px}
|
|
11
|
+
h1{color:#7C3AED;margin-bottom:8px;font-size:28px}
|
|
12
|
+
h2{margin-top:28px;margin-bottom:10px;font-size:18px}
|
|
13
|
+
p,li{color:#334155;margin-bottom:10px}
|
|
14
|
+
ul{padding-left:20px}
|
|
15
|
+
a{color:#7C3AED}
|
|
16
|
+
footer{margin-top:40px;padding-top:20px;border-top:1px solid #e2e8f0;font-size:13px;color:#64748b}
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<div class="container">
|
|
21
|
+
<h1>Termos de Serviço</h1>
|
|
22
|
+
|
|
23
|
+
<h2>1. Natureza da ferramenta</h2>
|
|
24
|
+
<p>O <strong>ProdMaker</strong> é uma aplicação local que auxilia na criação de infoprodutos,
|
|
25
|
+
landing pages e campanhas de tráfego. A ferramenta atua como automação sobre plataformas
|
|
26
|
+
de terceiros (Google Ads, Meta Ads, TikTok Ads, Pinterest, GitHub/Cloudflare, provedores
|
|
27
|
+
de IA), sempre sob comando e com credenciais fornecidas pelo próprio usuário.</p>
|
|
28
|
+
|
|
29
|
+
<h2>2. Responsabilidade do usuário</h2>
|
|
30
|
+
<ul>
|
|
31
|
+
<li>O usuário é o <strong>único responsável</strong> pelo cumprimento das políticas,
|
|
32
|
+
termos e diretrizes de cada plataforma utilizada (Google, Meta, TikTok, Pinterest e outras).</li>
|
|
33
|
+
<li>O usuário é o único responsável pelas <strong>credenciais fornecidas</strong> (tokens
|
|
34
|
+
de API, contas de anúncios, cookies de sessão) e pelos conteúdos publicados.</li>
|
|
35
|
+
<li>O ProdMaker <strong>não se responsabiliza</strong> por bloqueios, suspensões,
|
|
36
|
+
rejeições ou limitações de contas de anúncios ou de qualquer plataforma resultantes do
|
|
37
|
+
uso da ferramenta, incluindo moderação de anúncios, políticas de conteúdo ou alterações
|
|
38
|
+
unilaterais das plataformas.</li>
|
|
39
|
+
</ul>
|
|
40
|
+
|
|
41
|
+
<h2>3. Sem garantias de resultados</h2>
|
|
42
|
+
<p>O ProdMaker fornece automação e sugestões baseadas em boas práticas de marketing
|
|
43
|
+
(métricas como ROAS, CPA, CTR). Resultados de vendas, alcance ou desempenho não são
|
|
44
|
+
garantidos e dependem de fatores fora do controle da ferramenta.</p>
|
|
45
|
+
|
|
46
|
+
<h2>4. Limitação de responsabilidade</h2>
|
|
47
|
+
<p>Na máxima extensão permitida pela lei, o ProdMaker é fornecido "no estado em que se
|
|
48
|
+
encontra" (AS IS), sem garantias implícitas de qualquer espécie. O uso é por conta e
|
|
49
|
+
risco do usuário.</p>
|
|
50
|
+
|
|
51
|
+
<h2>5. Alterações</h2>
|
|
52
|
+
<p>Estes termos podem ser atualizados em novas versões do produto.</p>
|
|
53
|
+
|
|
54
|
+
<footer>© 2026 ProdMaker · <a href="index.html">Início</a> · <a href="privacy.html">Política de Privacidade</a></footer>
|
|
55
|
+
</div>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danhachuel/prodmaker",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "ProdMaker — SaaS local para criação de infoprodutos, landing pages, campanhas e tracking (base AdsX).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"prodmaker": "scripts/cli.mjs"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=20"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"scripts/",
|
|
15
|
+
"app/",
|
|
16
|
+
"seed/",
|
|
17
|
+
"legal/",
|
|
18
|
+
"frontend/dist/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"CHANGELOG.md",
|
|
21
|
+
"MANUAL-INSTALACAO.md",
|
|
22
|
+
"THIRD-PARTY-NOTICES.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"requirements.txt"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"start": "node scripts/cli.mjs",
|
|
28
|
+
"install-app": "node scripts/cli.mjs install",
|
|
29
|
+
"doctor": "node scripts/cli.mjs doctor"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/DanHachuel/ProdMaker.git"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"prodmaker",
|
|
37
|
+
"infoprodutos",
|
|
38
|
+
"ads",
|
|
39
|
+
"landing-pages",
|
|
40
|
+
"local-saas"
|
|
41
|
+
],
|
|
42
|
+
"author": "Dan Pariente Hachuel"
|
|
43
|
+
}
|
package/requirements.txt
ADDED
package/scripts/cli.mjs
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* ProdMaker launcher — install | run | doctor
|
|
3
|
+
* REGRA ZERO: este launcher NUNCA abre o navegador. Apenas imprime a URL.
|
|
4
|
+
*/
|
|
5
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import net from "node:net";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import process from "node:process";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const PKG_ROOT = path.resolve(__dirname, "..");
|
|
15
|
+
const APP_DIR = path.join(PKG_ROOT, "app");
|
|
16
|
+
const REQUIREMENTS = path.join(PKG_ROOT, "requirements.txt");
|
|
17
|
+
const APP_VERSION = "0.1.01";
|
|
18
|
+
const DEFAULT_PORT = 8188;
|
|
19
|
+
|
|
20
|
+
const STORAGE_FOLDERS = ["state", "pages", "produtos", "artifacts", "downloads", "logs"];
|
|
21
|
+
const DESIGNATED_HOME = "C:\\Users\\danha\\Documents\\REPOSITORIO\\ProdMaker";
|
|
22
|
+
|
|
23
|
+
const DEFAULT_SETTINGS = {
|
|
24
|
+
schema: 1,
|
|
25
|
+
port: DEFAULT_PORT,
|
|
26
|
+
language: "pt-BR",
|
|
27
|
+
theme: "light",
|
|
28
|
+
api_keys: {},
|
|
29
|
+
llm: { providers: [] },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function resolveHome() {
|
|
33
|
+
if (process.env.PRODMAKER_HOME) return path.resolve(process.env.PRODMAKER_HOME);
|
|
34
|
+
try {
|
|
35
|
+
if (fs.existsSync(DESIGNATED_HOME)) return path.resolve(DESIGNATED_HOME);
|
|
36
|
+
} catch {}
|
|
37
|
+
return path.join(os.homedir(), "ProdMaker");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function storagePath(home, ...parts) {
|
|
41
|
+
return path.join(home, "storage", ...parts);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ensureInstallSkeleton(home) {
|
|
45
|
+
fs.mkdirSync(home, { recursive: true });
|
|
46
|
+
for (const folder of STORAGE_FOLDERS) {
|
|
47
|
+
fs.mkdirSync(storagePath(home, folder), { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
const settingsPath = storagePath(home, "state", "settings.json");
|
|
50
|
+
if (!fs.existsSync(settingsPath)) {
|
|
51
|
+
fs.writeFileSync(settingsPath, JSON.stringify(DEFAULT_SETTINGS, null, 2), "utf8");
|
|
52
|
+
}
|
|
53
|
+
return settingsPath;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function findSystemPython() {
|
|
57
|
+
const candidates =
|
|
58
|
+
process.platform === "win32"
|
|
59
|
+
? ["py", "python", "python3"]
|
|
60
|
+
: ["python3", "python"];
|
|
61
|
+
for (const candidate of candidates) {
|
|
62
|
+
try {
|
|
63
|
+
const result = spawnSync(candidate, process.platform === "win32" && candidate === "py" ? ["-3", "--version"] : ["--version"], {
|
|
64
|
+
encoding: "utf8",
|
|
65
|
+
shell: process.platform === "win32",
|
|
66
|
+
});
|
|
67
|
+
if (result.status === 0) return candidate;
|
|
68
|
+
} catch {}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function venvPython(home) {
|
|
74
|
+
const exe = process.platform === "win32" ? "Scripts\\python.exe" : "bin/python";
|
|
75
|
+
const candidate = path.join(home, "venv", ...exe.split(/[\\/]/));
|
|
76
|
+
return fs.existsSync(candidate) ? candidate : null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function printUrlBox(port) {
|
|
80
|
+
const url = `http://localhost:${port}`;
|
|
81
|
+
console.log("");
|
|
82
|
+
console.log("┌─────────────────────────────────────────────┐");
|
|
83
|
+
console.log("│ ProdMaker rodando em: │");
|
|
84
|
+
console.log(`│ >>> ${url} ${" ".repeat(Math.max(0, 24 - url.length))}│`);
|
|
85
|
+
console.log("│ Abra esta URL MANUALMENTE no navegador. │");
|
|
86
|
+
console.log("└─────────────────────────────────────────────┘");
|
|
87
|
+
console.log("");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isPortFree(port) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
const server = net.createServer();
|
|
93
|
+
server.once("error", () => resolve(false));
|
|
94
|
+
server.once("listening", () => server.close(() => resolve(true)));
|
|
95
|
+
server.listen(port, "127.0.0.1");
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function pickPort(preferred) {
|
|
100
|
+
for (let port = preferred; port <= preferred + 11; port += 1) {
|
|
101
|
+
if (await isPortFree(port)) return port;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function runCommand(cmd, args, options = {}) {
|
|
107
|
+
const child = spawn(cmd, args, { stdio: "inherit", shell: process.platform === "win32", ...options });
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
child.on("close", (code) => resolve(code ?? 0));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function commandInstall(flags) {
|
|
114
|
+
const home = resolveHome();
|
|
115
|
+
console.log(`ProdMaker ${APP_VERSION} — install`);
|
|
116
|
+
console.log(`Pasta de dados (PRODMAKER_HOME): ${home}`);
|
|
117
|
+
const settingsPath = ensureInstallSkeleton(home);
|
|
118
|
+
console.log(`Storage pronto. Settings: ${settingsPath}`);
|
|
119
|
+
|
|
120
|
+
if (flags.skipPythonDeps) {
|
|
121
|
+
console.log(" (--skip-python-deps) Dependências Python ignoradas.");
|
|
122
|
+
} else {
|
|
123
|
+
const base = findSystemPython();
|
|
124
|
+
if (!base) {
|
|
125
|
+
console.error("Python 3.10+ não encontrado. Instale o Python e rode 'prodmaker install' novamente.");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const venvDir = path.join(home, "venv");
|
|
129
|
+
if (!venvPython(home)) {
|
|
130
|
+
console.log("Criando ambiente virtual Python...");
|
|
131
|
+
const venvArgs = process.platform === "win32" && base === "py" ? ["-3", "-m", "venv", venvDir] : ["-m", "venv", venvDir];
|
|
132
|
+
const code = await runCommand(base, venvArgs);
|
|
133
|
+
if (code !== 0) {
|
|
134
|
+
console.error("Falha ao criar o venv.");
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const python = venvPython(home);
|
|
139
|
+
console.log("Instalando dependências Python (requirements.txt)...");
|
|
140
|
+
const code = await runCommand(python, ["-m", "pip", "install", "--upgrade", "pip"]);
|
|
141
|
+
const code2 = await runCommand(python, ["-m", "pip", "install", "-r", REQUIREMENTS]);
|
|
142
|
+
if (code2 !== 0) {
|
|
143
|
+
console.error("Falha ao instalar dependências Python.");
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log("");
|
|
149
|
+
console.log("Instalação concluída. Para iniciar:");
|
|
150
|
+
console.log(" npx --yes @danhachuel/prodmaker");
|
|
151
|
+
console.log("Depois abra http://localhost:8188 MANUALMENTE no navegador (o sistema nunca abre o navegador).");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function commandRun() {
|
|
155
|
+
const home = resolveHome();
|
|
156
|
+
const settingsPath = storagePath(home, "state", "settings.json");
|
|
157
|
+
if (!fs.existsSync(settingsPath)) {
|
|
158
|
+
console.error("ProdMaker ainda não está instalado. Rode primeiro: prodmaker install");
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
let preferred = DEFAULT_PORT;
|
|
162
|
+
try {
|
|
163
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
164
|
+
if (Number.isInteger(settings.port)) preferred = settings.port;
|
|
165
|
+
} catch {}
|
|
166
|
+
|
|
167
|
+
const python = venvPython(home) || findSystemPython();
|
|
168
|
+
if (!python) {
|
|
169
|
+
console.error("Python não encontrado. Rode: prodmaker install");
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
if (!fs.existsSync(path.join(APP_DIR, "main.py"))) {
|
|
173
|
+
console.error("Backend não encontrado (app/main.py).");
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const port = await pickPort(preferred);
|
|
178
|
+
if (!port) {
|
|
179
|
+
console.error("Nenhuma porta disponível entre " + preferred + " e " + (preferred + 11) + ".");
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
if (port !== preferred) console.log(`Porta ${preferred} ocupada — usando ${port}.`);
|
|
183
|
+
|
|
184
|
+
const pythonCmd = venvPython(home) ? python : python;
|
|
185
|
+
const pythonArgs = venvPython(home)
|
|
186
|
+
? ["-m", "uvicorn", "app.main:app", "--host", "127.0.0.1", "--port", String(port)]
|
|
187
|
+
: process.platform === "win32" && python === "py"
|
|
188
|
+
? ["-3", "-m", "uvicorn", "app.main:app", "--host", "127.0.0.1", "--port", String(port)]
|
|
189
|
+
: ["-m", "uvicorn", "app.main:app", "--host", "127.0.0.1", "--port", String(port)];
|
|
190
|
+
|
|
191
|
+
console.log("Iniciando ProdMaker...");
|
|
192
|
+
printUrlBox(port);
|
|
193
|
+
|
|
194
|
+
const env = { ...process.env, PRODMAKER_HOME: home, PRODMAKER_PORT: String(port) };
|
|
195
|
+
const child = spawn(pythonCmd, pythonArgs, {
|
|
196
|
+
cwd: PKG_ROOT,
|
|
197
|
+
stdio: "inherit",
|
|
198
|
+
env,
|
|
199
|
+
shell: false,
|
|
200
|
+
});
|
|
201
|
+
const stop = () => {
|
|
202
|
+
child.kill();
|
|
203
|
+
process.exit(0);
|
|
204
|
+
};
|
|
205
|
+
process.on("SIGINT", stop);
|
|
206
|
+
process.on("SIGTERM", stop);
|
|
207
|
+
child.on("close", (code) => {
|
|
208
|
+
console.log(`ProdMaker encerrou (código ${code ?? 0}).`);
|
|
209
|
+
process.exit(code ?? 0);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function commandDoctor() {
|
|
214
|
+
console.log(`ProdMaker ${APP_VERSION} — doctor`);
|
|
215
|
+
console.log(`Node: ${process.version}`);
|
|
216
|
+
const home = resolveHome();
|
|
217
|
+
console.log(`PRODMAKER_HOME: ${home}`);
|
|
218
|
+
console.log(`Storage instalado: ${fs.existsSync(storagePath(home, "state", "settings.json")) ? "OK" : "FALTA (rode install)"}`);
|
|
219
|
+
const venv = venvPython(home);
|
|
220
|
+
console.log(`Venv: ${venv || "ausente"}`);
|
|
221
|
+
if (venv) {
|
|
222
|
+
const check = spawnSync(venv, ["-c", "import fastapi, uvicorn"], { encoding: "utf8" });
|
|
223
|
+
console.log(`Dependências Python (fastapi/uvicorn): ${check.status === 0 ? "OK" : "FALTANDO (rode install)"}`);
|
|
224
|
+
} else {
|
|
225
|
+
const base = findSystemPython();
|
|
226
|
+
console.log(`Python do sistema: ${base || "não encontrado"}`);
|
|
227
|
+
}
|
|
228
|
+
console.log(`Backend (app/main.py): ${fs.existsSync(path.join(APP_DIR, "main.py")) ? "OK" : "FALTANDO"}`);
|
|
229
|
+
const dist = path.join(PKG_ROOT, "frontend", "dist", "index.html");
|
|
230
|
+
console.log(`Frontend build (frontend/dist): ${fs.existsSync(dist) ? "OK" : "pendente (Parte 2)"}`);
|
|
231
|
+
const port = await pickPort(DEFAULT_PORT);
|
|
232
|
+
console.log(`Porta ${DEFAULT_PORT}: ${port === DEFAULT_PORT ? "livre" : "ocupada"}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function main() {
|
|
236
|
+
const command = process.argv[2] || "run";
|
|
237
|
+
const flags = {
|
|
238
|
+
skipPythonDeps: process.argv.includes("--skip-python-deps"),
|
|
239
|
+
};
|
|
240
|
+
if (command === "install") return commandInstall(flags);
|
|
241
|
+
if (command === "doctor") return commandDoctor();
|
|
242
|
+
if (command === "run" || command === "start") return commandRun();
|
|
243
|
+
console.log("Uso: prodmaker [install|run|doctor] [--skip-python-deps]");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
main().catch((error) => {
|
|
247
|
+
console.error(error);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rede": "SEARCH",
|
|
3
|
+
"objetivo": "VENDAS",
|
|
4
|
+
"lance": {
|
|
5
|
+
"estrategia": "CPA",
|
|
6
|
+
"cpa_alvo": "60-80% do valor da comissão"
|
|
7
|
+
},
|
|
8
|
+
"orcamento_diario_brl": [100, 120],
|
|
9
|
+
"localizacao": "Presença (apenas)",
|
|
10
|
+
"correspondencia": "frase",
|
|
11
|
+
"negativas_file": "seed/negatives/google-words.txt",
|
|
12
|
+
"anuncio": {
|
|
13
|
+
"titulos": [
|
|
14
|
+
"{produto} - Site Oficial",
|
|
15
|
+
"Compre Agora com Desconto",
|
|
16
|
+
"Oferta por Tempo Limitado"
|
|
17
|
+
],
|
|
18
|
+
"recursos": ["sitelinks", "callouts", "estrutura de preços"]
|
|
19
|
+
},
|
|
20
|
+
"otimizacao": {
|
|
21
|
+
"ctr_minimo": "1%",
|
|
22
|
+
"cpa_alerta": "> 50% do ticket"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"estrutura": "1 campanha -> 1 conjunto -> 5-20 criativos",
|
|
3
|
+
"objetivo": "VENDAS",
|
|
4
|
+
"publico": "aberto (Open) + Advantage+",
|
|
5
|
+
"orcamento": "numero_criativos x (ticket / 2)",
|
|
6
|
+
"criativo": {
|
|
7
|
+
"formula": "Atencao 3s + Promessa + Prova + CTA",
|
|
8
|
+
"rosto_e_texto": true,
|
|
9
|
+
"cpv_alerta_brl": 2.70
|
|
10
|
+
},
|
|
11
|
+
"otimizacao": {
|
|
12
|
+
"cpa_alerta": "> metade do ticket",
|
|
13
|
+
"roas_manter": [1.2, 1.6],
|
|
14
|
+
"roas_escalar_20pct": [1.6, 2.0],
|
|
15
|
+
"roas_dobrar": 2.0,
|
|
16
|
+
"dias_para_campanha_escala": 7
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tamanhos_px": [[1000, 1500], [1000, 1000]],
|
|
3
|
+
"texto": "grande e legivel",
|
|
4
|
+
"temas": ["review", "beneficios", "comparacao", "dica"],
|
|
5
|
+
"seo": ["titulo", "descricao", "nome do arquivo", "boards tematicos"],
|
|
6
|
+
"minimo_pins_por_lancamento": 5,
|
|
7
|
+
"metricas": ["impressoes", "cliques", "salvamentos", "CTR"]
|
|
8
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"formato": "9:16 vertical",
|
|
3
|
+
"duracao_segundos": [15, 30],
|
|
4
|
+
"estilo": "UGC",
|
|
5
|
+
"publico": {
|
|
6
|
+
"idade": [18, 45],
|
|
7
|
+
"paises": ["US", "UK", "CA", "AU"]
|
|
8
|
+
},
|
|
9
|
+
"criativo": "primeiros 3 segundos param o scroll; musica viral; texto na tela; CTA final",
|
|
10
|
+
"orcamento": {
|
|
11
|
+
"teste_diario_usd": [10, 20],
|
|
12
|
+
"escala_diario_usd": [50, 100]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Checklist Final de Lançamento
|
|
2
|
+
|
|
3
|
+
## Produto
|
|
4
|
+
- [ ] Problema específico definido (resolvível em 48h)
|
|
5
|
+
- [ ] Formato escolhido (PDF, planilha, mini-curso...)
|
|
6
|
+
- [ ] Nome autoexplicativo (máx 6 palavras)
|
|
7
|
+
- [ ] Preço definido (R$27–97)
|
|
8
|
+
- [ ] Conteúdo criado (consumo em até 48h)
|
|
9
|
+
- [ ] Order bump configurado (+R$21,90)
|
|
10
|
+
- [ ] Upsell configurado (+R$197)
|
|
11
|
+
|
|
12
|
+
## Página
|
|
13
|
+
- [ ] 12 seções presentes (página de vendas) OU estrutura pre-sell completa
|
|
14
|
+
- [ ] Design mobile-first
|
|
15
|
+
- [ ] Carregamento < 3s
|
|
16
|
+
- [ ] Pixel do ProdMaker embutido
|
|
17
|
+
- [ ] Hospedada no domínio (Cloudflare Pages)
|
|
18
|
+
|
|
19
|
+
## Tráfego
|
|
20
|
+
- [ ] Conta Google Ads pronta (MCC/subconta)
|
|
21
|
+
- [ ] Contas Meta/TikTok prontas
|
|
22
|
+
- [ ] Criativos prontos (5–20 variações)
|
|
23
|
+
- [ ] Palavras-chave validadas + negativas aplicadas
|
|
24
|
+
- [ ] Links de afiliado/checkout configurados
|
|
25
|
+
- [ ] Orçamento diário definido
|
|
26
|
+
- [ ] Pinterest: pelo menos 5 Pins criados e agendados
|
|
27
|
+
|
|
28
|
+
## Métricas de acompanhamento
|
|
29
|
+
CPA · CTR · CPV · ROAS · taxa de conversão da página · impressões/cliques/salvamentos (Pinterest)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"regras": [
|
|
3
|
+
{ "se": "ROAS > 2.0", "entao": "escalar budget +20%", "dias_consecutivos_escala": 7 },
|
|
4
|
+
{ "se": "ROAS entre 1.5 e 2.0", "entao": "manter e observar" },
|
|
5
|
+
{ "se": "ROAS < 1.5", "entao": "pausar ou otimizar (trocar criativos, ajustar keywords, revisar pagina)" },
|
|
6
|
+
{ "se": "CTR < 1% (Google)", "entao": "melhorar titulo/hook" },
|
|
7
|
+
{ "se": "CPV > R$2,70 (Meta)", "entao": "trocar criativo" },
|
|
8
|
+
{ "se": "CPA > 50% do ticket", "entao": "pausar" },
|
|
9
|
+
{ "se": "keyword/criativo sem conversao por 7 dias", "entao": "substituir" }
|
|
10
|
+
],
|
|
11
|
+
"acao_requer_confirmacao": true
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Prompt — Criativos (Meta/TikTok)
|
|
2
|
+
|
|
3
|
+
Gere {QUANTIDADE} roteiros de criativos em vídeo (9:16, 15–30s) para o produto **{NOME_DO_PRODUTO}**.
|
|
4
|
+
|
|
5
|
+
**Fórmula obrigatória:** Atenção em 3s + Promessa + Prova + CTA.
|
|
6
|
+
|
|
7
|
+
**Características:** gancho forte nos 3 primeiros segundos; rosto + texto na tela;
|
|
8
|
+
promessa clara; CTA direto no final ("Clique no link abaixo e comece agora!").
|
|
9
|
+
Estilo UGC para TikTok; para Meta, variar aberturas para testar 5–20 criativos.
|
|
10
|
+
|
|
11
|
+
Formato de saída por criativo:
|
|
12
|
+
{ "gancho_3s": "", "roteiro": "", "texto_na_tela": "", "cta": "" }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Prompt — Geração de Infoproduto (Modo Rápido)
|
|
2
|
+
|
|
3
|
+
Você é um especialista em criação de infoprodutos low-ticket (R$27–R$97).
|
|
4
|
+
|
|
5
|
+
**Entradas:** formato: {FORMATO} · nicho: {NICHO} · dor: {DOR} · avatar: {AVATAR} · resultado prometido: {RESULTADO}
|
|
6
|
+
|
|
7
|
+
**Regras do produto:**
|
|
8
|
+
- O problema deve ser específico, recorrente e resolvível em até 48h.
|
|
9
|
+
- Nome: fórmula [RESULTADO] + [FORMATO] + [ESPECIFICIDADE], máximo 6 palavras.
|
|
10
|
+
- Preço sugerido: e-book R$29,90–49,90 · planilha R$17–47 · mini-curso R$67–97 · desafio R$37–57 · workshop R$57–97.
|
|
11
|
+
- Order bump: +R$21,90 (conversão esperada 25–45%).
|
|
12
|
+
- Upsell pós-compra: +R$197 com desconto (conversão esperada 5–15%).
|
|
13
|
+
|
|
14
|
+
**Gere o conteúdo em Markdown com a estrutura obrigatória:**
|
|
15
|
+
1. Capa com título autoexplicativo (máx 6 palavras)
|
|
16
|
+
2. Diagnóstico do problema (5 motivos)
|
|
17
|
+
3. Solução passo a passo (5–7 passos)
|
|
18
|
+
4. Exemplos práticos (3 casos reais ou simulados)
|
|
19
|
+
5. Checklist de implementação
|
|
20
|
+
6. Bônus (1 recurso extra)
|
|
21
|
+
|
|
22
|
+
Depois de gerar o Markdown, o sistema converte para HTML com CSS A4 e gera o PDF.
|
|
23
|
+
Retorne APENAS o Markdown do produto, sem comentários.
|