feat: добавить базовые сервисы image-platform

- добавлены backend, admin, gateway и worker skeleton
- добавлены Drizzle schema, database package и initial migration
- добавлены shared packages для RabbitMQ topology и S3 helpers
- обновлены dev-инфраструктура, env example, scripts и dependencies
- обновлена документация под versioned image URLs и read-through flow
This commit is contained in:
2026-05-05 09:59:21 +03:00
parent 37592c8b81
commit bcadb85a83
66 changed files with 8698 additions and 213 deletions

View File

@@ -0,0 +1,2 @@
export * from "./jobs.js"
export * from "./topology.js"

View File

@@ -0,0 +1,37 @@
export type GenerateVariantJob = {
jobId: string
variantId: string
}
export function parseGenerateVariantJobBuffer(buffer: Buffer): GenerateVariantJob {
const value = JSON.parse(buffer.toString("utf8")) as unknown
return parseGenerateVariantJob(value)
}
export function parseGenerateVariantJob(value: unknown): GenerateVariantJob {
if (!isRecord(value)) {
throw new Error("generate variant job must be a JSON object")
}
if (!isNonEmptyString(value.jobId)) {
throw new Error("generate variant job must include jobId")
}
if (!isNonEmptyString(value.variantId)) {
throw new Error("generate variant job must include variantId")
}
return {
jobId: value.jobId,
variantId: value.variantId,
}
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value)
}
function isNonEmptyString(value: unknown): value is string {
return typeof value === "string" && value.trim().length > 0
}

View File

@@ -0,0 +1,33 @@
export type QueueTopology = {
generateVariantDeadLetterQueue: string
generateVariantDeadLetterRoutingKey: string
generateVariantQueue: string
generateVariantRoutingKey: string
jobsDeadLetterExchange: string
jobsExchange: string
}
export const DEFAULT_QUEUE_TOPOLOGY: QueueTopology = {
generateVariantDeadLetterQueue: "image.generate-variant.dlq",
generateVariantDeadLetterRoutingKey: "image.generate-variant.dlq",
generateVariantQueue: "image.generate-variant",
generateVariantRoutingKey: "image.generate-variant",
jobsDeadLetterExchange: "image-platform.jobs.dlx",
jobsExchange: "image-platform.jobs",
}
export function loadQueueTopologyFromEnv(env: NodeJS.ProcessEnv = process.env): QueueTopology {
const generateVariantQueue = env.RABBITMQ_GENERATE_VARIANT_QUEUE ?? DEFAULT_QUEUE_TOPOLOGY.generateVariantQueue
const generateVariantDeadLetterQueue =
env.RABBITMQ_GENERATE_VARIANT_DLQ ?? DEFAULT_QUEUE_TOPOLOGY.generateVariantDeadLetterQueue
return {
generateVariantDeadLetterQueue,
generateVariantDeadLetterRoutingKey:
env.RABBITMQ_GENERATE_VARIANT_DLQ_ROUTING_KEY ?? generateVariantDeadLetterQueue,
generateVariantQueue,
generateVariantRoutingKey: env.RABBITMQ_GENERATE_VARIANT_ROUTING_KEY ?? generateVariantQueue,
jobsDeadLetterExchange: env.RABBITMQ_GENERATE_VARIANT_DLX ?? DEFAULT_QUEUE_TOPOLOGY.jobsDeadLetterExchange,
jobsExchange: env.RABBITMQ_JOBS_EXCHANGE ?? DEFAULT_QUEUE_TOPOLOGY.jobsExchange,
}
}