# How to Set Up Document Management with File Attachments in TREK: A Complete Guide

> Learn to set up document management with file attachments in TREK. Configure permissions and use the FilesService API or useFileManager hook for real-time attachment management.

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

---

**Enable the Documents addon in TREK's admin panel, configure `file_upload` permissions, and use the built-in `FilesService` API or React `useFileManager` hook to upload, link, and manage attachments in real-time.**

TREK implements document management as a first-class addon called **Documents**, providing a complete solution for handling file attachments within trip planning workflows. This guide walks through the architecture spanning NestJS 11 backend services and React 19 frontend hooks, showing exactly how to enable and configure document management with file attachments in TREK according to the source code in `mauriceboe/TREK`.

## Backend Architecture: FilesService and REST API

The backend implements a robust file handling layer using NestJS decorators and custom interceptors, storing metadata in SQLite while persisting binaries on the filesystem.

### Core Service Implementation

The `FilesService` class in [`server/src/nest/files/files.service.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/files/files.service.ts) handles the core business logic for document management. It manages **disk storage** under the `uploads/` directory, where files are saved with UUID-based filenames to prevent collisions. The service performs permission checks against `file_upload`, `file_edit`, and `file_delete` permissions, implements soft-delete/restore functionality, and manages linking files to places or reservations.

Every mutation operation triggers WebSocket broadcasts via the `broadcast` method, emitting events like `file:created`, `file:updated`, or `file:deleted` to synchronize all connected clients in real-time.

### REST Endpoints and Upload Flow

The `FilesController` in [`server/src/nest/files/files.controller.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/files/files.controller.ts) exposes routes under **`/api/trips/:tripId/files`**. The upload flow follows this sequence:

1. **Request validation**: The controller enforces trip ownership, demo-mode restrictions, and MIME type validation before accepting multipart data.
2. **File interception**: `FileInterceptor` (configured with `UPLOAD` constants) saves the binary to `uploads/<uuid>.<ext>`.
3. **Metadata persistence**: `FilesService.createFile` writes a row to the SQLite `files` table containing `mime_type`, `original_name`, optional `place_id`/`reservation_id`, and the uploader's user ID.
4. **Real-time sync**: A `file:created` WebSocket event fires, allowing the frontend to instantly display the new attachment.

### Configuration and Security Constraints

Security constraints are defined in [`server/src/services/fileService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/fileService.ts):

- **Maximum file size**: `MAX_FILE_SIZE = 50 * 1024 * 1024` (50 MiB)
- **Blocked extensions**: `.svg`, `.exe`, and other dangerous file types are rejected
- **Allowed types**: Admin-configurable via the `ALLOWED_FILE_TYPES` environment variable or UI settings

Permissions are declared in [`server/src/nest/services/permissions.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/services/permissions.ts) with three file-related keys:
- `file_upload` (default: `trip_member`)
- `file_edit` (default: `trip_member`)  
- `file_delete` (default: `admin`)

## Frontend Implementation: useFileManager Hook

The React frontend encapsulates file management logic in a dedicated hook that handles drag-and-drop, paste operations, and permission-gated UI controls.

### Drag-and-Drop and Upload Handling

The `useFileManager` hook in [`client/src/components/Files/useFileManager.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/components/Files/useFileManager.ts) integrates `react-dropzone` for drag-and-drop functionality. Key implementation details include:

- **Size enforcement**: The dropzone respects the 50 MiB limit (`maxSize: 50 * 1024 * 1024`) defined in the backend constants.
- **Paste handling**: The hook intercepts clipboard paste events and validates content before upload.
- **Auto-assignment**: After successful upload, the hook automatically opens the "assign" modal to link the file to a place or reservation (see lines 18-22 of the hook).

The hook communicates with `filesApi` in [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts), which provides methods for `list`, `upload`, `toggleStar`, `restore`, `permanentDelete`, `emptyTrash`, and `link` operations.

### Permission Gates and UI Controls

Before enabling upload buttons or delete actions, the UI checks `useCanDo` from [`client/src/store/permissionsStore.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/store/permissionsStore.ts). This utility returns a boolean indicating whether the current user holds the required permission level (`trip_member`, `trip_owner`, or `admin`) for the specific file operation.

The [`FilesPanel.tsx`](https://github.com/mauriceboe/TREK/blob/main/FilesPanel.tsx) component renders filter tabs (All, PDF, Images, Docs, Starred, Collab), a lightbox for image previews, and modals for linking files to itinerary items.

## Enabling and Configuring the Documents Addon

Document management requires explicit activation and configuration through the admin interface.

### Activating the Addon in Admin Panel

Navigate to **Admin → Addons** and toggle the **Documents** addon to enable file attachment functionality system-wide. This exposes the Files tab in the trip planner interface and activates the REST endpoints.

### Configuring Upload Limits and Allowed File Types

Admins can adjust constraints by modifying [`server/src/services/fileService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/fileService.ts):

```typescript
// server/src/services/fileService.ts
export const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50 MiB default
export const BLOCKED_EXTENSIONS = ['.svg', '.exe', '.bat', '.sh'];

```

Allowed file types can be configured via environment variables or the Admin-Addons UI page, which writes to the application's configuration store.

### Permission Levels for File Operations

Permission defaults are configured in [`server/src/nest/services/permissions.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/services/permissions.ts):

```typescript
// server/src/nest/services/permissions.ts
export const PERMISSIONS = [
  { key: 'file_upload', defaultLevel: 'trip_member', allowedLevels: ['admin', 'trip_owner', 'trip_member'] },
  { key: 'file_edit',   defaultLevel: 'trip_member', allowedLevels: ['admin', 'trip_owner', 'trip_member'] },
  { key: 'file_delete', defaultLevel: 'admin',       allowedLevels: ['admin'] },
];

```

Changing `defaultLevel` or `allowedLevels` instantly updates the UI because `useCanDo` reads this runtime configuration to enable or disable action buttons.

## Practical Implementation Examples

### Uploading and Linking Files via REST API

Use the `/api/trips/:tripId/files` endpoint to upload and immediately associate files with itinerary items:

```bash

# Upload a PDF and link to reservation #42

curl -X POST "http://localhost:3000/api/trips/7/files" \
  -H "Authorization: Bearer <jwt>" \
  -F "file=@invoice.pdf;type=application/pdf" \
  -F "reservation_id=42" \
  -H "x-socket-id: abc123"

# Star the uploaded file

curl -X PATCH "http://localhost:3000/api/trips/7/files/23/star" \
  -H "Authorization: Bearer <jwt>" \
  -H "x-socket-id: abc123"

# List all non-trashed files

curl -X GET "http://localhost:3000/api/trips/7/files" \
  -H "Authorization: Bearer <jwt>"

```

### React Component Integration

Implement document management in custom components using the `useFileManager` hook:

```tsx
import { useFileManager } from '@/components/Files/useFileManager';
import { filesApi } from '@/api/client';

function TripFiles({ tripId, places, reservations }) {
  const { files, uploading, filterType, setFilterType, handleStar, handleDelete } =
    useFileManager({
      tripId,
      places,
      reservations,
      onUpload: (fd) => filesApi.upload(tripId, fd),
      onDelete: (id) => filesApi.remove(tripId, id),
    });

  return (
    <section>
      <header>
        <select value={filterType} onChange={e => setFilterType(e.target.value)}>
          <option value="all">All</option>
          <option value="pdf">PDF</option>
          <option value="image">Images</option>
          <option value="doc">Docs</option>
        </select>
      </header>

      {uploading && <p>Uploading…</p>}

      <ul>
        {files.map(f => (
          <li key={f.id}>
            {f.name}
            <button onClick={() => handleStar(f.id)}>
              {f.starred ? '★' : '☆'}
            </button>
            <button onClick={() => handleDelete(f.id)}>Trash</button>
          </li>
        ))}
      </ul>
    </section>
  );
}

```

### Customizing Permission Levels

To restrict file deletion to administrators only, modify the permissions array:

```typescript
// server/src/nest/services/permissions.ts
{
  key: 'file_delete',
  defaultLevel: 'admin',
  allowedLevels: ['admin', 'trip_owner'] // Expand if needed
}

```

Link existing files to places using the `linkFile` API wrapper:

```typescript
// Link to a specific place
import { linkFile } from '@/api/client';

await linkFile(tripId, fileId, { place_id: 12 });
// Hits POST /api/trips/:tripId/files/:fileId/link

```

## Summary

- **Enable the Documents addon** via Admin → Addons to activate file attachment functionality.
- **Configure storage limits** in [`server/src/services/fileService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/fileService.ts) (default 50 MiB) and define allowed file types.
- **Set permission levels** in [`server/src/nest/services/permissions.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/services/permissions.ts) to control who can upload, edit, or delete files.
- **Use `FilesService`** for backend operations with automatic WebSocket synchronization.
- **Implement `useFileManager`** in React components to handle drag-and-drop, filtering, and permission-gated actions.
- **Store files** on the filesystem under `uploads/` with UUID filenames while tracking metadata in SQLite.

## Frequently Asked Questions

### What file types are supported for upload in TREK?

TREK supports configurable file types defined by the admin via the `ALLOWED_FILE_TYPES` setting. By default, the system blocks dangerous extensions like `.svg`, `.exe`, `.bat`, and `.sh` as defined in [`server/src/services/fileService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/fileService.ts). Administrators can whitelist specific MIME types through the Admin → Addons page or environment variables.

### How does TREK handle file storage and security?

Uploaded files are stored on the server's filesystem under the `uploads/` directory with UUID-based filenames to prevent directory traversal attacks. Metadata including original names, MIME types, and ownership is stored in the SQLite database at `data/travel.db`. The `FilesController` enforces trip ownership validation and permission checks before any file operation, ensuring users can only access documents within trips they belong to.

### Can I link uploaded files to specific places or reservations?

Yes, the `FilesService` supports linking files to places and reservations through the `place_id` and `reservation_id` foreign keys. When uploading via `POST /api/trips/:tripId/files`, include these IDs as form fields. Alternatively, use the `linkFile` API method or the UI modal that appears automatically after upload to associate existing files with itinerary items.

### What is the maximum file size allowed in TREK document management?

The default maximum file size is **50 MiB** (50 * 1024 * 1024 bytes), enforced by both the frontend `useFileManager` hook and the backend `FilesController`. Administrators can modify this limit by changing the `MAX_FILE_SIZE` constant in [`server/src/services/fileService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/fileService.ts) and ensuring the frontend dropzone configuration matches the new value.