Phase 3 Completed
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
-- Initial migration for RayLab Core (PostgreSQL)
|
||||
-- Requires: CREATE EXTENSION IF NOT EXISTS pgcrypto; (for gen_random_uuid())
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- Extension for UUID generation
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- Enum types
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'userrolesource') THEN
|
||||
CREATE TYPE "UserRoleSource" AS ENUM ('AUTHENTIK', 'SYSTEM');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Users
|
||||
CREATE TABLE IF NOT EXISTS "User" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
authentik_id text UNIQUE,
|
||||
authentik_user_id text UNIQUE,
|
||||
authentik_subject text UNIQUE,
|
||||
username varchar(255) UNIQUE,
|
||||
email varchar(320) UNIQUE,
|
||||
name varchar(255),
|
||||
picture text,
|
||||
is_active boolean NOT NULL DEFAULT true,
|
||||
deleted_at timestamptz,
|
||||
last_seen_at timestamptz,
|
||||
last_synced_at timestamptz,
|
||||
sync_status text,
|
||||
storage_quota bigint DEFAULT 10737418240,
|
||||
storage_used bigint DEFAULT 0,
|
||||
metadata jsonb,
|
||||
last_group_hash text,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_authentik_id ON "User" (authentik_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_username ON "User" (username);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_email ON "User" (email);
|
||||
|
||||
-- Roles
|
||||
CREATE TABLE IF NOT EXISTS "Role" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
code varchar(100) NOT NULL UNIQUE,
|
||||
name varchar(255) NOT NULL,
|
||||
display_name varchar(255),
|
||||
description text,
|
||||
is_default boolean NOT NULL DEFAULT false,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- Permissions
|
||||
CREATE TABLE IF NOT EXISTS "Permission" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
code varchar(150) NOT NULL UNIQUE,
|
||||
name varchar(255) NOT NULL,
|
||||
display_name varchar(255),
|
||||
description text,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- RolePermission
|
||||
CREATE TABLE IF NOT EXISTS "RolePermission" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
role_id uuid NOT NULL REFERENCES "Role"(id) ON DELETE CASCADE,
|
||||
permission_id uuid NOT NULL REFERENCES "Permission"(id) ON DELETE CASCADE,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT uq_role_permission UNIQUE (role_id, permission_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_rolepermission_role_id ON "RolePermission" (role_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_rolepermission_permission_id ON "RolePermission" (permission_id);
|
||||
|
||||
-- UserRole
|
||||
CREATE TABLE IF NOT EXISTS "UserRole" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id uuid NOT NULL REFERENCES "User"(id) ON DELETE CASCADE,
|
||||
role_id uuid NOT NULL REFERENCES "Role"(id) ON DELETE CASCADE,
|
||||
source "UserRoleSource" NOT NULL DEFAULT 'AUTHENTIK',
|
||||
synced_at timestamptz NOT NULL DEFAULT now(),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT uq_user_role UNIQUE (user_id, role_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_userrole_user_id ON "UserRole" (user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_userrole_role_id ON "UserRole" (role_id);
|
||||
|
||||
-- AuthGroupRoleMapping
|
||||
CREATE TABLE IF NOT EXISTS "AuthGroupRoleMapping" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
auth_group varchar(255) NOT NULL,
|
||||
role_id uuid NOT NULL REFERENCES "Role"(id) ON DELETE CASCADE,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_authgroup_name ON "AuthGroupRoleMapping" (auth_group);
|
||||
|
||||
-- AuditLog
|
||||
CREATE TABLE IF NOT EXISTS "AuditLog" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id uuid REFERENCES "User"(id) ON DELETE SET NULL,
|
||||
action varchar(200) NOT NULL,
|
||||
resource varchar(200),
|
||||
resource_id text,
|
||||
details jsonb,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_auditlog_user_id ON "AuditLog" (user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_auditlog_action ON "AuditLog" (action);
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,37 @@
|
||||
-- Phase 4 migration: add ScheduledJob and MediaObject
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ScheduledJob
|
||||
CREATE TABLE IF NOT EXISTS "ScheduledJob" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name varchar(255) NOT NULL,
|
||||
payload jsonb,
|
||||
cron varchar(255),
|
||||
run_at timestamptz,
|
||||
status varchar(50) NOT NULL DEFAULT 'pending',
|
||||
attempts integer NOT NULL DEFAULT 0,
|
||||
last_run_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_scheduledjob_name ON "ScheduledJob" (name);
|
||||
CREATE INDEX IF NOT EXISTS idx_scheduledjob_status ON "ScheduledJob" (status);
|
||||
|
||||
-- MediaObject
|
||||
CREATE TABLE IF NOT EXISTS "MediaObject" (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
owner_user_id uuid REFERENCES "User"(id) ON DELETE SET NULL,
|
||||
storage_key varchar(1024) NOT NULL,
|
||||
filename varchar(1024),
|
||||
mime_type varchar(255),
|
||||
size bigint,
|
||||
is_public boolean NOT NULL DEFAULT false,
|
||||
metadata jsonb,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_owner_user_id ON "MediaObject" (owner_user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_storage_key ON "MediaObject" (storage_key);
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Migration: add Application table
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "Application" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
"code" varchar(100) NOT NULL UNIQUE,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"description" text,
|
||||
"icon" text,
|
||||
"url" text,
|
||||
"applicationsClaim" varchar(255) NOT NULL UNIQUE,
|
||||
"isActive" boolean NOT NULL DEFAULT true,
|
||||
"displayOrder" integer NOT NULL DEFAULT 0,
|
||||
"createdAt" timestamptz NOT NULL DEFAULT now(),
|
||||
"updatedAt" timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Application_code_idx" ON "Application" ("code");
|
||||
CREATE INDEX IF NOT EXISTS "Application_applicationsClaim_idx" ON "Application" ("applicationsClaim");
|
||||
+149
-78
@@ -1,5 +1,5 @@
|
||||
// Prisma schema
|
||||
// Basic User model for RayLab Core
|
||||
// Prisma schema for RayLab Core - Phase 1
|
||||
// PostgreSQL datasource. DATABASE_URL must be set in environment.
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
@@ -11,99 +11,170 @@ datasource db {
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
|
||||
authentikId String? @unique
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
authentikId String? @unique
|
||||
authentikUserId String? @unique
|
||||
authentikSubject String? @unique
|
||||
username String? @db.VarChar(255) @unique
|
||||
email String? @db.VarChar(320) @unique
|
||||
name String? @db.VarChar(255)
|
||||
picture String?
|
||||
isActive Boolean @default(true)
|
||||
deletedAt DateTime?
|
||||
lastSeenAt DateTime?
|
||||
lastSyncedAt DateTime?
|
||||
syncStatus String?
|
||||
storageQuota BigInt? @default(10737418240)
|
||||
storageUsed BigInt? @default(0)
|
||||
metadata Json?
|
||||
userRoles UserRole[]
|
||||
auditLogs AuditLog[]
|
||||
lastGroupHash String? @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
username String @unique
|
||||
email String @unique
|
||||
|
||||
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// storage (in bytes)
|
||||
storageQuota BigInt @default(10737418240)
|
||||
storageUsed BigInt @default(0)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
lastSeenAt DateTime?
|
||||
lastSyncedAt DateTime?
|
||||
syncStatus String?
|
||||
|
||||
roles UserRole[]
|
||||
permissions UserPermission[]
|
||||
|
||||
@@index([authentikId])
|
||||
@@index([username])
|
||||
@@index([email])
|
||||
}
|
||||
|
||||
model Role {
|
||||
id String @id @default(uuid())
|
||||
|
||||
code String @unique
|
||||
name String
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
code String @unique @db.VarChar(100)
|
||||
name String @db.VarChar(255)
|
||||
displayName String? @db.VarChar(255)
|
||||
description String?
|
||||
|
||||
isDefault Boolean @default(false)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
users UserRole[]
|
||||
permissions RolePermission[]
|
||||
isDefault Boolean @default(false)
|
||||
rolePermissions RolePermission[]
|
||||
userRoles UserRole[]
|
||||
mappings AuthGroupRoleMapping[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Permission {
|
||||
id String @id @default(uuid())
|
||||
|
||||
code String @unique
|
||||
name String
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
code String @unique @db.VarChar(150)
|
||||
name String @db.VarChar(255)
|
||||
displayName String? @db.VarChar(255)
|
||||
description String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
roles RolePermission[]
|
||||
users UserPermission[]
|
||||
}
|
||||
|
||||
model UserRole {
|
||||
userId String
|
||||
roleId String
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
|
||||
assignedAt DateTime @default(now())
|
||||
assignedBy String
|
||||
|
||||
@@id([userId, roleId])
|
||||
rolePermissions RolePermission[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model RolePermission {
|
||||
roleId String
|
||||
permissionId String
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
roleId String @db.Uuid
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
permissionId String @db.Uuid
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
assignedAt DateTime @default(now())
|
||||
assignedBy String
|
||||
|
||||
@@id([roleId, permissionId])
|
||||
@@unique([roleId, permissionId])
|
||||
@@index([roleId])
|
||||
@@index([permissionId])
|
||||
}
|
||||
|
||||
model UserPermission {
|
||||
userId String
|
||||
permissionId String
|
||||
enum UserRoleSource {
|
||||
AUTHENTIK
|
||||
SYSTEM
|
||||
}
|
||||
|
||||
model UserRole {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String @db.Uuid
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
roleId String @db.Uuid
|
||||
source UserRoleSource @default(AUTHENTIK)
|
||||
syncedAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([userId, roleId])
|
||||
@@index([userId])
|
||||
@@index([roleId])
|
||||
}
|
||||
|
||||
model AuthGroupRoleMapping {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
authGroup String @db.VarChar(255)
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
roleId String @db.Uuid
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([authGroup])
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
userId String? @db.Uuid
|
||||
action String @db.VarChar(200)
|
||||
resource String? @db.VarChar(200)
|
||||
resourceId String?
|
||||
details Json?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([action])
|
||||
}
|
||||
|
||||
model ScheduledJob {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String @db.VarChar(255)
|
||||
payload Json?
|
||||
cron String?
|
||||
runAt DateTime?
|
||||
status String @db.VarChar(50) @default("pending")
|
||||
attempts Int @default(0)
|
||||
lastRunAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([name])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model MediaObject {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
ownerUserId String? @db.Uuid
|
||||
owner User? @relation(fields: [ownerUserId], references: [id], onDelete: SetNull)
|
||||
storageKey String @db.VarChar(1024)
|
||||
filename String? @db.VarChar(1024)
|
||||
mimeType String? @db.VarChar(255)
|
||||
size BigInt?
|
||||
isPublic Boolean @default(false)
|
||||
metadata Json?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([ownerUserId])
|
||||
@@index([storageKey])
|
||||
}
|
||||
|
||||
|
||||
|
||||
model Application {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
code String @unique @db.VarChar(100)
|
||||
name String @db.VarChar(255)
|
||||
description String?
|
||||
icon String?
|
||||
url String?
|
||||
applicationsClaim String @unique @db.VarChar(255)
|
||||
isActive Boolean @default(true)
|
||||
displayOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([code])
|
||||
@@index([applicationsClaim])
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
assignedAt DateTime @default(now())
|
||||
assignedBy String
|
||||
|
||||
@@id([userId, permissionId])
|
||||
}
|
||||
+171
-1
@@ -1 +1,171 @@
|
||||
// prisma seed placeholder
|
||||
/**
|
||||
* Prisma seed script for RayLab Core - Phase 1
|
||||
* Run with: npx ts-node prisma/seed.ts
|
||||
* Requires DATABASE_URL env var.
|
||||
*/
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding default roles, permissions, and mappings...');
|
||||
|
||||
// Default roles
|
||||
const roles = [
|
||||
{ name: 'Owner', displayName: 'Owner', description: 'Platform owner with full access' },
|
||||
{ name: 'Employee', displayName: 'Employee', description: 'Employee role with internal permissions' },
|
||||
{ name: 'Family', displayName: 'Family', description: 'Family role with limited access' },
|
||||
];
|
||||
|
||||
for (const r of roles) {
|
||||
const code = r.name.toLowerCase();
|
||||
await prisma.role.upsert({
|
||||
where: { code },
|
||||
update: { name: r.name, displayName: r.displayName, description: r.description },
|
||||
create: { code, name: r.name, displayName: r.displayName, description: r.description },
|
||||
});
|
||||
}
|
||||
|
||||
// Default permissions (resource.action lowercase as requested)
|
||||
const permissions = [
|
||||
'users.create',
|
||||
'users.read',
|
||||
'users.update',
|
||||
'users.delete',
|
||||
'roles.create',
|
||||
'roles.read',
|
||||
'roles.update',
|
||||
'roles.delete',
|
||||
'permissions.create',
|
||||
'permissions.read',
|
||||
'permissions.update',
|
||||
'permissions.delete',
|
||||
'audit.read',
|
||||
'storage.read',
|
||||
'storage.write',
|
||||
'storage.delete',
|
||||
'media.read',
|
||||
'media.write',
|
||||
'media.delete',
|
||||
'scheduler.read',
|
||||
'scheduler.manage',
|
||||
];
|
||||
|
||||
for (const p of permissions) {
|
||||
// Use code as canonical identifier (resource.action). Use name == code for now.
|
||||
const code = p;
|
||||
await prisma.permission.upsert({
|
||||
where: { code },
|
||||
update: { name: p, description: null },
|
||||
create: { code, name: p, description: null },
|
||||
});
|
||||
}
|
||||
|
||||
// Assign permissions to roles (example mapping)
|
||||
const owner = await prisma.role.findUnique({ where: { code: 'owner' } });
|
||||
const employee = await prisma.role.findUnique({ where: { code: 'employee' } });
|
||||
const family = await prisma.role.findUnique({ where: { code: 'family' } });
|
||||
|
||||
if (!owner || !employee || !family) {
|
||||
throw new Error('Default roles missing after upsert');
|
||||
}
|
||||
|
||||
// Owner -> all permissions
|
||||
const allPerms = await prisma.permission.findMany();
|
||||
for (const perm of allPerms) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: { roleId_permissionId: { roleId: owner.id, permissionId: perm.id } },
|
||||
update: {},
|
||||
create: { roleId: owner.id, permissionId: perm.id },
|
||||
});
|
||||
}
|
||||
|
||||
// Employee -> a subset
|
||||
const employeePerms = [
|
||||
'users.read',
|
||||
'permissions.read',
|
||||
'scheduler.read',
|
||||
'scheduler.manage',
|
||||
'media.read',
|
||||
'media.write',
|
||||
];
|
||||
for (const p of employeePerms) {
|
||||
const perm = await prisma.permission.findUnique({ where: { code: p } });
|
||||
if (perm) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: { roleId_permissionId: { roleId: employee.id, permissionId: perm.id } },
|
||||
update: {},
|
||||
create: { roleId: employee.id, permissionId: perm.id },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Family -> limited
|
||||
const familyPerms = [
|
||||
'media.read',
|
||||
'media.write',
|
||||
'media.delete',
|
||||
];
|
||||
for (const p of familyPerms) {
|
||||
const perm = await prisma.permission.findUnique({ where: { code: p } });
|
||||
if (perm) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: { roleId_permissionId: { roleId: family.id, permissionId: perm.id } },
|
||||
update: {},
|
||||
create: { roleId: family.id, permissionId: perm.id },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Authentik group mappings
|
||||
const mappings = [
|
||||
{ authGroup: 'RL-Owner', roleName: 'Owner' },
|
||||
{ authGroup: 'RL-Employee', roleName: 'Employee' },
|
||||
{ authGroup: 'RL-Family', roleName: 'Family' },
|
||||
];
|
||||
|
||||
for (const m of mappings) {
|
||||
const role = await prisma.role.findUnique({ where: { name: m.roleName } });
|
||||
if (!role) continue;
|
||||
// Ensure mapping exists (authGroup + roleId). AuthGroup can map to multiple roles.
|
||||
const existing = await prisma.authGroupRoleMapping.findFirst({ where: { authGroup: m.authGroup, roleId: role.id } });
|
||||
if (!existing) {
|
||||
await prisma.authGroupRoleMapping.create({ data: { authGroup: m.authGroup, roleId: role.id } });
|
||||
}
|
||||
}
|
||||
|
||||
// Seed application catalog
|
||||
const apps = [
|
||||
{ code: 'core', name: 'Core', description: 'RayLab Core Dashboard', icon: 'mdi-apps', url: '/', applicationsClaim: 'core', displayOrder: 0 },
|
||||
{ code: 'warung', name: 'Warung', description: 'Warung app', icon: 'mdi-store', url: '/warung', applicationsClaim: 'warung', displayOrder: 10 },
|
||||
{ code: 'nextcloud', name: 'Nextcloud', description: 'Nextcloud', icon: 'mdi-cloud', url: 'https://nextcloud.example', applicationsClaim: 'nextcloud', displayOrder: 20 },
|
||||
{ code: 'jellyfin', name: 'Jellyfin', description: 'Jellyfin media server', icon: 'mdi-movie', url: 'https://jellyfin.example', applicationsClaim: 'jellyfin', displayOrder: 30 },
|
||||
{ code: 'forgejo', name: 'Forgejo', description: 'Forgejo git server', icon: 'mdi-source-repository', url: 'https://forgejo.example', applicationsClaim: 'forgejo', displayOrder: 40 },
|
||||
{ code: 'immich', name: 'Immich', description: 'Immich photo server', icon: 'mdi-image', url: 'https://immich.example', applicationsClaim: 'immich', displayOrder: 50 },
|
||||
{ code: 'grafana', name: 'Grafana', description: 'Grafana monitoring', icon: 'mdi-chart-line', url: 'https://grafana.example', applicationsClaim: 'grafana', displayOrder: 60 },
|
||||
{ code: 'vaultwarden', name: 'Vaultwarden', description: 'Vaultwarden password manager', icon: 'mdi-lock', url: 'https://vaultwarden.example', applicationsClaim: 'vaultwarden', displayOrder: 70 },
|
||||
{ code: 'homepage', name: 'Homepage', description: 'Homepage', icon: 'mdi-home', url: 'https://home.example', applicationsClaim: 'homepage', displayOrder: 80 },
|
||||
];
|
||||
|
||||
for (const a of apps) {
|
||||
await prisma.application.upsert({
|
||||
where: { code: a.code },
|
||||
update: { name: a.name, description: a.description, icon: a.icon, url: a.url, applicationsClaim: a.applicationsClaim, isActive: true, displayOrder: a.displayOrder },
|
||||
create: { code: a.code, name: a.name, description: a.description, icon: a.icon, url: a.url, applicationsClaim: a.applicationsClaim, isActive: true, displayOrder: a.displayOrder },
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Seeding completed.');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(async (e) => {
|
||||
console.error(e);
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user