From adf96002b678773c4708bafbe643dc395fbae5db Mon Sep 17 00:00:00 2001 From: VPS 4 Builder Date: Tue, 16 Jun 2026 06:46:01 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20versionamento=20vis=C3=ADvel=20(rodap?= =?UTF-8?q?=C3=A9=20+=20/api/version=20+=20carimbo=20no=20build)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - backend: endpoint GET /api/version + linha [VERSION] no boot (le APP_VERSION/GIT_COMMIT/BUILD_TIME/APP_ENV) - frontend: buildInfo.ts le import.meta.env.VITE_* ; versão no rodapé do Sidebar - Dockerfiles (front+back): ARG/ENV do carimbo de versão - docker-compose.yml: build args (APP_VERSION/GIT_COMMIT/BUILD_TIME/APP_ENV) com defaults - bump V1.0.12 -> V1.0.13 Co-Authored-By: Claude Opus 4.8 --- backend/Dockerfile | 9 +++++++++ backend/server.js | 11 +++++++++++ docker-compose.yml | 9 +++++++++ frontend/Dockerfile | 7 +++++++ frontend/buildInfo.ts | 17 +++++++++++++++++ frontend/components/Sidebar.tsx | 10 ++++++++++ frontend/constants.ts | 2 +- 7 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 frontend/buildInfo.ts diff --git a/backend/Dockerfile b/backend/Dockerfile index a559606..fe540b0 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,4 +5,13 @@ RUN npm install --omit=dev && npm cache clean --force COPY . . EXPOSE 8018 ENV NODE_ENV=production +# Carimbo de versão (exposto em GET /api/version e no log de boot) +ARG APP_VERSION=dev +ARG GIT_COMMIT=dev +ARG BUILD_TIME= +ARG APP_ENV=DEV +ENV APP_VERSION=$APP_VERSION +ENV GIT_COMMIT=$GIT_COMMIT +ENV BUILD_TIME=$BUILD_TIME +ENV APP_ENV=$APP_ENV CMD ["node", "server.js"] diff --git a/backend/server.js b/backend/server.js index d01813a..1a5b83e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -171,6 +171,16 @@ app.use(cors({ // --- HEALTH CHECK --- app.get('/api/ping', (req, res) => res.json({ status: 'ok', ts: new Date().toISOString() })); +// --- VERSION / BUILD INFO (carimbado no build via ARGs do Dockerfile) --- +const BUILD_INFO = { + name: 'ScoreOdonto API', + version: process.env.APP_VERSION || 'dev', + commit: process.env.GIT_COMMIT || 'dev', + build: process.env.BUILD_TIME || '', + environment: (process.env.APP_ENV || 'DEV').toUpperCase(), +}; +app.get('/api/version', (req, res) => res.json(BUILD_INFO)); + // ============================================================================= // SECURITY MIDDLEWARE: Tenant Guard // ============================================================================= @@ -7985,6 +7995,7 @@ app.post('/api/admin/repasses/:id/confirmar', adminGuard, async (req, res) => { const httpServer = app.listen(PORT, '0.0.0.0', async () => { console.log(`[SERVER] Running on http://0.0.0.0:${PORT}`); + console.log(`[VERSION] ${BUILD_INFO.name} ${BUILD_INFO.version} · commit ${BUILD_INFO.commit} · build ${BUILD_INFO.build || 'n/a'} · ${BUILD_INFO.environment}`); await loadGoogleCredsFromDb(); await runMigrations(); await seedContratoModelos(); diff --git a/docker-compose.yml b/docker-compose.yml index ed93e4b..9bb6baf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,11 @@ services: build: context: "./backend" dockerfile: Dockerfile + args: + APP_VERSION: ${APP_VERSION:-dev} + GIT_COMMIT: ${GIT_COMMIT:-dev} + BUILD_TIME: ${BUILD_TIME:-} + APP_ENV: ${APP_ENV:-DEV} restart: always env_file: - "./backend/.env" @@ -51,6 +56,10 @@ services: build: context: "." dockerfile: frontend/Dockerfile + args: + GIT_COMMIT: ${GIT_COMMIT:-dev} + BUILD_TIME: ${BUILD_TIME:-} + APP_ENV: ${APP_ENV:-DEV} restart: always env_file: - "./frontend/.env.production.local" diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 437cbb5..f75545a 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -4,6 +4,13 @@ WORKDIR /app/frontend COPY frontend/package*.json . RUN npm install COPY frontend/ . +# Carimbo de versão visível (lido por buildInfo.ts via import.meta.env.VITE_*) +ARG GIT_COMMIT=dev +ARG BUILD_TIME= +ARG APP_ENV=DEV +ENV VITE_GIT_COMMIT=$GIT_COMMIT +ENV VITE_BUILD_TIME=$BUILD_TIME +ENV VITE_APP_ENV=$APP_ENV RUN npm run build # Stage 2: Serve diff --git a/frontend/buildInfo.ts b/frontend/buildInfo.ts new file mode 100644 index 0000000..2c2d949 --- /dev/null +++ b/frontend/buildInfo.ts @@ -0,0 +1,17 @@ +import { APP_VERSION } from './constants.ts'; + +// Metadados de build. commit/build/ambiente são carimbados no build via +// variáveis VITE_* (ARGs do Dockerfile do frontend). Em dev sem build args, +// caem nos defaults abaixo. +const meta = (import.meta as any).env || {}; + +export const BUILD_INFO = { + name: 'ScoreOdonto', + version: APP_VERSION, + commit: meta.VITE_GIT_COMMIT || 'dev', + build: meta.VITE_BUILD_TIME || '', + environment: String(meta.VITE_APP_ENV || 'DEV').toUpperCase(), +}; + +// Rótulo curto: "V1.0.13 · 7a9b3c1 · DEV" +export const versionLabel = `${BUILD_INFO.version} · ${BUILD_INFO.commit} · ${BUILD_INFO.environment}`; diff --git a/frontend/components/Sidebar.tsx b/frontend/components/Sidebar.tsx index 5b3a284..616eed7 100644 --- a/frontend/components/Sidebar.tsx +++ b/frontend/components/Sidebar.tsx @@ -7,6 +7,7 @@ import { import { ToothIcon } from './ToothIcon.tsx'; import { HybridBackend } from '../services/backend.ts'; import { getActivePlugins } from '../views/plugins/pluginRegistry.ts'; +import { BUILD_INFO } from '../buildInfo.ts'; interface SidebarProps { activeTab: string; @@ -283,6 +284,15 @@ export const Sidebar: React.FC = ({ activeTab, setActiveTab }) => SAIR DO SISTEMA + +
+ {BUILD_INFO.version} + {' · '}{BUILD_INFO.commit} + {' · '}{BUILD_INFO.environment} +
); diff --git a/frontend/constants.ts b/frontend/constants.ts index 55dd5ac..e515a2d 100644 --- a/frontend/constants.ts +++ b/frontend/constants.ts @@ -1 +1 @@ -export const APP_VERSION = 'V1.0.12'; +export const APP_VERSION = 'V1.0.13';