Skip to main content

Homepage Links Backend Plugin

The Homepage Links Backend provides persistence for user homepage preferences, onboarding links, and team documentation links.

Overview

PropertyValue
Package@internal/plugin-homepage-links-backend
TypeBackend
Plugin IDhomepage-links
DatabasePostgreSQL via Knex

Architecture

API Endpoints

MethodEndpointDescription
GET/linksGet user's links
GET/links/by-group/:groupRefGet links for group
POST/linksCreate new link
DELETE/links/:idDelete entire link
DELETE/links/:id/groups/:groupRefRemove link from group
GET/autocompleteSearch existing links

Preferences

MethodEndpointDescription
GET/preferencesGet user preferences
PUT/preferencesUpdate preferences

User Info

MethodEndpointDescription
GET/user-groupsGet current user's groups

Database Schema

ColumnTypeDescription
idUUIDPrimary key
titleVARCHARLink title
urlVARCHARLink URL
descriptionTEXTOptional description
typeVARCHAR'onboarding' or 'team'
iconVARCHARIcon identifier
group_refsJSONBArray of group refs
created_byVARCHARCreator user reference
created_atTIMESTAMPCreation time
updated_atTIMESTAMPLast update time

user_preferences

ColumnTypeDescription
user_refVARCHARPrimary key (user ref)
collapsed_sectionsJSONBArray of collapsed IDs
hidden_itemsJSONBArray of hidden item IDs
group_orderJSONBCustom group ordering
updated_atTIMESTAMPLast update time

Links shown in the onboarding section for new team members:

interface OnboardingLink {
id: string;
title: string;
url: string;
description: string;
type: "onboarding";
icon: "book" | "code" | "settings" | "help";
groupRefs: string[];
}

Links for team documentation and resources:

interface TeamLink {
id: string;
title: string;
url: string;
description: string;
type: "team";
icon: "docs" | "wiki" | "repo" | "dashboard";
groupRefs: string[];
}

Request/Response Schemas

// POST /links
interface CreateLinkRequest {
title: string;
url: string;
description?: string;
type: "onboarding" | "team";
icon?: string;
groupRefs: string[];
}

// Zod schema
const createLinkSchema = z.object({
title: z.string().min(1).max(255),
url: z.string().url(),
description: z.string().max(1000).optional(),
type: z.enum(["onboarding", "team"]),
icon: z.string().optional(),
groupRefs: z.array(z.string()).min(1),
});

User Preferences

// PUT /preferences
interface UpdatePreferencesRequest {
collapsedSections?: string[];
hiddenItems?: string[];
groupOrder?: string[];
}

// Zod schema
const updatePreferencesSchema = z.object({
collapsedSections: z.array(z.string()).optional(),
hiddenItems: z.array(z.string()).optional(),
groupOrder: z.array(z.string()).optional(),
});

LinksStore Service

interface LinksStore {
// Link operations
getLinks(groupRefs: string[]): Promise<Link[]>;
getLinksByGroup(groupRef: string): Promise<Link[]>;
createLink(input: CreateLinkInput, createdBy: string): Promise<Link>;
deleteLink(id: string): Promise<void>;
removeLinkFromGroup(id: string, groupRef: string): Promise<void>;
autocomplete(query: string): Promise<Link[]>;

// Preference operations
getPreferences(userRef: string): Promise<UserPreferences>;
updatePreferences(
userRef: string,
prefs: Partial<UserPreferences>,
): Promise<UserPreferences>;

// User info
getUserGroups(claims: JWTClaims): string[];
}

Group-Based Access

Links are scoped to groups:

URL Normalization

URLs are normalized before storage:

class UrlNormalizer {
normalize(url: string): string {
// Add protocol if missing
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "https://" + url;
}
// Remove trailing slash
url = url.replace(/\/$/, "");
// Lowercase domain
const parsed = new URL(url);
parsed.hostname = parsed.hostname.toLowerCase();
return parsed.toString();
}
}

Usage Examples

curl -X POST http://localhost:7007/api/homepage-links/links \
-H "Content-Type: application/json" \
-d '{
"title": "Getting Started Guide",
"url": "https://docs.example.com/onboarding",
"description": "New team member onboarding documentation",
"type": "onboarding",
"icon": "book",
"groupRefs": ["group:default/platform-team"]
}'
curl http://localhost:7007/api/homepage-links/links

Update Preferences

curl -X PUT http://localhost:7007/api/homepage-links/preferences \
-H "Content-Type: application/json" \
-d '{
"collapsedSections": ["onboarding"],
"groupOrder": ["platform-team", "devops"]
}'