@grapadigital/shared-schemas 1.0.204 → 1.0.207
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/schemas/action.schema.d.ts +5 -0
- package/dist/schemas/action.schema.js +5 -0
- package/dist/schemas/client.schema.d.ts +4 -3
- package/dist/schemas/content.schema.d.ts +1 -0
- package/dist/schemas/content.schema.js +4 -0
- package/dist/schemas/job.schema.d.ts +84 -0
- package/dist/schemas/job.schema.js +118 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/schemas/action.schema.ts +8 -0
- package/src/schemas/client.schema.ts +4 -3
- package/src/schemas/content.schema.ts +6 -0
- package/src/schemas/job.schema.ts +106 -0
package/dist/index.d.ts
CHANGED
|
@@ -31,5 +31,6 @@ export { Note, NoteSchema, NoteMention, NoteMentionSchema } from './schemas/note
|
|
|
31
31
|
export * from './schemas/content-capture-process.schema';
|
|
32
32
|
export * from './schemas/content-draft.schema';
|
|
33
33
|
export * from './schemas/export-comments-job.schema';
|
|
34
|
+
export * from './schemas/job.schema';
|
|
34
35
|
export * from './schemas/profile-followers-snapshot.schema';
|
|
35
36
|
export * from './schemas/lead.schema';
|
package/dist/index.js
CHANGED
|
@@ -52,5 +52,6 @@ Object.defineProperty(exports, "NoteMentionSchema", { enumerable: true, get: fun
|
|
|
52
52
|
__exportStar(require("./schemas/content-capture-process.schema"), exports);
|
|
53
53
|
__exportStar(require("./schemas/content-draft.schema"), exports);
|
|
54
54
|
__exportStar(require("./schemas/export-comments-job.schema"), exports);
|
|
55
|
+
__exportStar(require("./schemas/job.schema"), exports);
|
|
55
56
|
__exportStar(require("./schemas/profile-followers-snapshot.schema"), exports);
|
|
56
57
|
__exportStar(require("./schemas/lead.schema"), exports);
|
|
@@ -111,6 +111,11 @@ export declare class Action {
|
|
|
111
111
|
updatedAt?: Date;
|
|
112
112
|
notes?: Note[];
|
|
113
113
|
primetagId?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Liga a análise GenIA (comentários + classificação por IA) só pra esta
|
|
116
|
+
* action, mesmo que o client dela não tenha `Client.hasGenIAAnalysis`.
|
|
117
|
+
*/
|
|
118
|
+
hasGenIAAnalysis?: boolean;
|
|
114
119
|
hashtags?: string[];
|
|
115
120
|
instagramMentions?: string[];
|
|
116
121
|
tiktokMentions?: string[];
|
|
@@ -281,6 +281,11 @@ __decorate([
|
|
|
281
281
|
(0, mongoose_1.Prop)({ type: String, required: false }),
|
|
282
282
|
__metadata("design:type", String)
|
|
283
283
|
], Action.prototype, "primetagId", void 0);
|
|
284
|
+
__decorate([
|
|
285
|
+
(0, swagger_1.ApiProperty)({ example: false, required: false }),
|
|
286
|
+
(0, mongoose_1.Prop)({ type: Boolean, required: false }),
|
|
287
|
+
__metadata("design:type", Boolean)
|
|
288
|
+
], Action.prototype, "hasGenIAAnalysis", void 0);
|
|
284
289
|
__decorate([
|
|
285
290
|
(0, swagger_1.ApiProperty)({ example: ['#trending', '#viral'], required: false }),
|
|
286
291
|
(0, mongoose_1.Prop)({ type: [String], required: false }),
|
|
@@ -133,9 +133,10 @@ export declare class Client extends Party {
|
|
|
133
133
|
hasGenIAAnalysis: boolean;
|
|
134
134
|
/**
|
|
135
135
|
* Client de organização (ex.: "Oma Creators"): representa a organização
|
|
136
|
-
* inteira, não uma marca.
|
|
137
|
-
*
|
|
138
|
-
*
|
|
136
|
+
* inteira, não uma marca. No hub, mostra todas as actions dessa organização
|
|
137
|
+
* independentemente do client (marca) de cada action. Não liga a análise
|
|
138
|
+
* GenIA das actions — isso é `Client.hasGenIAAnalysis` do client da action
|
|
139
|
+
* ou `Action.hasGenIAAnalysis`.
|
|
139
140
|
*/
|
|
140
141
|
organization?: Types.ObjectId;
|
|
141
142
|
reportResponsable?: Responsable;
|
|
@@ -417,6 +417,10 @@ __decorate([
|
|
|
417
417
|
(0, mongoose_1.Prop)({ type: String, required: false }),
|
|
418
418
|
__metadata("design:type", String)
|
|
419
419
|
], Content.prototype, "primetagId", void 0);
|
|
420
|
+
__decorate([
|
|
421
|
+
(0, mongoose_1.Prop)({ type: String, required: false }),
|
|
422
|
+
__metadata("design:type", String)
|
|
423
|
+
], Content.prototype, "captureRunId", void 0);
|
|
420
424
|
__decorate([
|
|
421
425
|
(0, mongoose_1.Prop)({ type: exports.SentimentAnalysisSchema, required: false, default: null }),
|
|
422
426
|
__metadata("design:type", Object)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/// <reference types="mongoose/types/aggregate" />
|
|
2
|
+
/// <reference types="mongoose/types/callback" />
|
|
3
|
+
/// <reference types="mongoose/types/collection" />
|
|
4
|
+
/// <reference types="mongoose/types/connection" />
|
|
5
|
+
/// <reference types="mongoose/types/cursor" />
|
|
6
|
+
/// <reference types="mongoose/types/document" />
|
|
7
|
+
/// <reference types="mongoose/types/error" />
|
|
8
|
+
/// <reference types="mongoose/types/expressions" />
|
|
9
|
+
/// <reference types="mongoose/types/helpers" />
|
|
10
|
+
/// <reference types="mongoose/types/middlewares" />
|
|
11
|
+
/// <reference types="mongoose/types/indexes" />
|
|
12
|
+
/// <reference types="mongoose/types/models" />
|
|
13
|
+
/// <reference types="mongoose/types/mongooseoptions" />
|
|
14
|
+
/// <reference types="mongoose/types/pipelinestage" />
|
|
15
|
+
/// <reference types="mongoose/types/populate" />
|
|
16
|
+
/// <reference types="mongoose/types/query" />
|
|
17
|
+
/// <reference types="mongoose/types/schemaoptions" />
|
|
18
|
+
/// <reference types="mongoose/types/session" />
|
|
19
|
+
/// <reference types="mongoose/types/types" />
|
|
20
|
+
/// <reference types="mongoose/types/utility" />
|
|
21
|
+
/// <reference types="mongoose/types/validation" />
|
|
22
|
+
/// <reference types="mongoose/types/virtuals" />
|
|
23
|
+
/// <reference types="mongoose/types/schematypes" />
|
|
24
|
+
/// <reference types="mongoose/types/inferschematype" />
|
|
25
|
+
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
26
|
+
import { HydratedDocument, Schema as MongooseSchema, Types } from 'mongoose';
|
|
27
|
+
import { Action } from './action.schema';
|
|
28
|
+
export type JobDocument = HydratedDocument<Job>;
|
|
29
|
+
export declare const JOB_ORIGINS: readonly ["trigger", "approval", "reclassify"];
|
|
30
|
+
export type JobOrigin = (typeof JOB_ORIGINS)[number];
|
|
31
|
+
export declare const JOB_WORKERS: readonly ["content-capture-trigger", "content-capture", "comment-capture", "content-classification", "metrics-generator", "profile-sync"];
|
|
32
|
+
export type JobWorker = (typeof JOB_WORKERS)[number];
|
|
33
|
+
export declare const JOB_STATUSES: readonly ["done", "skipped", "error"];
|
|
34
|
+
export type JobStatus = (typeof JOB_STATUSES)[number];
|
|
35
|
+
/**
|
|
36
|
+
* Trilha única do pipeline de captura: cada worker grava uma linha por
|
|
37
|
+
* unidade de trabalho (action ou content), e todas as linhas da mesma rodada
|
|
38
|
+
* compartilham o `runId` gerado pelo content-capture-trigger. `requestId`
|
|
39
|
+
* separa cada disparo dentro de um `runId` — na captura é igual ao `runId`;
|
|
40
|
+
* na aprovação/reclassificação a api-campaigns gera um por clique. `input` é
|
|
41
|
+
* o payload recebido, `response` o que veio de fora (Primetag, exportcomments,
|
|
42
|
+
* OpenAI) e `result` o que o worker decidiu ou gravou.
|
|
43
|
+
*/
|
|
44
|
+
export declare class Job {
|
|
45
|
+
_id?: Types.ObjectId;
|
|
46
|
+
runId: string;
|
|
47
|
+
requestId: string;
|
|
48
|
+
origin: JobOrigin;
|
|
49
|
+
worker: JobWorker;
|
|
50
|
+
actionId: Types.ObjectId | Action;
|
|
51
|
+
contentId?: Types.ObjectId;
|
|
52
|
+
primetagId?: string;
|
|
53
|
+
status: JobStatus;
|
|
54
|
+
input?: unknown;
|
|
55
|
+
response?: unknown;
|
|
56
|
+
result?: unknown;
|
|
57
|
+
error?: string;
|
|
58
|
+
startedAt: Date;
|
|
59
|
+
finishedAt?: Date;
|
|
60
|
+
createdAt?: Date;
|
|
61
|
+
updatedAt?: Date;
|
|
62
|
+
}
|
|
63
|
+
export declare const JobSchema: MongooseSchema<Job, import("mongoose").Model<Job, any, any, any, import("mongoose").Document<unknown, any, Job, any, {}> & Job & Required<{
|
|
64
|
+
_id: Types.ObjectId;
|
|
65
|
+
}> & {
|
|
66
|
+
__v: number;
|
|
67
|
+
}, any>, {}, {}, {}, {}, import("mongoose").DefaultSchemaOptions, Job, import("mongoose").Document<unknown, {}, import("mongoose").FlatRecord<Job>, {}, import("mongoose").ResolveSchemaOptions<import("mongoose").DefaultSchemaOptions>> & import("mongoose").FlatRecord<Job> & Required<{
|
|
68
|
+
_id: Types.ObjectId;
|
|
69
|
+
}> & {
|
|
70
|
+
__v: number;
|
|
71
|
+
}>;
|
|
72
|
+
export declare const JobModel: import("mongoose").Model<Job, {}, {}, {}, import("mongoose").Document<unknown, {}, Job, {}, import("mongoose").DefaultSchemaOptions> & Job & Required<{
|
|
73
|
+
_id: Types.ObjectId;
|
|
74
|
+
}> & {
|
|
75
|
+
__v: number;
|
|
76
|
+
}, MongooseSchema<Job, import("mongoose").Model<Job, any, any, any, import("mongoose").Document<unknown, any, Job, any, {}> & Job & Required<{
|
|
77
|
+
_id: Types.ObjectId;
|
|
78
|
+
}> & {
|
|
79
|
+
__v: number;
|
|
80
|
+
}, any>, {}, {}, {}, {}, import("mongoose").DefaultSchemaOptions, Job, import("mongoose").Document<unknown, {}, import("mongoose").FlatRecord<Job>, {}, import("mongoose").ResolveSchemaOptions<import("mongoose").DefaultSchemaOptions>> & import("mongoose").FlatRecord<Job> & Required<{
|
|
81
|
+
_id: Types.ObjectId;
|
|
82
|
+
}> & {
|
|
83
|
+
__v: number;
|
|
84
|
+
}>>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.JobModel = exports.JobSchema = exports.Job = exports.JOB_STATUSES = exports.JOB_WORKERS = exports.JOB_ORIGINS = void 0;
|
|
13
|
+
const mongoose_1 = require("@nestjs/mongoose");
|
|
14
|
+
const mongoose_2 = require("mongoose");
|
|
15
|
+
exports.JOB_ORIGINS = ['trigger', 'approval', 'reclassify'];
|
|
16
|
+
exports.JOB_WORKERS = [
|
|
17
|
+
'content-capture-trigger',
|
|
18
|
+
'content-capture',
|
|
19
|
+
'comment-capture',
|
|
20
|
+
'content-classification',
|
|
21
|
+
'metrics-generator',
|
|
22
|
+
'profile-sync',
|
|
23
|
+
];
|
|
24
|
+
exports.JOB_STATUSES = ['done', 'skipped', 'error'];
|
|
25
|
+
/**
|
|
26
|
+
* Trilha única do pipeline de captura: cada worker grava uma linha por
|
|
27
|
+
* unidade de trabalho (action ou content), e todas as linhas da mesma rodada
|
|
28
|
+
* compartilham o `runId` gerado pelo content-capture-trigger. `requestId`
|
|
29
|
+
* separa cada disparo dentro de um `runId` — na captura é igual ao `runId`;
|
|
30
|
+
* na aprovação/reclassificação a api-campaigns gera um por clique. `input` é
|
|
31
|
+
* o payload recebido, `response` o que veio de fora (Primetag, exportcomments,
|
|
32
|
+
* OpenAI) e `result` o que o worker decidiu ou gravou.
|
|
33
|
+
*/
|
|
34
|
+
let Job = class Job {
|
|
35
|
+
};
|
|
36
|
+
__decorate([
|
|
37
|
+
(0, mongoose_1.Prop)({ type: mongoose_2.Schema.Types.ObjectId, auto: true, required: false }),
|
|
38
|
+
__metadata("design:type", mongoose_2.Types.ObjectId)
|
|
39
|
+
], Job.prototype, "_id", void 0);
|
|
40
|
+
__decorate([
|
|
41
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
42
|
+
__metadata("design:type", String)
|
|
43
|
+
], Job.prototype, "runId", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
46
|
+
__metadata("design:type", String)
|
|
47
|
+
], Job.prototype, "requestId", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
(0, mongoose_1.Prop)({ type: String, enum: exports.JOB_ORIGINS, required: true }),
|
|
50
|
+
__metadata("design:type", String)
|
|
51
|
+
], Job.prototype, "origin", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
(0, mongoose_1.Prop)({ type: String, enum: exports.JOB_WORKERS, required: true }),
|
|
54
|
+
__metadata("design:type", String)
|
|
55
|
+
], Job.prototype, "worker", void 0);
|
|
56
|
+
__decorate([
|
|
57
|
+
(0, mongoose_1.Prop)({ type: mongoose_2.Schema.Types.ObjectId, ref: 'Action', required: true }),
|
|
58
|
+
__metadata("design:type", Object)
|
|
59
|
+
], Job.prototype, "actionId", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, mongoose_1.Prop)({ type: mongoose_2.Schema.Types.ObjectId, required: false }),
|
|
62
|
+
__metadata("design:type", mongoose_2.Types.ObjectId)
|
|
63
|
+
], Job.prototype, "contentId", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
(0, mongoose_1.Prop)({ type: String, required: false }),
|
|
66
|
+
__metadata("design:type", String)
|
|
67
|
+
], Job.prototype, "primetagId", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
(0, mongoose_1.Prop)({ type: String, enum: exports.JOB_STATUSES, required: true }),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], Job.prototype, "status", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
(0, mongoose_1.Prop)({ type: mongoose_2.Schema.Types.Mixed, required: false }),
|
|
74
|
+
__metadata("design:type", Object)
|
|
75
|
+
], Job.prototype, "input", void 0);
|
|
76
|
+
__decorate([
|
|
77
|
+
(0, mongoose_1.Prop)({ type: mongoose_2.Schema.Types.Mixed, required: false }),
|
|
78
|
+
__metadata("design:type", Object)
|
|
79
|
+
], Job.prototype, "response", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, mongoose_1.Prop)({ type: mongoose_2.Schema.Types.Mixed, required: false }),
|
|
82
|
+
__metadata("design:type", Object)
|
|
83
|
+
], Job.prototype, "result", void 0);
|
|
84
|
+
__decorate([
|
|
85
|
+
(0, mongoose_1.Prop)({ type: String, required: false }),
|
|
86
|
+
__metadata("design:type", String)
|
|
87
|
+
], Job.prototype, "error", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
(0, mongoose_1.Prop)({ type: Date, required: true, default: Date.now }),
|
|
90
|
+
__metadata("design:type", Date)
|
|
91
|
+
], Job.prototype, "startedAt", void 0);
|
|
92
|
+
__decorate([
|
|
93
|
+
(0, mongoose_1.Prop)({ type: Date, required: false }),
|
|
94
|
+
__metadata("design:type", Date)
|
|
95
|
+
], Job.prototype, "finishedAt", void 0);
|
|
96
|
+
__decorate([
|
|
97
|
+
(0, mongoose_1.Prop)({ default: Date.now, required: false }),
|
|
98
|
+
__metadata("design:type", Date)
|
|
99
|
+
], Job.prototype, "createdAt", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
(0, mongoose_1.Prop)({ default: Date.now, required: false }),
|
|
102
|
+
__metadata("design:type", Date)
|
|
103
|
+
], Job.prototype, "updatedAt", void 0);
|
|
104
|
+
Job = __decorate([
|
|
105
|
+
(0, mongoose_1.Schema)({ collection: 'jobs', timestamps: true })
|
|
106
|
+
], Job);
|
|
107
|
+
exports.Job = Job;
|
|
108
|
+
exports.JobSchema = mongoose_1.SchemaFactory.createForClass(Job);
|
|
109
|
+
// Reentrega da mesma mensagem atualiza a mesma linha.
|
|
110
|
+
exports.JobSchema.index({ runId: 1, requestId: 1, worker: 1, contentId: 1, primetagId: 1 }, { unique: true });
|
|
111
|
+
// Trava do trigger: última rodada de uma action.
|
|
112
|
+
exports.JobSchema.index({ actionId: 1, worker: 1, origin: 1, startedAt: -1 });
|
|
113
|
+
// A trilha guarda o payload bruto de cada rodada e cresce rápido: o Mongo
|
|
114
|
+
// apaga sozinho as linhas com mais de 180 dias.
|
|
115
|
+
exports.JobSchema.index({ createdAt: 1 }, { expireAfterSeconds: 180 * 24 * 60 * 60 });
|
|
116
|
+
// Raw mais recente de uma publication (linhas do content-capture).
|
|
117
|
+
exports.JobSchema.index({ actionId: 1, worker: 1, primetagId: 1, startedAt: -1 });
|
|
118
|
+
exports.JobModel = (0, mongoose_2.model)('Job', exports.JobSchema);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -31,5 +31,6 @@ export { Note, NoteSchema, NoteMention, NoteMentionSchema } from './schemas/note
|
|
|
31
31
|
export * from './schemas/content-capture-process.schema';
|
|
32
32
|
export * from './schemas/content-draft.schema';
|
|
33
33
|
export * from './schemas/export-comments-job.schema';
|
|
34
|
+
export * from './schemas/job.schema';
|
|
34
35
|
export * from './schemas/profile-followers-snapshot.schema';
|
|
35
36
|
export * from './schemas/lead.schema';
|
|
@@ -235,6 +235,14 @@ export class Action {
|
|
|
235
235
|
@Prop({ type: String, required: false })
|
|
236
236
|
primetagId?: string;
|
|
237
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Liga a análise GenIA (comentários + classificação por IA) só pra esta
|
|
240
|
+
* action, mesmo que o client dela não tenha `Client.hasGenIAAnalysis`.
|
|
241
|
+
*/
|
|
242
|
+
@ApiProperty({ example: false, required: false })
|
|
243
|
+
@Prop({ type: Boolean, required: false })
|
|
244
|
+
hasGenIAAnalysis?: boolean;
|
|
245
|
+
|
|
238
246
|
@ApiProperty({ example: ['#trending', '#viral'], required: false })
|
|
239
247
|
@Prop({ type: [String], required: false })
|
|
240
248
|
hashtags?: string[];
|
|
@@ -139,9 +139,10 @@ export class Client extends Party {
|
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
141
|
* Client de organização (ex.: "Oma Creators"): representa a organização
|
|
142
|
-
* inteira, não uma marca.
|
|
143
|
-
*
|
|
144
|
-
*
|
|
142
|
+
* inteira, não uma marca. No hub, mostra todas as actions dessa organização
|
|
143
|
+
* independentemente do client (marca) de cada action. Não liga a análise
|
|
144
|
+
* GenIA das actions — isso é `Client.hasGenIAAnalysis` do client da action
|
|
145
|
+
* ou `Action.hasGenIAAnalysis`.
|
|
145
146
|
*/
|
|
146
147
|
@Prop({ type: MongooseSchema.Types.ObjectId, ref: 'Organization', required: false })
|
|
147
148
|
organization?: Types.ObjectId;
|
|
@@ -348,6 +348,12 @@ export class Content {
|
|
|
348
348
|
@Prop({ type: String, required: false })
|
|
349
349
|
primetagId?: string;
|
|
350
350
|
|
|
351
|
+
// runId da última captura que tocou o conteúdo (não o da rodada que o
|
|
352
|
+
// criou) — a aprovação e a reclassificação reaproveitam esse runId pra
|
|
353
|
+
// continuar na mesma trilha da coleção `jobs`.
|
|
354
|
+
@Prop({ type: String, required: false })
|
|
355
|
+
captureRunId?: string;
|
|
356
|
+
|
|
351
357
|
@Prop({ type: SentimentAnalysisSchema, required: false, default: null })
|
|
352
358
|
sentimentAnalysis?: SentimentAnalysis | null;
|
|
353
359
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
|
2
|
+
import {
|
|
3
|
+
HydratedDocument,
|
|
4
|
+
Schema as MongooseSchema,
|
|
5
|
+
Types,
|
|
6
|
+
model as MongooseModel,
|
|
7
|
+
} from 'mongoose';
|
|
8
|
+
import { Action } from './action.schema';
|
|
9
|
+
|
|
10
|
+
export type JobDocument = HydratedDocument<Job>;
|
|
11
|
+
|
|
12
|
+
export const JOB_ORIGINS = ['trigger', 'approval', 'reclassify'] as const;
|
|
13
|
+
export type JobOrigin = (typeof JOB_ORIGINS)[number];
|
|
14
|
+
|
|
15
|
+
export const JOB_WORKERS = [
|
|
16
|
+
'content-capture-trigger',
|
|
17
|
+
'content-capture',
|
|
18
|
+
'comment-capture',
|
|
19
|
+
'content-classification',
|
|
20
|
+
'metrics-generator',
|
|
21
|
+
'profile-sync',
|
|
22
|
+
] as const;
|
|
23
|
+
export type JobWorker = (typeof JOB_WORKERS)[number];
|
|
24
|
+
|
|
25
|
+
export const JOB_STATUSES = ['done', 'skipped', 'error'] as const;
|
|
26
|
+
export type JobStatus = (typeof JOB_STATUSES)[number];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Trilha única do pipeline de captura: cada worker grava uma linha por
|
|
30
|
+
* unidade de trabalho (action ou content), e todas as linhas da mesma rodada
|
|
31
|
+
* compartilham o `runId` gerado pelo content-capture-trigger. `requestId`
|
|
32
|
+
* separa cada disparo dentro de um `runId` — na captura é igual ao `runId`;
|
|
33
|
+
* na aprovação/reclassificação a api-campaigns gera um por clique. `input` é
|
|
34
|
+
* o payload recebido, `response` o que veio de fora (Primetag, exportcomments,
|
|
35
|
+
* OpenAI) e `result` o que o worker decidiu ou gravou.
|
|
36
|
+
*/
|
|
37
|
+
@Schema({ collection: 'jobs', timestamps: true })
|
|
38
|
+
export class Job {
|
|
39
|
+
@Prop({ type: MongooseSchema.Types.ObjectId, auto: true, required: false })
|
|
40
|
+
_id?: Types.ObjectId;
|
|
41
|
+
|
|
42
|
+
@Prop({ type: String, required: true })
|
|
43
|
+
runId: string;
|
|
44
|
+
|
|
45
|
+
@Prop({ type: String, required: true })
|
|
46
|
+
requestId: string;
|
|
47
|
+
|
|
48
|
+
@Prop({ type: String, enum: JOB_ORIGINS, required: true })
|
|
49
|
+
origin: JobOrigin;
|
|
50
|
+
|
|
51
|
+
@Prop({ type: String, enum: JOB_WORKERS, required: true })
|
|
52
|
+
worker: JobWorker;
|
|
53
|
+
|
|
54
|
+
@Prop({ type: MongooseSchema.Types.ObjectId, ref: 'Action', required: true })
|
|
55
|
+
actionId: Types.ObjectId | Action;
|
|
56
|
+
|
|
57
|
+
@Prop({ type: MongooseSchema.Types.ObjectId, required: false })
|
|
58
|
+
contentId?: Types.ObjectId;
|
|
59
|
+
|
|
60
|
+
@Prop({ type: String, required: false })
|
|
61
|
+
primetagId?: string;
|
|
62
|
+
|
|
63
|
+
@Prop({ type: String, enum: JOB_STATUSES, required: true })
|
|
64
|
+
status: JobStatus;
|
|
65
|
+
|
|
66
|
+
@Prop({ type: MongooseSchema.Types.Mixed, required: false })
|
|
67
|
+
input?: unknown;
|
|
68
|
+
|
|
69
|
+
@Prop({ type: MongooseSchema.Types.Mixed, required: false })
|
|
70
|
+
response?: unknown;
|
|
71
|
+
|
|
72
|
+
@Prop({ type: MongooseSchema.Types.Mixed, required: false })
|
|
73
|
+
result?: unknown;
|
|
74
|
+
|
|
75
|
+
@Prop({ type: String, required: false })
|
|
76
|
+
error?: string;
|
|
77
|
+
|
|
78
|
+
@Prop({ type: Date, required: true, default: Date.now })
|
|
79
|
+
startedAt: Date;
|
|
80
|
+
|
|
81
|
+
@Prop({ type: Date, required: false })
|
|
82
|
+
finishedAt?: Date;
|
|
83
|
+
|
|
84
|
+
@Prop({ default: Date.now, required: false })
|
|
85
|
+
createdAt?: Date;
|
|
86
|
+
|
|
87
|
+
@Prop({ default: Date.now, required: false })
|
|
88
|
+
updatedAt?: Date;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const JobSchema = SchemaFactory.createForClass(Job);
|
|
92
|
+
|
|
93
|
+
// Reentrega da mesma mensagem atualiza a mesma linha.
|
|
94
|
+
JobSchema.index(
|
|
95
|
+
{ runId: 1, requestId: 1, worker: 1, contentId: 1, primetagId: 1 },
|
|
96
|
+
{ unique: true },
|
|
97
|
+
);
|
|
98
|
+
// Trava do trigger: última rodada de uma action.
|
|
99
|
+
JobSchema.index({ actionId: 1, worker: 1, origin: 1, startedAt: -1 });
|
|
100
|
+
// A trilha guarda o payload bruto de cada rodada e cresce rápido: o Mongo
|
|
101
|
+
// apaga sozinho as linhas com mais de 180 dias.
|
|
102
|
+
JobSchema.index({ createdAt: 1 }, { expireAfterSeconds: 180 * 24 * 60 * 60 });
|
|
103
|
+
// Raw mais recente de uma publication (linhas do content-capture).
|
|
104
|
+
JobSchema.index({ actionId: 1, worker: 1, primetagId: 1, startedAt: -1 });
|
|
105
|
+
|
|
106
|
+
export const JobModel = MongooseModel('Job', JobSchema);
|