Initial commit: buildfor_life_repair inventory system

SvelteKit + PostgreSQL app for tracking vintage computers, audio equipment,
components, and installation history. Features device/component CRUD, operation
logs, QR code labels, global search, image uploads, and dark mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 17:11:05 +07:00
commit 6f0e0ad6c6
64 changed files with 8996 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
import type { PageServerLoad } from './$types';
import { db } from '$lib/server/db/index.js';
import { devices, deviceImages, locations } from '$lib/server/db/schema.js';
import { eq, ilike, or, count, desc, and, sql } from 'drizzle-orm';
export const load: PageServerLoad = async ({ url }) => {
const category = url.searchParams.get('category');
const condition = url.searchParams.get('condition');
const search = url.searchParams.get('q');
const page = Math.max(1, Number(url.searchParams.get('page') ?? 1));
const pageSize = 24;
const conditions = [eq(devices.disabled, false)];
if (category) {
conditions.push(eq(devices.category, category));
}
if (condition === 'needs-repair') {
conditions.push(
or(eq(devices.condition, 'In Repair'), eq(devices.condition, 'Waiting for Repair'))!
);
} else if (condition) {
conditions.push(eq(devices.condition, condition));
}
if (search) {
conditions.push(
or(
ilike(devices.title, `%${search}%`),
ilike(devices.brand, `%${search}%`),
ilike(devices.model, `%${search}%`),
ilike(devices.serialNumber, `%${search}%`)
)!
);
}
const where = conditions.length > 0 ? and(...conditions) : undefined;
const [totalResult] = await db.select({ value: count() }).from(devices).where(where);
const total = totalResult?.value ?? 0;
const deviceList = await db
.select({
id: devices.id,
title: devices.title,
category: devices.category,
brand: devices.brand,
model: devices.model,
condition: devices.condition,
year: devices.year,
locationName: locations.name
})
.from(devices)
.leftJoin(locations, eq(devices.locationId, locations.id))
.where(where)
.orderBy(desc(devices.updatedAt))
.limit(pageSize)
.offset((page - 1) * pageSize);
// Fetch first image for each device
const deviceIds = deviceList.map((d) => d.id);
let imageMap: Record<string, string> = {};
if (deviceIds.length > 0) {
const images = await db
.select({
deviceId: deviceImages.deviceId,
thumbnailPath: deviceImages.thumbnailPath,
filePath: deviceImages.filePath
})
.from(deviceImages)
.where(sql`${deviceImages.deviceId} IN ${deviceIds}`)
.orderBy(deviceImages.sortOrder);
for (const img of images) {
if (!imageMap[img.deviceId]) {
imageMap[img.deviceId] = img.thumbnailPath ?? img.filePath;
}
}
}
return {
devices: deviceList.map((d) => ({
...d,
thumbnail: imageMap[d.id] ?? null
})),
total,
page,
pageSize,
filters: { category, condition, search }
};
};