f0b570284e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
2.5 KiB
TypeScript
52 lines
2.5 KiB
TypeScript
import { model, models, Schema, type InferSchemaType, type Model } from "mongoose";
|
||
import { ATTACHMENT_KINDS } from "@/shared/attachments";
|
||
|
||
/** Ek dosyanın bağlanabileceği kayıt türleri (ileride: alışveriş fişi, cari hareket…). */
|
||
export const ATTACHMENT_OWNER_TYPES = ["transaction", "product"] as const;
|
||
export type AttachmentOwnerType = (typeof ATTACHMENT_OWNER_TYPES)[number];
|
||
|
||
/**
|
||
* Ek dosya meta verisi (Bölüm 7.4). Dosyanın kendisi depolama sürücüsünde, rastgele anahtarla.
|
||
* - Yüklenince `ownerId: null` (bekleyen); kayıt kaydedilince sahibine bağlanır.
|
||
* - Bekleyen ek yalnızca yükleyene görünür ve 24 saat içinde bağlanmazsa temizlenir.
|
||
* - Kayıttan çıkarılan ek `deletedAt` alır; dosya saklama süresi sonunda silinir.
|
||
*/
|
||
const attachmentSchema = new Schema(
|
||
{
|
||
householdId: { type: Schema.Types.ObjectId, required: true },
|
||
ownerType: { type: String, enum: ATTACHMENT_OWNER_TYPES, default: null },
|
||
ownerId: { type: Schema.Types.ObjectId, default: null },
|
||
kind: { type: String, enum: ATTACHMENT_KINDS, required: true },
|
||
/** Saklanan içeriğin türü (görseller her zaman WebP'ye çevrilir). */
|
||
mimeType: { type: String, enum: ["image/webp", "application/pdf"], required: true },
|
||
/** Kaynak tür (jpeg, png, webp, heic, pdf) — bilgi amaçlı. */
|
||
sourceType: { type: String, required: true },
|
||
originalName: { type: String, default: "", maxlength: 120 },
|
||
size: { type: Number, required: true },
|
||
originalSize: { type: Number, required: true },
|
||
width: { type: Number, default: null },
|
||
height: { type: Number, default: null },
|
||
storageKey: { type: String, required: true },
|
||
thumbKey: { type: String, default: null },
|
||
uploadedBy: { type: Schema.Types.ObjectId, required: true },
|
||
/** Kayıt içindeki sıra (carousel sırası). */
|
||
order: { type: Number, default: 0 },
|
||
deletedAt: { type: Date, default: null },
|
||
},
|
||
{ timestamps: true, collection: "attachments" },
|
||
);
|
||
|
||
attachmentSchema.index({ householdId: 1, ownerType: 1, ownerId: 1, deletedAt: 1, order: 1 });
|
||
attachmentSchema.index({ ownerId: 1, createdAt: 1 });
|
||
attachmentSchema.index(
|
||
{ deletedAt: 1 },
|
||
{ partialFilterExpression: { deletedAt: { $type: "date" } } },
|
||
);
|
||
attachmentSchema.index({ storageKey: 1 }, { unique: true });
|
||
|
||
export type Attachment = InferSchemaType<typeof attachmentSchema>;
|
||
|
||
export const AttachmentModel: Model<Attachment> =
|
||
(models.Attachment as Model<Attachment> | undefined) ??
|
||
model<Attachment>("Attachment", attachmentSchema);
|