Skip to content

Commit f8f00e4

Browse files
author
Jovinull
committed
chore: resolve merge conflict with upstream develop
2 parents 65b689c + 3b5e395 commit f8f00e4

421 files changed

Lines changed: 1661 additions & 147540 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cspell/custom-dictionary-workspace.txt

Lines changed: 72 additions & 0 deletions
Large diffs are not rendered by default.

backend/bruno/Auth/Register.bru

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ post {
1212

1313
body:json {
1414
{
15-
"email":"hudsonteste@email.com",
16-
"password": "teste1234",
17-
"name": "Tavares"
15+
"email":"testeregister@email.com",
16+
"password": "register1234",
17+
"name": "Register"
1818
}
1919
}
2020

backend/bruno/Jobs/SearchJobs.bru

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ meta {
55
}
66

77
get {
8-
url: {{base_url}}/jobs/search
8+
url: {{base_url}}/jobs/search?keywords=node.js
99
body: none
1010
auth: inherit
1111
}
1212

1313
params:query {
14-
~keywords: typescript
14+
keywords: node.js
1515
}
1616

1717
headers {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
vars {
2-
base_url: http://jobsglobalscraper.ddns.net/api
2+
base_url: http://localhost:3001/api
33
sessionCookie: vagas_session=Fe26.2*1*6b1ee4abcbe0ef8e42e8203e5e9110ead280c442ba3c9e1bf78d0c1f24fb5f5d*7c9X00fVX_sg3MhS9HZe6w*TPGS8-0VdhkyeqTAGGkuJB-4mBhf8ybA4wEB5RrO0S-tC9ykpwRVP8y1b1T8cQFYOPsm7Q-9dccgg92xnaMswi9GoU3Q55N1flcZHo_r7PmLsF8EsadRSraRo5TQOjG2isq6B6UavP_zf_Zr5jkpbA*1780502414077*3727896ffed5c4dd607f5d8460989c13de4218813e5d6263848dc882ae4a9027*Q7YEyyEcQbXbMzCdy4gyJU4RBccUkj6GKw5WW8JhzmE~2
44
}

backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"express": "^5.2.1",
4444
"iron-session": "^8.0.4",
4545
"pdfkit": "^0.18.0",
46+
"prom-client": "^15.1.3",
4647
"redis": "^5.12.1",
4748
"swagger-jsdoc": "^6.3.0",
4849
"swagger-ui-express": "^5.0.1",

backend/src/app.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import cors from "cors";
22
import express, { NextFunction, Request, Response } from "express";
3+
import { register } from "./metrics/metrics";
34
import { corsOptions } from "./middleware/cors";
45
import { errorHandler } from "./middleware/errorHandler";
6+
import { metricsMiddleware } from "./middleware/metrics";
7+
import { requestIdMiddleware } from "./middleware/requestId";
58
import { requireAuth } from "./middleware/requireAuth";
69
import { securityHeaders } from "./middleware/securityHeaders";
710
import { withSession } from "./middleware/withSession";
@@ -17,6 +20,8 @@ export function createJobsApiApp() {
1720
app.disable("x-powered-by");
1821
app.use(express.json({ limit: "16kb" }));
1922
app.use(securityHeaders);
23+
app.use(requestIdMiddleware);
24+
app.use(metricsMiddleware);
2025

2126
// um wrapper para garantir se o CORS chega com erro 403
2227
app.use((req: Request, res: Response, next: NextFunction) => {
@@ -46,6 +51,11 @@ export function createJobsApiApp() {
4651
*/
4752
app.get("/api/health", (_req, res) => res.json({ ok: true }));
4853

54+
app.get("/metrics", async (_req, res) => {
55+
res.set("Content-Type", register.contentType);
56+
res.end(await register.metrics());
57+
});
58+
4959
app.use(errorHandler);
5060

5161
return app;

backend/src/logger.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import pino from "pino";
33
export const logger = pino({
44
level: process.env.LOG_LEVEL ?? "info",
55
timestamp: pino.stdTimeFunctions.isoTime,
6+
base: {
7+
service: "backend",
8+
environment: process.env.NODE_ENV ?? "development",
9+
},
610
formatters: {
711
level(label) {
812
return { level: label };
@@ -16,3 +20,11 @@ export const logWarn = (msg: string, ctx?: object) =>
1620
logger.warn(ctx ?? {}, msg);
1721
export const logError = (msg: string, ctx?: object) =>
1822
logger.error(ctx ?? {}, msg);
23+
24+
/**
25+
* Cria um child logger com requestId/userId já anexados,
26+
* para usar dentro de rotas/controllers.
27+
*/
28+
export function getRequestLogger(ctx: { requestId?: string; userId?: string }) {
29+
return logger.child(ctx);
30+
}

backend/src/metrics/metrics.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import client from "prom-client";
2+
3+
export const register = new client.Registry();
4+
client.collectDefaultMetrics({ register });
5+
6+
export const httpRequestDuration = new client.Histogram({
7+
name: "http_request_duration_seconds",
8+
help: "Duração das requisições HTTP",
9+
labelNames: ["method", "route", "status_code"],
10+
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 2, 5],
11+
registers: [register],
12+
});
13+
14+
export const httpRequestsTotal = new client.Counter({
15+
name: "http_requests_total",
16+
help: "Total de requisições HTTP",
17+
labelNames: ["method", "route", "status_code"],
18+
registers: [register],
19+
});
20+
21+
export const activeSessions = new client.Gauge({
22+
name: "active_sessions",
23+
help: "Sessões ativas (aproximação por requisições autenticadas recentes)",
24+
registers: [register],
25+
});
26+
27+
export const jobSearchesTotal = new client.Counter({
28+
name: "job_searches_total",
29+
help: "Total de buscas de vagas realizadas",
30+
labelNames: ["has_keywords"],
31+
registers: [register],
32+
});
33+
34+
export const cacheOperationsTotal = new client.Counter({
35+
name: "cache_operations_total",
36+
help: "Operações de cache no Valkey",
37+
labelNames: ["operation", "result"],
38+
registers: [register],
39+
});

backend/src/middleware/metrics.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { NextFunction, Request, Response } from "express";
2+
import { httpRequestDuration, httpRequestsTotal } from "../metrics/metrics";
3+
4+
export function metricsMiddleware(
5+
req: Request,
6+
res: Response,
7+
next: NextFunction,
8+
) {
9+
const end = httpRequestDuration.startTimer();
10+
11+
res.on("finish", () => {
12+
// route já resolvido pelo Express (com :params), com fallback pro path cru
13+
const route = req.route?.path
14+
? `${req.baseUrl}${req.route.path}`
15+
: req.path;
16+
17+
const labels = {
18+
method: req.method,
19+
route,
20+
status_code: String(res.statusCode),
21+
};
22+
23+
end(labels);
24+
httpRequestsTotal.inc(labels);
25+
});
26+
27+
next();
28+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { randomUUID } from "crypto";
2+
import type { NextFunction, Request, Response } from "express";
3+
4+
declare module "express-serve-static-core" {
5+
interface Request {
6+
requestId: string;
7+
}
8+
}
9+
10+
export function requestIdMiddleware(
11+
req: Request,
12+
res: Response,
13+
next: NextFunction,
14+
) {
15+
req.requestId = (req.headers["x-request-id"] as string) || randomUUID();
16+
res.setHeader("x-request-id", req.requestId);
17+
next();
18+
}

0 commit comments

Comments
 (0)