# How Packing Lists Are Managed with Templates, Member Assignments, and Bag Tracking in TREK

> Discover how TREK manages packing lists with templates, member assignments, and bag tracking. Learn about its relational architecture and permission system for efficient organization.

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

---

**TREK implements packing lists through a relational architecture that separates items, bags, and member assignments into distinct database schemas, with reusable templates stored as hierarchal collections and all mutations protected by the `packing_edit` permission.**

The TREK travel planning application organizes trip preparation through a sophisticated packing list management system. This architecture, implemented in the `mauriceboe/TREK` repository, uses Zod schemas to define strict data shapes for items and bags while a centralized service layer handles member assignments and template workflows.

## Core Database Schema

The system defines four interconnected entities in [`shared/src/packing/packing.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/packing/packing.schema.ts) that establish the foundation for packing list management.

### Packing Items

Individual checklist entries are governed by the **`packingItemSchema`** (lines 17-35), which specifies fields for `name`, `category`, `quantity`, a boolean `checked` flag, optional `weight`, and a `bag_id` foreign key. This schema ensures that every item tracks its completion status and physical container assignment.

### Bags as Logical Containers

The **`packingBagSchema`** (lines 48-66) defines bags as color-coded containers with properties for `name`, `color`, and `sort_order`. Each bag belongs to a specific trip and serves as a grouping mechanism for items, enabling teams to organize gear by physical luggage or responsibility zones.

### Member Assignments

Bag access control operates through the **`packingBagMemberSchema`** (lines 37-45), which creates a many-to-many junction table between users and bags. This schema enables the UI to render which team members are responsible for specific bags and restricts edit permissions to assigned users.

### Template Storage

Reusable checklists are structured by the **`packingTemplateSummarySchema`** (lines 112-127) and related template item schemas. Templates store read-only collections of items grouped by categories, allowing users to apply predefined packing lists to new trips without recreating common entries.

## Service Layer Implementation

The [`server/src/services/packingService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/packingService.ts) file encapsulates all business logic for packing operations, providing atomic functions for CRUD actions and permission enforcement.

### Item and Bag Operations

The **`listItems(tripId)`** function executes a SQL query selecting all rows from `packing_items` ordered by `sort_order ASC` and `created_at ASC` (lines 10-13). For creating new entries, **`createItem(tripId, data)`** calculates the next sort index and sanitizes quantity inputs to a 1-999 range before insertion (lines 16-24).

When retrieving baggage containers, **`listBags(tripId)`** (lines 121-137) queries the `packing_bags` table and executes a secondary fetch against `packing_bag_members` to populate each bag's `members` array with user data including avatar URLs.

### Dynamic Member Management

Assigning users to specific bags utilizes **`addBagMember(bagId, userId)`** (lines 144-149), which executes an `INSERT OR IGNORE INTO packing_bag_members` statement to prevent duplicate relationships. The inverse operation, **`removeBagMember(bagId, userId)`** (lines 140-143), deletes the specific user-bag association row when a member is unassigned from luggage responsibilities.

## Template Workflows

Templates provide reusable packing patterns that teams can apply across multiple trips, with creation and application handled by distinct service functions.

### Saving Trip Data as Templates

The **`saveAsTemplate(tripId, userId, name)`** function (lines 241-267) transforms a trip's current packing list into a reusable template. This process inserts a parent record into `packing_templates`, then iterates through categories to populate `packing_template_categories`, and finally writes individual items to `packing_template_items` while preserving the original grouping structure.

### Applying Templates to Trips

When users select a template, **`applyTemplate(tripId, templateId)`** (lines 214-230) clones the template's contents into the target trip. The function queries `packing_template_items` with a `SELECT` statement, then loops through results to create fresh rows in `packing_items` with the new `trip_id`, returning `null` if the source template contains no items.

Template access is bifurcated by role: regular members receive read-only summaries via **`listTemplates(tripId, isMember)`** (lines 199-207), while administrators manipulate template records through [`adminService.ts`](https://github.com/mauriceboe/TREK/blob/main/adminService.ts) endpoints.

## Permission Model and Security

All packing mutations are gated by the **`packing_edit`** permission defined in [`server/src/services/permissions.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/permissions.ts) (line 42). Before executing any create, update, or delete operation, the service layer invokes `verifyTripAccess` (imported from [`server/src/services/tripAccess.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/tripAccess.ts)) to validate that the requesting user is either the trip owner or a member explicitly granted packing rights.

This permission check applies to item modifications, bag creation, member assignments, and template applications, ensuring that unauthorized users cannot alter packing lists even if they have general trip access.

## Practical Implementation Examples

The following patterns demonstrate how client applications interact with the packing system:

```typescript
// Load all packing items and bags for a trip
const items = await fetch(`/api/trips/${tripId}/packing/items`).then(r => r.json());
const bags = await fetch(`/api/trips/${tripId}/packing/bags`).then(r => r.json());

// Create a new packing item with category and quantity
await fetch(`/api/trips/${tripId}/packing/items`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ 
    name: 'Sunscreen', 
    category: 'Toiletries', 
    quantity: 2 
  })
});

// Assign a team member to a specific bag
await fetch(`/api/trips/${tripId}/packing/bags/${bagId}/members`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ userId: teammateId })
});

// Save current trip's packing list as a reusable template
await fetch(`/api/trips/${tripId}/packing/templates`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Winter Iceland Gear' })
});

// Apply a template to populate the current trip
await fetch(`/api/trips/${tripId}/packing/templates/${templateId}/apply`, { 
  method: 'POST' 
});

```

## Summary

- **TREK** separates packing concerns into four distinct schemas: items, bags, bag-members, and templates, defined in [`shared/src/packing/packing.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/packing/packing.schema.ts).
- **Bag tracking** combines the `packing_bags` table for container metadata with the `packing_bag_members` junction table to manage user assignments and edit permissions.
- **Templates** are created via `saveAsTemplate` which writes to three hierarchical tables, and applied via `applyTemplate` which clones items into the target trip.
- **Security** is enforced through the `packing_edit` permission checked by `verifyTripAccess` before any mutation, ensuring only owners and assigned members can modify packing data.

## Frequently Asked Questions

### How are bag permissions structured in TREK?

Bag permissions operate through a separate membership table rather than item-level checks. The `packing_bag_members` table links user IDs to specific bag IDs, and the service layer loads these relationships when fetching bags. This allows the UI to display assigned members with avatars while the backend ensures only assigned users can modify items within that bag.

### Can regular trip members create packing templates?

No. According to the permission matrix in [`server/src/services/permissions.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/permissions.ts), regular members receive read-only access to templates through the `listTemplates` function. Template creation, modification, and deletion are restricted to administrators and trip owners who access these functions through [`adminService.ts`](https://github.com/mauriceboe/TREK/blob/main/adminService.ts) endpoints.

### What happens when a template is applied to an existing trip?

The `applyTemplate` function creates entirely new rows in `packing_items` for the target trip, copying data from `packing_template_items` but generating fresh IDs and timestamps. It preserves category groupings from the template but does not delete existing items in the trip, effectively merging the template contents with the current packing list.

### How does the system handle duplicate member assignments?

The `addBagMember` function uses an `INSERT OR IGNORE` SQL pattern (line 144-149 in [`packingService.ts`](https://github.com/mauriceboe/TREK/blob/main/packingService.ts)) that silently skips duplicate entries if the user-bag relationship already exists. This prevents database constraint violations while allowing idempotent assignment operations from the client side.