https://github.com/ducks/discourse-itinerary
Turn a Discourse category into a travel itinerary. Topics become flights, hotels, trains, and events sorted by date.
https://github.com/ducks/discourse-itinerary
Last synced: 17 days ago
JSON representation
Turn a Discourse category into a travel itinerary. Topics become flights, hotels, trains, and events sorted by date.
- Host: GitHub
- URL: https://github.com/ducks/discourse-itinerary
- Owner: ducks
- Created: 2026-05-24T19:34:59.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-06-11T19:07:19.000Z (22 days ago)
- Last Synced: 2026-06-11T21:06:05.315Z (22 days ago)
- Language: Ruby
- Size: 192 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# discourse-itinerary
A Discourse plugin that turns a category of topics into a chronological
travel itinerary, with one trip per topic and its items linked back to it.
Topics in the configured itinerary category that carry a set of itinerary
custom fields are collected, grouped under their parent trip, sorted by
start time, and returned via plugin routes. Ember pages render the list
of trips and the per-trip timeline grouped by day.
This is an early, narrow tool. It is not a generic notes app, calendar, or
project planner. It just makes a category of Discourse topics readable as a
travel timeline.
## How it works
- **Category** = container for many trips. The plugin auto-creates an
"Itinerary" category on first boot and stores its id in the
`itinerary_category_id` site setting; admins can repoint that setting
at a different category if they want.
- **Topic with `itinerary_item_type = trip`** = the trip workspace
- **Other itinerary topics** = items (flight, hotel, train, event, transfer,
note) that point at their parent trip via `itinerary_parent_trip_id`
- **Topic custom fields** = structured metadata
- **Plugin routes**: `GET /itinerary/trips` (list trips, optionally
filtered by `category_id`), `GET /itinerary/trips/:id` (one trip
with its items, day-grouped on the client)
- **Pages**: `/itinerary` (trip list) and `/itinerary/:trip_id` (timeline)
### Custom fields
Each itinerary topic stores these fields on the standard topic
`custom_fields` table:
| Field | Type | Example |
| ------------------------------ | -------- | ----------------------- |
| `itinerary_item_type` | string | `flight` |
| `itinerary_starts_at` | string | `2026-09-20T14:30` |
| `itinerary_ends_at` | string | `2026-09-21T09:15` |
| `itinerary_origin` | string | `PDX` |
| `itinerary_destination` | string | `MAD` |
| `itinerary_name` | string | `Memmo Alfama` |
| `itinerary_location` | string | `Artrip, Madrid` |
| `itinerary_confirmation_code` | string | `ABC123` |
| `itinerary_status` | string | `booked` |
Timestamps are stored as ISO-8601 strings; sorting is lexical.
## Status
- **v0.1** — JSON route + Rails-side query
- **v0.2** — composer extension for authoring itinerary topics
- **v0.3** - team-trip data model (one category, many trips), split
finders, trip + item JSON routes, Ember route and timeline rendering
- **v0.4** - auto-create dedicated category; drop tag requirement
- **v0.5** - hide itinerary category from /latest by default so the
plugin owns the UX; /itinerary is the canonical entrypoint, with
a sidebar link under the Community section and +Add buttons on
both the trip list and per-trip timeline pages
- **v0.6** - auto-synthesize topic title and body from itinerary
fields. Hide the bare title input; pre-fill the body. Item topics
no longer require the user to invent a title.
- **v0.7** - iCalendar (.ics) export per trip. Download a single
calendar file containing one VEVENT per item with a start time;
import into Apple Calendar, Google Calendar, or Outlook.
- **later** — filters, status tracking, drag-reorder, per-user
subscribe URLs so calendar apps can subscribe rather than download
No calendar sync, email parsing, or map view. Not planned for the near term.
ICS export shipped in v0.7.
## Site settings
- `itinerary_enabled` (default: true) — kill switch for the plugin
- `itinerary_category_id` (default: -1) - id of the category the plugin
treats as the itinerary workspace. Auto-set on first boot when the
plugin provisions its default category; can be repointed in admin.
## Requirements
- A Discourse category to hold itinerary topics. The plugin creates one
automatically on first boot if `itinerary_category_id` is unset.
## Local development
A `shell.nix` is shipped for the linter/test workflow:
```sh
nix-shell # ruby 3.3 + bundler + native deps
bundle install # installs gems into ./.gems
bundle exec rubocop # lint Ruby
bundle exec stree check $(git ls-files '*.rb') Gemfile
```
To run the specs you need a Discourse checkout — symlink the plugin in and
run rspec from there:
```sh
ln -s $PWD ~/discourse/discourse/plugins/discourse-itinerary
cd ~/discourse/discourse
bin/rspec plugins/discourse-itinerary/spec/
```
## License
MIT.