diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..9e091aab
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,35 @@
+version: 2
+
+updates:
+ - package-ecosystem: "npm"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 10
+ groups:
+ npm-minor-patch:
+ update-types:
+ - "minor"
+ - "patch"
+
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 10
+
+ - package-ecosystem: "gomod"
+ directory: "/scraper-go"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
+
+ - package-ecosystem: "docker"
+ directories:
+ - "/backend"
+ - "/frontend"
+ - "/front_admin"
+ - "/scraper-go"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..2b389147
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,98 @@
+# Código de Conduta
+
+## Nosso compromisso
+
+No interesse de manter uma comunidade aberta, colaborativa e respeitosa, nós, como membros, contribuidores e mantenedores do projeto **Candidate**, nos comprometemos a tornar a participação no projeto uma experiência livre de assédio e discriminação para todos.
+
+Esperamos que todas as pessoas que participam do projeto ajam de maneira profissional, respeitosa e colaborativa, independentemente de experiência, origem, nacionalidade, aparência, deficiência, identidade ou expressão de gênero, religião, orientação sexual ou qualquer outra característica pessoal.
+
+## Comportamentos esperados
+
+Exemplos de comportamentos que contribuem para um ambiente positivo:
+
+* Utilizar linguagem respeitosa e inclusiva.
+* Respeitar opiniões, experiências e abordagens técnicas diferentes.
+* Aceitar críticas construtivas de maneira profissional.
+* Fornecer feedback técnico de forma objetiva e respeitosa.
+* Concentrar as discussões no projeto e em seus objetivos.
+* Evitar ataques pessoais durante discussões técnicas.
+* Assumir responsabilidade por erros e contribuir para sua resolução.
+* Priorizar o benefício do projeto e da comunidade.
+* Respeitar o trabalho e as contribuições de outros participantes.
+* Manter discussões técnicas baseadas em argumentos, evidências e requisitos do projeto.
+
+## Comportamentos inaceitáveis
+
+Não serão tolerados:
+
+* Assédio, intimidação ou perseguição de qualquer participante.
+* Ataques pessoais, insultos ou comentários depreciativos.
+* Discriminação de qualquer natureza.
+* Linguagem ou comportamento sexualizado inadequado.
+* Ameaças ou comportamento agressivo.
+* Publicação de informações pessoais de terceiros sem autorização.
+* Trolling, spam ou comportamento deliberadamente disruptivo.
+* Tentativas de constranger, humilhar ou descredibilizar outros participantes.
+* Uso das ferramentas, issues, pull requests ou discussões do projeto para conflitos pessoais ou políticos que não tenham relação com o desenvolvimento do projeto.
+* Qualquer comportamento que possa ser considerado inadequado em um ambiente profissional.
+
+## Discussões técnicas
+
+O projeto incentiva debates técnicos e diferentes pontos de vista.
+
+Discordâncias sobre arquitetura, implementação, bibliotecas, padrões de código, decisões de produto ou outras questões técnicas são naturais e fazem parte do desenvolvimento colaborativo.
+
+Entretanto, divergências técnicas devem permanecer focadas nos argumentos e nas decisões relacionadas ao projeto, e não se transformar em ataques pessoais.
+
+Críticas devem ser direcionadas ao código, à implementação ou à decisão técnica, e não à pessoa responsável pela contribuição.
+
+## Responsabilidades dos mantenedores
+
+Os mantenedores são responsáveis por esclarecer e aplicar este Código de Conduta.
+
+Eles poderão:
+
+* Moderar, editar ou remover comentários, issues, pull requests e outras contribuições que violem este código.
+* Solicitar que uma discussão seja redirecionada para uma abordagem mais adequada.
+* Advertir participantes sobre comportamentos inadequados.
+* Restringir temporariamente a participação de pessoas que violem este código.
+* Bloquear permanentemente participantes em casos graves ou reincidentes.
+
+As medidas adotadas deverão considerar a gravidade e o contexto da situação.
+
+## Abrangência
+
+Este Código de Conduta se aplica a todos os espaços relacionados oficialmente ao projeto Candidate, incluindo:
+
+* Repositório GitHub.
+* Issues.
+* Pull Requests.
+* Code Reviews.
+* Discussions.
+* Documentação do projeto.
+* Canais oficiais de comunicação da comunidade.
+* Eventos ou atividades em que uma pessoa esteja representando oficialmente o projeto.
+
+Também poderá ser aplicado a comportamentos públicos fora desses espaços quando uma pessoa estiver oficialmente representando o projeto ou sua comunidade.
+
+## Denúncias
+
+Casos de comportamento abusivo, assédio ou qualquer outra violação deste Código de Conduta devem ser reportados aos mantenedores do projeto por meio dos canais oficiais disponíveis no repositório.
+
+As denúncias deverão ser tratadas com confidencialidade e avaliadas de maneira imparcial.
+
+Não serão toleradas retaliações contra pessoas que realizem denúncias de boa-fé.
+
+## Aplicação
+
+Os mantenedores avaliarão cada situação individualmente e poderão tomar medidas proporcionais à gravidade da violação.
+
+Em casos graves ou reincidentes, as medidas podem incluir a remoção de contribuições, restrição temporária de participação ou banimento permanente do projeto.
+
+## Atribuição
+
+Este Código de Conduta foi baseado no **Contributor Covenant**, adaptado às necessidades e ao contexto do projeto Candidate.
+
+Para referência, consulte a documentação oficial do Contributor Covenant.
+
+[Contributor Covenant](https://www.contributor-covenant.org)
diff --git a/electron/loading.html b/electron/loading.html
deleted file mode 100644
index ee7b6264..00000000
--- a/electron/loading.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
-
- Vagas Full – Carregando
-
-
-
-
-
Vagas Full
-
-
Buscando vagas no LinkedIn...
-
Isso pode levar alguns instantes.
Aguarde enquanto os dados são coletados.
-
-
-
diff --git a/electron/main.js b/electron/main.js
deleted file mode 100644
index df1294af..00000000
--- a/electron/main.js
+++ /dev/null
@@ -1,195 +0,0 @@
-'use strict';
-
-// ─────────────────────────────────────────────────────────────────────────────
-// Vagas Full – Electron main process
-//
-// Boot flow:
-// 1. Show loading window while the backend starts
-// 2. Import backend server in-process → Express starts on localhost:3001
-// 3. Poll GET /api/health until the server accepts connections
-// 4. Open the main window (React app served by Express)
-// 5. Scraper execution is user-triggered from the UI via /api/scraper/run
-//
-// Why in-process import() instead of spawn('node', ...)?
-// spawn('node', ...) requires Node to be installed on the user's machine.
-// import() works because Electron ships its own Node runtime – the app
-// runs fully standalone, no external Node installation needed.
-// ─────────────────────────────────────────────────────────────────────────────
-
-const { app, BrowserWindow, dialog } = require('electron');
-const path = require('path');
-const http = require('http');
-const { pathToFileURL } = require('url');
-
-const BACKEND_PORT = 3001;
-const BACKEND_URL = `http://localhost:${BACKEND_PORT}`;
-const MAX_RETRIES = 60; // 60 × 500 ms = 30 s maximum wait
-const RETRY_INTERVAL_MS = 500; // ms between health-check polls
-
-// ─── Path helpers ─────────────────────────────────────────────────────────────
-// app.getAppPath() returns:
-// development : workspace root (where root package.json lives)
-// packaged : /resources/app (asar: false)
-
-function getAppRootPath() {
- return app.getAppPath();
-}
-
-function getFrontendDistPath() {
- return path.join(getAppRootPath(), 'frontend', 'dist');
-}
-
-function getBackendServerPath() {
- return path.join(getAppRootPath(), 'backend', 'src', 'server.js');
-}
-
-// userData is the OS user-data directory – writable even under Program Files,
-// and survives app updates.
-function getOutputDir() {
- return path.join(app.getPath('userData'), 'output');
-}
-
-function getLoadingPagePath() {
- return path.join(getAppRootPath(), 'electron', 'loading.html');
-}
-
-// ─── Backend startup (in-process) ─────────────────────────────────────────────
-
-async function startBackend() {
- // All env vars must be set BEFORE the ESM module is imported so they are
- // visible at module-evaluation time.
- const outDir = getOutputDir();
- process.env.PORT = String(BACKEND_PORT);
- process.env.ELECTRON_OUTPUT_DIR = outDir; // API reads XLSX files from here
- process.env.ELECTRON_STATIC_DIR = getFrontendDistPath(); // Express serves the React build
- process.env.OUTPUT_FILE = path.join(outDir, 'vagas_linkedin.xlsx'); // scraper writes here
- process.env.PDF_FILE = path.join(outDir, 'vagas_linkedin.pdf'); // scraper writes here
-
- // pathToFileURL produces a correct file:// URL on Windows (handles spaces & backslashes)
- await import(pathToFileURL(getBackendServerPath()).href);
-}
-
-// ─── Health-check polling ──────────────────────────────────────────────────────
-
-function waitForBackend() {
- return new Promise((resolve, reject) => {
- let retries = 0;
-
- function check() {
- const req = http.get(
- `${BACKEND_URL}/api/health`,
- { timeout: 2000 },
- (res) => {
- res.resume(); // drain body; only the status code matters
- if (res.statusCode === 200) {
- resolve();
- } else {
- scheduleRetry();
- }
- }
- );
-
- req.on('error', scheduleRetry);
- req.on('timeout', () => {
- req.destroy();
- scheduleRetry();
- });
- }
-
- function scheduleRetry() {
- retries += 1;
- if (retries >= MAX_RETRIES) {
- reject(
- new Error(
- `O servidor backend não respondeu após ${MAX_RETRIES} tentativas (${(MAX_RETRIES * RETRY_INTERVAL_MS) / 1000}s).`
- )
- );
- return;
- }
- setTimeout(check, RETRY_INTERVAL_MS);
- }
-
- check();
- });
-}
-
-// ─── Windows ──────────────────────────────────────────────────────────────────
-
-function createLoadingWindow() {
- const win = new BrowserWindow({
- width: 520,
- height: 360,
- resizable: false,
- frame: false,
- show: false,
- backgroundColor: '#0f172a',
- webPreferences: {
- contextIsolation: true,
- nodeIntegration: false,
- sandbox: true,
- },
- });
-
- win.loadFile(getLoadingPagePath());
- win.once('ready-to-show', () => win.show());
- return win;
-}
-
-function createMainWindow() {
- const win = new BrowserWindow({
- width: 1280,
- height: 800,
- minWidth: 900,
- minHeight: 600,
- show: false,
- backgroundColor: '#0f172a',
- title: 'Vagas Full',
- webPreferences: {
- preload: path.join(__dirname, 'preload.js'),
- contextIsolation: true,
- nodeIntegration: false,
- sandbox: true,
- },
- });
-
- // The React app is served by Express as static files.
- // loadURL keeps relative /api/... fetch calls working correctly.
- win.loadURL(BACKEND_URL);
- win.once('ready-to-show', () => win.show());
- return win;
-}
-
-// ─── App lifecycle ─────────────────────────────────────────────────────────────
-
-app.whenReady().then(async () => {
- const loader = createLoadingWindow();
-
- try {
- // 1. Start Express (backend + static file serving) inside this process
- await startBackend();
-
- // 2. Wait until the HTTP server is accepting connections
- await waitForBackend();
-
- // 3. Open the dashboard; destroy loading screen when page is ready
- const main = createMainWindow();
- main.once('ready-to-show', () => loader.destroy());
-
- } catch (fatal) {
- loader.destroy();
- dialog.showErrorBox(
- 'Falha ao iniciar o aplicativo',
- `O servidor não pôde ser iniciado.\n\n${fatal.message}`,
- );
- app.quit();
- }
-
- // macOS: recreate window when dock icon is clicked
- app.on('activate', () => {
- if (BrowserWindow.getAllWindows().length === 0) createMainWindow();
- });
-});
-
-app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') app.quit();
-});
diff --git a/electron/preload.js b/electron/preload.js
deleted file mode 100644
index a6392b2c..00000000
--- a/electron/preload.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-/**
- * Preload script — runs in a sandboxed context before the renderer page loads.
- *
- * Use `contextBridge.exposeInMainWorld` here if you ever need to expose
- * safe IPC helpers to the React app. For now the app only needs the backend
- * HTTP API, so no extra bridging is required.
- */
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
deleted file mode 100644
index c6903469..00000000
--- a/pnpm-workspace.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-packages:
- - "frontend"
- - "backend"
- - "front_admin"
-
-allowBuilds:
- "@scarf/scarf": true
- argon2: true
- electron: true
- electron-winstaller: true
- es5-ext: true
- esbuild: true
- msw: true
-minimumReleaseAgeExclude:
- - xlsx@0.19.3
- - xlsx@0.20.2
-overrides:
- electron@<35.7.5: ">=35.7.5"
- electron@<38.8.6: ">=38.8.6"
- electron@<39.8.1: ">=39.8.1"
- electron@<39.8.5: ">=39.8.5"
- electron@>=33.0.0-alpha.1 <39.8.5: ">=39.8.5"
- esbuild@<=0.24.2: ">=0.25.0"
- tar@<7.5.7: ">=7.5.7"
- tar@<7.5.8: ">=7.5.8"
- tar@<=7.5.10: ">=7.5.11"
- tar@<=7.5.2: ">=7.5.3"
- tar@<=7.5.3: ">=7.5.4"
- tar@<=7.5.9: ">=7.5.10"
- tmp@<0.2.6: ">=0.2.6"
- vitest@<4.1.0: ">=4.1.0"
-
-"pnpm": { "allowBuilds": ["@scarf/scarf", "electron", "esbuild"] }