Initial commit for gscMy carved out as its own repo (was tracked
loosely under the monorepo's web/ which is gitignored).
What this contains:
- Auth: next-auth v5 via @gsc/web-kit createAuth (Keycloak only,
identity sourced from claims, no admin.users writes)
- Chrome: @gsc/web-kit AdminShell — replaces the legacy MyShell.
Sidebar JSON config carried over and mapped to DbMenuItem.
- Middleware: createAuthMiddleware. Public: /access-denied,
/auth/keycloak, /signed-out, /api/health, /api/pam/approve.
- RP-initiated signout at /api/auth/signout → Keycloak end_session →
/signed-out (mirrors gscAdmin).
- Phosphor-iconned access-denied + signed-out landing pages.
PAM/JIT request flow (ported from gscAdmin's pre-strip git history):
- /access page (Active + Eligible tables, request modal with
duration slider + justification + optional MFA)
- API: /api/pam/{eligible, active, audit, request, approve/:token,
revoke/:id}
- src/lib/{authz, pam, pam-mail, pam-mfa}.ts — same files as
gscAdmin had before the strip. PAM tables (admin.privilege_*)
are shared with gscAdmin; gscMy uses the same Prisma model defs.
- Top-bar widget shows active grants with countdown + revoke.
Build/Deploy: Dockerfile (monorepo-root context), k8s manifests for
my.gosec.internal, self-signed TLS placeholder, DNS A record.
Keycloak gsc-my client extended to include my.gosec.internal/* in
redirect_uris + web_origins.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
112 lines
9.4 KiB
TypeScript
112 lines
9.4 KiB
TypeScript
/**
|
|
* Seed settings definitions into gsc_core.admin.settings_definitions.
|
|
* Upserts on (category, key) unique constraint.
|
|
*
|
|
* Usage: npx tsx scripts/seed-settings.ts
|
|
*/
|
|
|
|
import { PrismaClient } from "@prisma/client";
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
interface SettingDef {
|
|
category: string;
|
|
key: string;
|
|
dataType: string;
|
|
defaultValue: unknown;
|
|
description: string;
|
|
allowedValues?: unknown;
|
|
displayOrder: number;
|
|
}
|
|
|
|
const SETTINGS: SettingDef[] = [
|
|
// ─── user.general ──────────────────────────────────────────
|
|
{ category: "user.general", key: "language", dataType: "string", defaultValue: "en", description: "Display language", allowedValues: ["en", "de", "fr"], displayOrder: 1 },
|
|
{ category: "user.general", key: "timezone", dataType: "string", defaultValue: "Europe/Helsinki", description: "User timezone for timestamps and scheduling", displayOrder: 2 },
|
|
{ category: "user.general", key: "dateFormat", dataType: "string", defaultValue: "DD/MM/YYYY", description: "Date display format", allowedValues: ["DD/MM/YYYY", "MM/DD/YYYY", "YYYY-MM-DD"], displayOrder: 3 },
|
|
{ category: "user.general", key: "theme", dataType: "string", defaultValue: "light", description: "UI theme", allowedValues: ["light", "dark", "system"], displayOrder: 4 },
|
|
{ category: "user.general", key: "compactMode", dataType: "boolean", defaultValue: false, description: "Reduce spacing for condensed layout", displayOrder: 5 },
|
|
{ category: "user.general", key: "showWelcomeScreen", dataType: "boolean", defaultValue: true, description: "Show welcome greeting on dashboard", displayOrder: 6 },
|
|
{ category: "user.general", key: "defaultLandingPage", dataType: "string", defaultValue: "/", description: "Default page after login", allowedValues: ["/", "/marketplace", "/account/profile"], displayOrder: 7 },
|
|
|
|
// ─── user.notifications ────────────────────────────────────
|
|
{ category: "user.notifications", key: "notifyEmail", dataType: "boolean", defaultValue: true, description: "Receive important updates via email", displayOrder: 1 },
|
|
{ category: "user.notifications", key: "notifyBrowser", dataType: "boolean", defaultValue: true, description: "Show desktop push notifications", displayOrder: 2 },
|
|
{ category: "user.notifications", key: "notifyActivity", dataType: "boolean", defaultValue: true, description: "Get notified about mentions, comments, shares", displayOrder: 3 },
|
|
{ category: "user.notifications", key: "notifySecurityAlerts", dataType: "boolean", defaultValue: true, description: "Notify about suspicious activity", displayOrder: 4 },
|
|
{ category: "user.notifications", key: "notifyProductUpdates", dataType: "boolean", defaultValue: false, description: "Get notified about new features", displayOrder: 5 },
|
|
|
|
// ─── user.email ────────────────────────────────────────────
|
|
{ category: "user.email", key: "messagesPerPage", dataType: "string", defaultValue: "50", description: "Messages per page in email client", allowedValues: ["25", "50", "100"], displayOrder: 1 },
|
|
{ category: "user.email", key: "defaultReplyMode", dataType: "string", defaultValue: "reply", description: "Default reply mode", allowedValues: ["reply", "replyAll"], displayOrder: 2 },
|
|
{ category: "user.email", key: "emailSignature", dataType: "string", defaultValue: "", description: "Email signature text", displayOrder: 3 },
|
|
{ category: "user.email", key: "composeFormat", dataType: "string", defaultValue: "html", description: "Email compose format", allowedValues: ["html", "plain"], displayOrder: 4 },
|
|
{ category: "user.email", key: "readReceipts", dataType: "boolean", defaultValue: true, description: "Request read receipts by default", displayOrder: 5 },
|
|
|
|
// ─── user.calendar ─────────────────────────────────────────
|
|
{ category: "user.calendar", key: "calendarDefaultView", dataType: "string", defaultValue: "week", description: "Default calendar view", allowedValues: ["month", "week", "day", "agenda"], displayOrder: 1 },
|
|
{ category: "user.calendar", key: "weekStartsOn", dataType: "string", defaultValue: "monday", description: "First day of week", allowedValues: ["monday", "sunday", "saturday"], displayOrder: 2 },
|
|
{ category: "user.calendar", key: "workingHoursStart", dataType: "string", defaultValue: "08:00", description: "Working hours start time", displayOrder: 3 },
|
|
{ category: "user.calendar", key: "workingHoursEnd", dataType: "string", defaultValue: "17:00", description: "Working hours end time", displayOrder: 4 },
|
|
{ category: "user.calendar", key: "defaultReminder", dataType: "string", defaultValue: "15", description: "Default reminder (minutes before)", allowedValues: ["5", "10", "15", "30", "60"], displayOrder: 5 },
|
|
{ category: "user.calendar", key: "defaultEventDuration", dataType: "string", defaultValue: "60", description: "Default event duration (minutes)", allowedValues: ["15", "30", "60", "90"], displayOrder: 6 },
|
|
|
|
// ─── user.privacy ──────────────────────────────────────────
|
|
{ category: "user.privacy", key: "profileVisibility", dataType: "string", defaultValue: "contacts", description: "Who can see your profile", allowedValues: ["public", "contacts", "private"], displayOrder: 1 },
|
|
{ category: "user.privacy", key: "showEmail", dataType: "boolean", defaultValue: false, description: "Show email on profile", displayOrder: 2 },
|
|
{ category: "user.privacy", key: "showPhone", dataType: "boolean", defaultValue: false, description: "Show phone on profile", displayOrder: 3 },
|
|
{ category: "user.privacy", key: "showLocation", dataType: "boolean", defaultValue: true, description: "Show location on profile", displayOrder: 4 },
|
|
{ category: "user.privacy", key: "showOnlineStatus", dataType: "boolean", defaultValue: true, description: "Show online status", displayOrder: 5 },
|
|
{ category: "user.privacy", key: "allowDirectMessages", dataType: "boolean", defaultValue: true, description: "Allow direct messages", displayOrder: 6 },
|
|
{ category: "user.privacy", key: "allowGroupInvites", dataType: "boolean", defaultValue: true, description: "Allow group invites", displayOrder: 7 },
|
|
{ category: "user.privacy", key: "allowMentions", dataType: "boolean", defaultValue: true, description: "Allow @mentions", displayOrder: 8 },
|
|
{ category: "user.privacy", key: "allowAnalytics", dataType: "boolean", defaultValue: true, description: "Share anonymous usage data", displayOrder: 9 },
|
|
{ category: "user.privacy", key: "allowPersonalization", dataType: "boolean", defaultValue: true, description: "Allow personalized recommendations", displayOrder: 10 },
|
|
{ category: "user.privacy", key: "allowThirdPartyIntegrations", dataType: "boolean", defaultValue: false, description: "Allow connected apps to access data", displayOrder: 11 },
|
|
{ category: "user.privacy", key: "emailMarketing", dataType: "boolean", defaultValue: false, description: "Receive marketing emails", displayOrder: 12 },
|
|
{ category: "user.privacy", key: "emailProductUpdates", dataType: "boolean", defaultValue: true, description: "Receive product update emails", displayOrder: 13 },
|
|
{ category: "user.privacy", key: "emailSecurityAlerts", dataType: "boolean", defaultValue: true, description: "Receive security alert emails", displayOrder: 14 },
|
|
{ category: "user.privacy", key: "emailActivityDigest", dataType: "boolean", defaultValue: true, description: "Receive weekly activity digest", displayOrder: 15 },
|
|
{ category: "user.privacy", key: "activityHistoryRetention", dataType: "string", defaultValue: "90d", description: "Activity history retention period", allowedValues: ["30d", "90d", "1y", "forever"], displayOrder: 16 },
|
|
{ category: "user.privacy", key: "searchHistoryEnabled", dataType: "boolean", defaultValue: true, description: "Save search history", displayOrder: 17 },
|
|
{ category: "user.privacy", key: "sessionTimeout", dataType: "number", defaultValue: 60, description: "Session timeout in minutes", displayOrder: 18 },
|
|
|
|
// ─── user.security ─────────────────────────────────────────
|
|
{ category: "user.security", key: "loginNotifications", dataType: "boolean", defaultValue: true, description: "Notify on new device logins", displayOrder: 1 },
|
|
];
|
|
|
|
async function main() {
|
|
console.log(`Seeding ${SETTINGS.length} settings definitions...`);
|
|
|
|
for (const s of SETTINGS) {
|
|
await prisma.settingsDefinition.upsert({
|
|
where: { category_key: { category: s.category, key: s.key } },
|
|
update: {
|
|
dataType: s.dataType,
|
|
defaultValue: s.defaultValue as never,
|
|
description: s.description,
|
|
allowed_values: s.allowedValues ? (s.allowedValues as never) : undefined,
|
|
display_order: s.displayOrder,
|
|
},
|
|
create: {
|
|
category: s.category,
|
|
key: s.key,
|
|
dataType: s.dataType,
|
|
defaultValue: s.defaultValue as never,
|
|
description: s.description,
|
|
allowed_values: s.allowedValues ? (s.allowedValues as never) : undefined,
|
|
display_order: s.displayOrder,
|
|
},
|
|
});
|
|
}
|
|
|
|
console.log("Done.");
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
})
|
|
.finally(() => prisma.$disconnect());
|