feat: versionamento visível (rodapé + /api/version + carimbo no build)
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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"]
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`;
|
||||
@@ -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<SidebarProps> = ({ activeTab, setActiveTab }) =>
|
||||
<LogOut size={16} />
|
||||
SAIR DO SISTEMA
|
||||
</button>
|
||||
|
||||
<div
|
||||
className="px-4 pt-1 text-[8px] leading-tight text-gray-300 font-mono select-text"
|
||||
title={`Build: ${BUILD_INFO.build || 'n/a'}`}
|
||||
>
|
||||
<span className="font-bold text-gray-400">{BUILD_INFO.version}</span>
|
||||
{' · '}{BUILD_INFO.commit}
|
||||
{' · '}<span className={BUILD_INFO.environment === 'PRODUÇÃO' || BUILD_INFO.environment === 'PROD' ? 'text-emerald-400' : 'text-amber-400'}>{BUILD_INFO.environment}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const APP_VERSION = 'V1.0.12';
|
||||
export const APP_VERSION = 'V1.0.13';
|
||||
|
||||
Reference in New Issue
Block a user