# How to Add Custom Addons to TREK: A Complete Implementation Guide

> Learn how to add custom addons to TREK with this implementation guide. Register identifiers, insert seed records, and use isAddonEnabled utility for backend logic.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: how-to-guide
- Published: 2026-07-03

---

**You can add custom addons to TREK by registering a new identifier in [`server/src/addons.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/addons.ts), inserting a seed record in [`server/src/db/seeds.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/db/seeds.ts), and wrapping your backend logic with the `isAddonEnabled()` utility.**

TREK is a modular travel planning application where features are packaged as optional addons that administrators can toggle on or off. If you need to extend TREK with proprietary features or third-party integrations, you can add custom addons to the codebase following the same architecture used for built-in features like Packing, Budget, and Collab.

## Step 1: Register the Addon Identifier

Every addon in TREK is identified by a string constant defined in the central registry. Open [`server/src/addons.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/addons.ts) and add your custom addon to the `ADDON_IDS` object.

```typescript
// server/src/addons.ts
export const ADDON_IDS = {
  MCP: 'mcp',
  PACKING: 'packing',
  BUDGET: 'budget',
  DOCUMENTS: 'documents',
  VACAY: 'vacay',
  ATLAS: 'atlas',
  COLLAB: 'collab',
  JOURNEY: 'journey',
  AIRTRAIL: 'airtrail',
  // Your custom addon
  WEATHER: 'weather',
} as const;

```

This constant serves as the single source of truth for your addon's identifier across the entire application.

## Step 2: Seed the Database Entry

To make your addon appear in the admin panel, you must insert a record into the database. Modify [`server/src/db/seeds.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/db/seeds.ts) to add a seed entry for the `Addon` entity.

```typescript
// server/src/db/seeds.ts
await queryRunner.manager.insert(Addon, {
  id: ADDON_IDS.WEATHER,
  enabled: false,
  name: 'Weather',
  description: 'Show forecast for trip destinations',
});

```

This seed ensures the addon appears in the **Admin → Addons** panel with a toggle switch defaulted to off.

## Step 3: Gate Backend Logic

Protect your addon's functionality by checking the activation state before executing logic. Import `isAddonEnabled` from [`server/src/addons.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/addons.ts) and use it to guard your services.

```typescript
// server/src/services/weather/weather.service.ts
import { isAddonEnabled } from '../addons';
import { ADDON_IDS } from '../../addons';

export async function getWeatherForPlace(placeId: string) {
  if (!isAddonEnabled(ADDON_IDS.WEATHER)) {
    return null; // Add-on disabled → no data
  }
  // Fetch forecast from external API
}

```

This pattern mirrors the implementation in [`server/src/mcp/tools/collab.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/tools/collab.ts), where the Collab tool returns early if the addon is disabled.

## Step 4: Register MCP Tools (Optional)

If your addon requires AI-driven access via MCP (Model Context Protocol), register tools conditionally in [`server/src/mcp/index.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/index.ts).

```typescript
// server/src/mcp/tools/weather.ts
import { ADDON_IDS } from '../../addons';
import { isAddonEnabled } from '../../utils/addon';

export function registerWeatherTool(server: McpServer) {
  if (!isAddonEnabled(ADDON_IDS.WEATHER)) return;

  server.registerTool('weather-forecast', async ({ placeId }) => {
    const weather = await getWeatherForPlace(placeId);
    return weather ?? { error: 'Weather addon disabled' };
  });
}

```

Register the tool in the main MCP index file only when the addon is enabled.

## Step 5: Build Frontend Components

### Admin Toggle

Add a toggle row to [`shared/src/pages/Admin/Addons.tsx`](https://github.com/mauriceboe/TREK/blob/main/shared/src/pages/Admin/Addons.tsx) so admins can enable your addon.

```tsx
// shared/src/pages/Admin/Addons.tsx
<Row key="weather">
  <Cell>{t('Weather')}</Cell>
  <Cell>{t('Show forecast for trip destinations')}</Cell>
  <Cell>
    <Switch
      checked={addons.weather.enabled}
      onChange={() => toggleAddon('weather')}
    />
  </Cell>
</Row>

```

### Feature UI

Conditionally render your component based on the addon state. Follow the pattern used in [`shared/src/components/Trip/Collab.tsx`](https://github.com/mauriceboe/TREK/blob/main/shared/src/components/Trip/Collab.tsx).

```tsx
// shared/src/components/Trip/WeatherPanel.tsx
if (!addonEnabled('weather')) return null;

return <div className="weather-panel">{/* Weather UI */}</div>;

```

## Step 6: Run Migrations and Test

After modifying the seed file, start the development server to apply the database changes.

```bash
npm run start:dev

```

Navigate to **Admin → Addons** and enable your custom addon. Verify that:
- The UI components appear only when enabled
- API routes return data when active and null when inactive
- MCP tools respond correctly via the AI interface

## Summary

- **Register the identifier** in [`server/src/addons.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/addons.ts) using the `ADDON_IDS` constant object
- **Seed the database** in [`server/src/db/seeds.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/db/seeds.ts) to make the addon toggleable in the admin panel
- **Gate backend logic** using `isAddonEnabled(ADDON_IDS.YOUR_ADDON)` to protect features from running when disabled
- **Register MCP tools** conditionally in [`server/src/mcp/index.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/index.ts) for AI integration
- **Implement frontend toggles** in [`shared/src/pages/Admin/Addons.tsx`](https://github.com/mauriceboe/TREK/blob/main/shared/src/pages/Admin/Addons.tsx) and feature components using `addonEnabled()` checks

## Frequently Asked Questions

### Where are addon identifiers defined in TREK?

Addon identifiers are defined as string constants in [`server/src/addons.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/addons.ts) within the `ADDON_IDS` object. This central registry ensures consistent naming across the backend and frontend.

### How does TREK check if an addon is enabled?

The backend uses the `isAddonEnabled()` utility exported from [`server/src/addons.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/addons.ts) to verify activation state. The frontend uses a similar `addonEnabled()` helper to conditionally render UI components.

### Can I add environment variables for my custom addon?

Yes. Add any required API keys or configuration variables to your environment file and document them in [`wiki/Environment-Variables.md`](https://github.com/mauriceboe/TREK/blob/main/wiki/Environment-Variables.md). Access them in your service code via `process.env.YOUR_KEY` after checking that the addon is enabled.

### Do I need to restart the server after adding a new addon?

You must run the database seeding process (typically via `npm run start:dev`) to insert the new addon record into the database. Once seeded, toggling the addon on or off in the admin panel does not require a server restart.