Skip to content

Feature/geral/switch javafx to tauri - #29

Closed
MathCunha16 wants to merge 2 commits into
mainfrom
feature/geral/switch-javafx-to-tauri
Closed

Feature/geral/switch javafx to tauri#29
MathCunha16 wants to merge 2 commits into
mainfrom
feature/geral/switch-javafx-to-tauri

Conversation

@MathCunha16

@MathCunha16 MathCunha16 commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Pull Request: Switch Desktop Frontend from JavaFX + WebView to Tauri v2

📌 Summary

This PR replaces the legacy JavaFX + Embedded WebView application shell with a modern Tauri v2 (Rust) desktop shell hosting a React frontend.

The backend continues to run as a headless Spring Boot service spawned and managed asynchronously by the Tauri desktop process.


🚀 Key Changes & Architecture

  • Desktop Shell: Replaced JavaFX with Tauri v2 (src-tauri).
  • Frontend Stack: React, Vite, TailwindCSS running within Tauri's native webview component.
  • Backend Orchestration: Tauri Rust core spawns the headless Spring Boot executable JAR (backend.jar) on application startup and manages process lifecycle & IPC token verification.
  • Cross-Platform Packaging: Added package build scripts for .deb, .appimage, .rpm, .msi, and .dmg bundles (npm run build:all, npm run build:deb).
  • Version Synchronization: Automated version syncing between application.yaml, package.json, Cargo.toml, and tauri.conf.json.

⚠️ Important Disclaimers & Known Issues

1. Backend RAM Consumption (WON'T FIX)

Warning

High Backend RAM Usage (JVM Footprint):
The Spring Boot backend process still consumes ~450–500 MB of RAM (RSS) at runtime due to JVM metaspace, Spring Data JPA/Hibernate, Liquibase, and thread stack overhead.

  • Status: WON'T FIX in this PR.
  • Long-term Solution: Resolving backend memory consumption to sub-100 MB levels will require a complete rewrite of the backend service in Go (or native Rust).

2. CI/CD Release Pipeline Status (CRITICAL)

Caution

CI/CD Releases Currently Non-Functional:
The automated GitHub Actions release and build pipeline is currently non-functional/disabled for Tauri packaging on this branch.

  • Manual local builds (npm run build:deb) function as expected.
  • Automated CI/CD release workflows need to be updated with Tauri GitHub Actions runners before automated releases can be published.

🧪 Verification & Testing

  • Tested local build on Linux (Zorin OS / Ubuntu): npm run build:deb
  • Verified backend process spawn, session token extraction, and splash screen transition.

Summary by CodeRabbit

  • Novos Recursos

    • Adicionado suporte ao aplicativo desktop baseado em Tauri, com splash screen e integração automática ao backend.
    • O aplicativo identifica automaticamente a porta e as credenciais da sessão.
    • Incluídos builds para Linux, Windows e macOS.
  • Melhorias

    • Suporte a conexões CORS originadas pelo aplicativo desktop.
    • Configuração de porta dinâmica em produção e porta fixa no ambiente de desenvolvimento.
    • Versões sincronizadas automaticamente entre os componentes do projeto.
  • Documentação

    • Atualizadas as orientações sobre tokens locais, sessões e descoberta do backend.

…nds, and automatic version synchronization script
…R and removing legacy Java desktop components.
@MathCunha16 MathCunha16 self-assigned this Jul 29, 2026
@MathCunha16 MathCunha16 added documentation Improvements or additions to documentation enhancement New feature or request Frontend Frontend feature or modification Backend Backend feature or modification Devops Devops feature or modification Desktop Desktop feature or modification labels Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A aplicação deixa de usar JavaFX e jpackage como shell desktop e passa a usar Tauri. O backend expõe porta e token de sessão, enquanto o shell Rust inicia o JAR, integra essas informações ao frontend e encerra o processo ao fechar.

Changes

Migração do backend

Layer / File(s) Summary
Backend desacoplado e sessão dinâmica
backend/build.gradle.kts, backend/src/main/java/..., backend/src/main/resources/..., docs/security/...
O backend passa a usar BackendApplication, remove integrações JavaFX/jpackage, configura portas por ambiente, registra porta e token no stdout e aceita origens Tauri.

Aplicativo Tauri

Layer / File(s) Summary
Configuração e automação do aplicativo Tauri
frontend/package.json, frontend/scripts/*, frontend/src-tauri/, frontend/public/splash.html
São adicionados o manifest Rust, configuração Tauri, capacidades, splash e scripts para gerar o JAR, sincronizar versões e construir os assets.
Execução do backend pelo shell Tauri
frontend/src-tauri/src/*
O shell inicia backend.jar, lê PORT e TOKEN do stdout, expõe comandos Tauri e encerra o processo Java no fechamento da janela.
Descoberta de endpoint e inicialização da interface
frontend/src/api/client.ts, frontend/src/components/RootLayout.tsx
O frontend usa a URL fornecida pelo Tauri, obtém informações do backend, define token e endpoint globais, valida a saúde da API e fecha o splash.

Estimated code review effort: 5 (Critical) | ~90 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Tauri
  participant SpringBoot
  participant React
  Tauri->>SpringBoot: inicia backend.jar
  SpringBoot-->>Tauri: envia PORT e TOKEN no stdout
  React->>Tauri: invoke get_backend_info
  Tauri-->>React: retorna BackendInfo
  React->>SpringBoot: executa health-check com token
  React->>Tauri: invoke close_splash
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título resume bem a mudança principal: a troca da shell desktop de JavaFX para Tauri.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@MathCunha16 MathCunha16 added the wontfix This will not be worked on label Jul 29, 2026
@MathCunha16
MathCunha16 marked this pull request as ready for review July 29, 2026 12:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/api/client.ts (1)

35-53: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Sessão do backend é assíncrona, mas o app a consome como se já estivesse disponível. Porta e token só chegam via invoke("get_backend_info") depois do mount, enquanto o cliente HTTP e as primeiras queries já foram inicializados — em produção a porta é dinâmica, então essas chamadas vão para localhost:8080 e/ou sem token.

  • frontend/src/api/client.ts#L35-L53: não congelar baseURL no axios.create; resolvê-la por requisição em um request interceptor.
  • frontend/src/components/RootLayout.tsx#L211-L236: bloquear a renderização dos filhos (e de useCheckUpdatesQuery) até a sessão nativa estar resolvida — por exemplo, com um estado sessionReady que só então monta NavigationSidebar/Outlet.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/api/client.ts` around lines 35 - 53, Atualize
frontend/src/api/client.ts nas linhas 35-53 para não congelar getApiBaseUrl() em
axios.create; resolva a URL atual em um interceptor de request antes de cada
chamada, preservando a configuração de headers. Em
frontend/src/components/RootLayout.tsx nas linhas 211-236, adicione um estado
sessionReady que só seja definido após invoke("get_backend_info") concluir e
bloqueie a montagem de NavigationSidebar, Outlet e useCheckUpdatesQuery até a
sessão nativa estar pronta.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@backend/src/main/java/com/devaulty/backend/infrastructure/lifecycle/RuntimeSessionLogger.java`:
- Around line 17-27: Restrinja o tratamento em onApplicationEvent de
RuntimeSessionLogger ao contexto do servidor principal, ignorando
WebServerInitializedEvent originado pelo contexto de management do Actuator
antes de publicar SESSION_PREFIX, port e token. Use a identificação já
disponível no evento ou contexto da aplicação para distinguir o servidor de
management, preservando a emissão única da sessão para a porta principal.

In `@backend/src/main/resources/application-dev.yml`:
- Around line 12-14: Atualize a configuração dev em devaulty.dev.token para usar
dev-session-token, alinhando-a ao valor retornado por
frontend/src-tauri/src/lib.rs e preservando a validação das chamadas Tauri.
Atualize também a documentação correspondente para refletir o novo token de
desenvolvimento.

In `@docs/security/local-development-tokens.md`:
- Around line 22-33: Atualize a documentação de sessão em “Production Mode” para
refletir o contrato consumido por `frontend/src-tauri/src/lib.rs`: o shell
aguarda no stdout uma linha contendo `[DEVAULTY_SESSION]`, `PORT=` e `TOKEN=`.
Remova ou corrija as afirmações de que `RuntimeSessionWriter`, `session.json` e
`DEVAULTY_PORT` são mecanismos de descoberta usados pelo shell, incluindo o
trecho aplicável às linhas 46–61.

In `@frontend/scripts/build-all.js`:
- Around line 24-39: Update the build flow around runCommand and sourceJarPath
so it cannot select an arbitrary executable JAR via jarFiles[0]. Clean the
backend build/libs output before running bootJar, or otherwise validate and
identify the newly generated expected artifact; preserve the existing failure
handling when no valid JAR is available.
- Around line 54-56: Update the Step 3 frontend build command in build-all.js to
invoke the package’s configured build script via npm run build instead of npx
vite build, ensuring the TypeScript project check runs before bundling.

In `@frontend/scripts/sync-version.js`:
- Around line 31-38: Atualize o fluxo de sincronização em torno de rawVersion e
cleanVersion para preservar o sufixo de pré-lançamento ao atualizar
package.json, Cargo.toml e tauri.conf.json. Remova ou ajuste a limpeza que
elimina o trecho após “-”, garantindo que versões como 0.1.6-alpha permaneçam
idênticas em todos os manifests.

In `@frontend/src-tauri/src/lib.rs`:
- Around line 190-200: Estenda a limpeza do processo filho além do evento
CloseRequested da janela main, adicionando um handler de saída da aplicação em
.build(...) que cubra RunEvent::Exit/ExitRequested e reutilize SessionState. Em
ambos os caminhos, extraia o child de child_process, execute kill quando
necessário e depois chame wait() para recolher o processo; preserve a limpeza
atual da janela principal e evite duplicação insegura.
- Around line 135-185: Atualize o fluxo de inicialização em torno de
resolve_java_binary e Command::new para registrar explicitamente falhas ao
resolver o Java e ao executar spawn, marcando is_jar_mode como ativo somente
após a inicialização válida. Remova o jar_path.to_str().unwrap(), tratando
caminhos não UTF-8 sem pânico, e capture stderr do processo Java para encaminhar
suas linhas ao mecanismo de logging existente. Garanta que cada falha seja
propagada ou registrada imediatamente, em vez de aguardar o timeout de
get_backend_info.
- Around line 28-36: Atualize o fallback de modo dev no fluxo que verifica
`is_jar` para retornar o token aceito pelo backend, usando `dev-secret-token` em
vez de `dev-session-token`. Mantenha a porta 8080 e o comportamento de retorno
imediato inalterados.

In `@frontend/src-tauri/tauri.conf.json`:
- Around line 36-38: Substitua o valor nulo de security.csp em tauri.conf.json
por uma política CSP restritiva, permitindo recursos próprios, conexões a
http://localhost:* e imagens self/data conforme necessário para Vite/Tailwind.
Remova apenas o desligamento da CSP e valide que o aplicativo continua
carregando seus recursos locais e comunicando-se com o servidor localhost.
- Around line 24-34: Enable app.macOSPrivateApi in tauri.conf.json and add the
macos-private-api feature in Cargo.toml so the splash window’s transparent
setting works on macOS while preserving the existing splash configuration.

In `@frontend/src/components/RootLayout.tsx`:
- Around line 228-232: Update the initialization error handling around the
RootLayout startup flow so only the expected non-Tauri case is silently ignored;
surface backend startup failures, including the 60-second timeout, through the
existing error state or toast mechanism before closing the splash screen. Keep
the finally block’s close_splash cleanup intact.

---

Outside diff comments:
In `@frontend/src/api/client.ts`:
- Around line 35-53: Atualize frontend/src/api/client.ts nas linhas 35-53 para
não congelar getApiBaseUrl() em axios.create; resolva a URL atual em um
interceptor de request antes de cada chamada, preservando a configuração de
headers. Em frontend/src/components/RootLayout.tsx nas linhas 211-236, adicione
um estado sessionReady que só seja definido após invoke("get_backend_info")
concluir e bloqueie a montagem de NavigationSidebar, Outlet e
useCheckUpdatesQuery até a sessão nativa estar pronta.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 6a3e1718-66cf-4a51-8144-21873d239d5f

📥 Commits

Reviewing files that changed from the base of the PR and between c6cddca and 1e82b11.

⛔ Files ignored due to path filters (21)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • frontend/public/devaulty-splash-screen-logo.png is excluded by !**/*.png
  • frontend/src-tauri/Cargo.lock is excluded by !**/*.lock
  • frontend/src-tauri/icons/128x128.png is excluded by !**/*.png
  • frontend/src-tauri/icons/128x128@2x.png is excluded by !**/*.png
  • frontend/src-tauri/icons/32x32.png is excluded by !**/*.png
  • frontend/src-tauri/icons/64x64.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square107x107Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square142x142Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square150x150Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square284x284Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square30x30Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square310x310Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square44x44Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square71x71Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/Square89x89Logo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/StoreLogo.png is excluded by !**/*.png
  • frontend/src-tauri/icons/devaulty-icon.png is excluded by !**/*.png
  • frontend/src-tauri/icons/icon.ico is excluded by !**/*.ico
  • frontend/src-tauri/icons/icon.png is excluded by !**/*.png
  • frontend/src-tauri/resources/backend.jar is excluded by !**/*.jar
📒 Files selected for processing (27)
  • backend/build.gradle.kts
  • backend/src/main/java/com/devaulty/backend/desktop/DevaultyDesktop.java
  • backend/src/main/java/com/devaulty/backend/desktop/DevaultyMainLauncher.java
  • backend/src/main/java/com/devaulty/backend/desktop/listener/ServerPortListener.java
  • backend/src/main/java/com/devaulty/backend/infrastructure/lifecycle/RuntimeSessionLogger.java
  • backend/src/main/java/com/devaulty/backend/infrastructure/security/WebConfig.java
  • backend/src/main/resources/application-dev.yml
  • backend/src/main/resources/application.yaml
  • backend/src/main/resources/jpackage/linux/devaulty.desktop
  • backend/src/main/resources/jpackage/macos/Info.plist
  • docs/security/local-development-tokens.md
  • frontend/.gitignore
  • frontend/VM.native_memory
  • frontend/package.json
  • frontend/public/splash.html
  • frontend/scripts/build-all.js
  • frontend/scripts/sync-version.js
  • frontend/src-tauri/.gitignore
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/build.rs
  • frontend/src-tauri/capabilities/default.json
  • frontend/src-tauri/icons/icon.icns
  • frontend/src-tauri/src/lib.rs
  • frontend/src-tauri/src/main.rs
  • frontend/src-tauri/tauri.conf.json
  • frontend/src/api/client.ts
  • frontend/src/components/RootLayout.tsx
💤 Files with no reviewable changes (5)
  • backend/src/main/java/com/devaulty/backend/desktop/listener/ServerPortListener.java
  • backend/src/main/java/com/devaulty/backend/desktop/DevaultyMainLauncher.java
  • backend/src/main/resources/jpackage/linux/devaulty.desktop
  • backend/src/main/java/com/devaulty/backend/desktop/DevaultyDesktop.java
  • backend/src/main/resources/jpackage/macos/Info.plist

Comment on lines +17 to +27
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
int port = event.getWebServer().getPort();
String token = AppTokenContext.PROCESS_TOKEN;

String sessionPayload = String.format("%s PORT=%d TOKEN=%s", SESSION_PREFIX, port, token);

System.out.println(sessionPayload);

log.info("Devaulty Backend initialized on dynamic port: {}", port);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Filtre o contexto de management antes de publicar a sessão.

WebServerInitializedEvent também é disparado pelo contexto do servidor de management (Actuator em porta própria). Nesse cenário a segunda emissão sobrescreve port/token no SessionState do shell Rust (frontend/src-tauri/src/lib.rs, linhas 174-177 guardam sempre o último valor), fazendo o frontend apontar para a porta de management.

🛡️ Correção sugerida
     `@Override`
     public void onApplicationEvent(WebServerInitializedEvent event) {
+        if (event.getApplicationContext().getServerNamespace() != null) {
+            return; // ignora o contexto de management
+        }
         int port = event.getWebServer().getPort();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
int port = event.getWebServer().getPort();
String token = AppTokenContext.PROCESS_TOKEN;
String sessionPayload = String.format("%s PORT=%d TOKEN=%s", SESSION_PREFIX, port, token);
System.out.println(sessionPayload);
log.info("Devaulty Backend initialized on dynamic port: {}", port);
}
`@Override`
public void onApplicationEvent(WebServerInitializedEvent event) {
if (event.getApplicationContext().getServerNamespace() != null) {
return; // ignora o contexto de management
}
int port = event.getWebServer().getPort();
String token = AppTokenContext.PROCESS_TOKEN;
String sessionPayload = String.format("%s PORT=%d TOKEN=%s", SESSION_PREFIX, port, token);
System.out.println(sessionPayload);
log.info("Devaulty Backend initialized on dynamic port: {}", port);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/devaulty/backend/infrastructure/lifecycle/RuntimeSessionLogger.java`
around lines 17 - 27, Restrinja o tratamento em onApplicationEvent de
RuntimeSessionLogger ao contexto do servidor principal, ignorando
WebServerInitializedEvent originado pelo contexto de management do Actuator
antes de publicar SESSION_PREFIX, port e token. Use a identificação já
disponível no evento ou contexto da aplicação para distinguir o servidor de
management, preservando a emissão única da sessão para a porta principal.

Comment on lines 12 to +14
devaulty:
dev:
token: "dev-secret-token" No newline at end of file
token: "dev-secret-token"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Alinhe o token de desenvolvimento com o token retornado pelo shell.

Em desenvolvimento, frontend/src-tauri/src/lib.rs retorna dev-session-token, mas o filtro aceita o valor configurado aqui (dev-secret-token) ou o UUID do processo. As chamadas da interface Tauri receberão 403. Use o mesmo valor nos dois lados e atualize a documentação correspondente.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/resources/application-dev.yml` around lines 12 - 14,
Atualize a configuração dev em devaulty.dev.token para usar dev-session-token,
alinhando-a ao valor retornado por frontend/src-tauri/src/lib.rs e preservando a
validação das chamadas Tauri. Atualize também a documentação correspondente para
refletir o novo token de desenvolvimento.

Comment on lines +22 to +33
- Written to session.json - Accepts random UUID as fallback
for Tauri to read - Enables Swagger UI & cURL testing
- Port also written to - Fixed port 8080
session.json
```

### 1. Production Mode (`application-prod.yml`)
- `AppTokenContext.PROCESS_TOKEN` generates a cryptographically unique UUID (`UUID.randomUUID()`) in-memory when the JVM boots.
- `DevaultyDesktop.java` injects this token directly into the JavaFX `WebView` JS context (`window.DEVAULTY_INTERNAL_TOKEN`) during the `Worker.State.RUNNING` state before React components mount.
- External requests without this exact in-memory UUID receive `HTTP 403 Forbidden`.
- `RuntimeSessionWriter` writes `~/.config/devaulty/session.json` containing both the ephemeral port and process token. The Tauri (Rust) shell reads this file to discover the backend's address and authenticate its requests.
- The session file is automatically deleted when the Spring Boot application shuts down (`DisposableBean.destroy()`).
- Additionally, `DEVAULTY_PORT=<port>` is printed to stdout as a fallback mechanism for Tauri to read from the child process output.
- External requests without the exact in-memory UUID receive `HTTP 403 Forbidden`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Documente o contrato de sessão realmente consumido pelo shell.

O shell em frontend/src-tauri/src/lib.rs não lê ~/.config/devaulty/session.json: ele aguarda no stdout uma linha contendo [DEVAULTY_SESSION], PORT= e TOKEN=. Documentar RuntimeSessionWriter, o arquivo de sessão e DEVAULTY_PORT como mecanismo de descoberta induz diagnósticos incorretos e pode mascarar o motivo do timeout de inicialização.

Also applies to: 46-61

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/security/local-development-tokens.md` around lines 22 - 33, Atualize a
documentação de sessão em “Production Mode” para refletir o contrato consumido
por `frontend/src-tauri/src/lib.rs`: o shell aguarda no stdout uma linha
contendo `[DEVAULTY_SESSION]`, `PORT=` e `TOKEN=`. Remova ou corrija as
afirmações de que `RuntimeSessionWriter`, `session.json` e `DEVAULTY_PORT` são
mecanismos de descoberta usados pelo shell, incluindo o trecho aplicável às
linhas 46–61.

Comment on lines +24 to +39
runCommand(`${gradlewCmd} bootJar`, backendDir);

// 2. Locate generated JAR in backend/build/libs/
const backendLibsDir = path.join(backendDir, "build/libs");
if (!fs.existsSync(backendLibsDir)) {
console.error(`Backend build libs directory not found: ${backendLibsDir}`);
process.exit(1);
}

const jarFiles = fs.readdirSync(backendLibsDir).filter((file) => file.endsWith(".jar") && !file.endsWith("-plain.jar"));
if (jarFiles.length === 0) {
console.error("No executable JAR file found in backend/build/libs/");
process.exit(1);
}

const sourceJarPath = path.join(backendLibsDir, jarFiles[0]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Não selecione o JAR pelo primeiro item do diretório.

build/libs pode reter JARs executáveis de versões anteriores, e a ordem de readdirSync() não identifica o artefato recém-gerado. Isso pode empacotar um backend antigo junto ao frontend atual. Limpe a saída antes do bootJar ou valide que há exatamente um JAR esperado antes de copiá-lo.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/scripts/build-all.js` around lines 24 - 39, Update the build flow
around runCommand and sourceJarPath so it cannot select an arbitrary executable
JAR via jarFiles[0]. Clean the backend build/libs output before running bootJar,
or otherwise validate and identify the newly generated expected artifact;
preserve the existing failure handling when no valid JAR is available.

Comment on lines +54 to +56
// 5. Build Frontend assets (Vite)
console.log("\nStep 3: Building React/Vite web bundle...");
runCommand("npx vite build", frontendDir);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Execute a checagem de tipos no build de empacotamento.

npx vite build não executa o tsc -b definido no script build. Assim, erros TypeScript podem não bloquear o bundle distribuído. Use npm run build nesta etapa.

Correção proposta
-  runCommand("npx vite build", frontendDir);
+  runCommand("npm run build", frontendDir);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 5. Build Frontend assets (Vite)
console.log("\nStep 3: Building React/Vite web bundle...");
runCommand("npx vite build", frontendDir);
// 5. Build Frontend assets (Vite)
console.log("\nStep 3: Building React/Vite web bundle...");
runCommand("npm run build", frontendDir);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/scripts/build-all.js` around lines 54 - 56, Update the Step 3
frontend build command in build-all.js to invoke the package’s configured build
script via npm run build instead of npx vite build, ensuring the TypeScript
project check runs before bundling.

Comment on lines +135 to +185
if jar_path.exists() {
// Mark as production JAR mode BEFORE spawning Java
*state_clone.is_jar_mode.lock().unwrap() = true;

if let Some(java_bin) = resolve_java_binary() {
if let Ok(mut child) = Command::new(&java_bin)
.env("SPRING_PROFILES_ACTIVE", "prod")
.args([
"-Xms64m",
"-Xmx256m",
"-XX:MetaspaceSize=96m",
"-XX:MaxMetaspaceSize=192m",
"-XX:ParallelGCThreads=2",
"-XX:ConcGCThreads=1",
"-XX:+UseG1GC",
"-XX:MaxGCPauseMillis=100",
"-jar",
jar_path.to_str().unwrap(),
"--spring.profiles.active=prod",
])
.stdout(Stdio::piped())
.spawn()
{
if let Some(stdout) = child.stdout.take() {
let state_inner = Arc::clone(&state_clone);
std::thread::spawn(move || {
let reader = BufReader::new(stdout);
for line in reader.lines().flatten() {
if line.contains("[DEVAULTY_SESSION]") {
let parts: Vec<&str> = line.split_whitespace().collect();
let mut port_val = None;
let mut token_val = None;
for part in parts {
if part.starts_with("PORT=") {
port_val = part.trim_start_matches("PORT=").parse::<u16>().ok();
} else if part.starts_with("TOKEN=") {
token_val = Some(part.trim_start_matches("TOKEN=").to_string());
}
}
if let (Some(p), Some(t)) = (port_val, token_val) {
*state_inner.port.lock().unwrap() = Some(p);
*state_inner.token.lock().unwrap() = Some(t);
}
}
}
});
}
*state_clone.child_process.lock().unwrap() = Some(child);
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Falhas ao iniciar o Java são silenciosas e degradam a inicialização para um erro de 60s.

is_jar_mode é marcado como true antes de resolver o binário; se resolve_java_binary() retornar None ou o spawn falhar, nada é registrado e get_backend_info só falha após o timeout de 60s — o frontend engole o erro e abre a janela principal sem backend. Além disso, jar_path.to_str().unwrap() (linha 152) pode entrar em pânico em caminhos não-UTF8, e stderr não é capturado, perdendo o stacktrace do Spring Boot.

🛠️ Correção sugerida
-          if let Some(java_bin) = resolve_java_binary() {
-            if let Ok(mut child) = Command::new(&java_bin)
+          let Some(java_bin) = resolve_java_binary() else {
+            log::error!("Java runtime não encontrado; backend não será iniciado");
+            return Ok(());
+          };
+          let Some(jar_str) = jar_path.to_str() else {
+            log::error!("Caminho do JAR não é UTF-8: {:?}", jar_path);
+            return Ok(());
+          };
+          match Command::new(&java_bin)
               .env("SPRING_PROFILES_ACTIVE", "prod")
               .args([
                 ...
-                jar_path.to_str().unwrap(),
+                jar_str,
                 "--spring.profiles.active=prod",
               ])
               .stdout(Stdio::piped())
+              .stderr(Stdio::piped())
               .spawn()
-            {
+          {
+            Ok(mut child) => { /* ... leitura do stdout ... */ }
+            Err(e) => log::error!("Falha ao iniciar o backend: {e}"),
+          }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/src/lib.rs` around lines 135 - 185, Atualize o fluxo de
inicialização em torno de resolve_java_binary e Command::new para registrar
explicitamente falhas ao resolver o Java e ao executar spawn, marcando
is_jar_mode como ativo somente após a inicialização válida. Remova o
jar_path.to_str().unwrap(), tratando caminhos não UTF-8 sem pânico, e capture
stderr do processo Java para encaminhar suas linhas ao mecanismo de logging
existente. Garanta que cada falha seja propagada ou registrada imediatamente, em
vez de aguardar o timeout de get_backend_info.

Comment on lines +190 to +200
.on_window_event(|window, event| {
if let tauri::WindowEvent::CloseRequested { .. } = event {
if window.label() == "main" {
let state = window.state::<Arc<SessionState>>();
let mut guard = state.child_process.lock().unwrap();
if let Some(mut child) = guard.take() {
let _ = child.kill();
}
}
}
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

O backend Java pode ficar órfão e o kill não colhe o processo.

O encerramento só acontece em CloseRequested da janela main. Saídas por outros caminhos (fechar a app pela splash, Cmd+Q no macOS, app.exit(), pânico no shell) deixam o JVM rodando com ~450-500 MB. Também falta wait() após kill(), deixando zumbi em Unix.

🛠️ Correção sugerida — encerrar também no evento de saída da aplicação
-          if let Some(mut child) = guard.take() {
-            let _ = child.kill();
-          }
+          if let Some(mut child) = guard.take() {
+            let _ = child.kill();
+            let _ = child.wait(); // evita processo zumbi
+          }

Além disso, replique a limpeza em .build(...) + RunEvent::Exit/ExitRequested para cobrir os demais caminhos de encerramento.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.on_window_event(|window, event| {
if let tauri::WindowEvent::CloseRequested { .. } = event {
if window.label() == "main" {
let state = window.state::<Arc<SessionState>>();
let mut guard = state.child_process.lock().unwrap();
if let Some(mut child) = guard.take() {
let _ = child.kill();
}
}
}
})
.on_window_event(|window, event| {
if let tauri::WindowEvent::CloseRequested { .. } = event {
if window.label() == "main" {
let state = window.state::<Arc<SessionState>>();
let mut guard = state.child_process.lock().unwrap();
if let Some(mut child) = guard.take() {
let _ = child.kill();
let _ = child.wait(); // evita processo zumbi
}
}
}
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/src/lib.rs` around lines 190 - 200, Estenda a limpeza do
processo filho além do evento CloseRequested da janela main, adicionando um
handler de saída da aplicação em .build(...) que cubra
RunEvent::Exit/ExitRequested e reutilize SessionState. Em ambos os caminhos,
extraia o child de child_process, execute kill quando necessário e depois chame
wait() para recolher o processo; preserve a limpeza atual da janela principal e
evite duplicação insegura.

Comment on lines +24 to +34
{
"label": "splash",
"url": "/splash.html",
"title": "Devaulty",
"width": 550,
"height": 400,
"center": true,
"decorations": false,
"transparent": true,
"alwaysOnTop": true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Tauri v2 transparent window macOSPrivateApi requirement

💡 Result:

To achieve a transparent window in Tauri v2 on macOS, you must enable the macOS private API, as it is required to unlock system-level transparency [1][2]. To implement this, you need to configure your application in two places: 1. Tauri Configuration (tauri.conf.json): Enable the private API in your configuration [3][1]. { "app": { "macOSPrivateApi": true } } Note that enabling this flag will cause apps distributed via the Mac App Store to be rejected, as it relies on private Apple APIs [1][4]. 2. Cargo Dependencies: You must also enable the corresponding feature in your Cargo.toml file to make the transparent method available for macOS [3][2]: [dependencies] tauri = { version = "2.0.0", features = ["macos-private-api"] } If the transparent method is missing from your WebviewWindowBuilder or WindowBuilder during compilation on macOS, it is almost always because one of these two configurations is missing [3][2]. Recent updates to Tauri v2 have introduced more granular control over these APIs, allowing you to use features like macos-private-api-transparent independently of other private APIs, though the legacy umbrella setting macOSPrivateApi remains for backward compatibility [5]. For production-grade transparent effects that avoid private API rejection, some developers look toward using native Metal rendering, though this requires more advanced implementation [4].

Citations:


Ative macOSPrivateApi para a splash translúcida no macOS
Se a splash precisa ser translúcida no macOS, habilite app.macOSPrivateApi e o feature macos-private-api no Cargo.toml; sem isso, transparent: true não surte efeito no macOS e a build pode ser rejeitada na App Store.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/tauri.conf.json` around lines 24 - 34, Enable
app.macOSPrivateApi in tauri.conf.json and add the macos-private-api feature in
Cargo.toml so the splash window’s transparent setting works on macOS while
preserving the existing splash configuration.

Comment on lines +36 to +38
"security": {
"csp": null
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

csp: null desativa a Content Security Policy do webview.

Com o app carregando conteúdo local e falando com http://localhost:<porta>, uma CSP restritiva é viável e reduz muito a superfície de XSS. Considere algo como default-src 'self'; connect-src 'self' http://localhost:*; img-src 'self' data: e ajustar conforme o Vite/Tailwind exigirem.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/tauri.conf.json` around lines 36 - 38, Substitua o valor
nulo de security.csp em tauri.conf.json por uma política CSP restritiva,
permitindo recursos próprios, conexões a http://localhost:* e imagens self/data
conforme necessário para Vite/Tailwind. Remova apenas o desligamento da CSP e
valide que o aplicativo continua carregando seus recursos locais e
comunicando-se com o servidor localhost.

Comment on lines +228 to +232
} catch {
// Silently ignore if running outside Tauri
} finally {
await invoke("close_splash").catch(() => {});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Erro de inicialização do backend fica invisível para o usuário.

O catch vazio trata igualmente "rodando fora do Tauri" e "timeout de 60s do backend" (frontend/src-tauri/src/lib.rs, linha 56). No segundo caso a splash fecha e a janela principal abre sem backend, sem qualquer mensagem. Diferencie os casos e exiba um estado de erro/toast.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/RootLayout.tsx` around lines 228 - 232, Update the
initialization error handling around the RootLayout startup flow so only the
expected non-Tauri case is silently ignored; surface backend startup failures,
including the 60-second timeout, through the existing error state or toast
mechanism before closing the splash screen. Keep the finally block’s
close_splash cleanup intact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend Backend feature or modification Desktop Desktop feature or modification Devops Devops feature or modification documentation Improvements or additions to documentation enhancement New feature or request Frontend Frontend feature or modification wontfix This will not be worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant