Skip to content

feat: trips as stays and moves, audit fixes, and simplification - #32

Merged
thisispivi merged 11 commits into
mainfrom
trips-v2
Oct 4, 2026
Merged

thisispivi merged 11 commits into
mainfrom
trips-v2

Conversation

@thisispivi

Copy link
Copy Markdown
Owner

Brings trips-v2 into main.

Trips as stays and moves

  • Trips are stored as stays, moves, and day trips instead of flat stop and transport steps.
  • The public site shows trips as numbered chapters, and the editor's trip story matches them.
  • migrateTrips.cli.ts converts legacy trip files; overnight layovers stay inside journeys.
  • The Python uploader module is refactored with stricter path validation and error handling.

Audit fixes

  • Editor middleware logs unexpected failures and answers with honest status codes. Upload settings in .env fail fast on a typo.
  • Bad gallery and lightbox links show a 404 instead of crashing. Route params and history state are validated.
  • City time zones must be ones Intl can use.
  • Tooling: lint guard on the editor's @/ alias, a pre-push hook that uses the uploader venv, hooks pinned to LF, ignore-file cleanup, urllib3 2.8.0, and a scoped braces audit exception (no fixed release exists).

Simplification pass (#31)

  • The world polygons are shared between the app and the editor.
  • react-transition-group is replaced by framer-motion, and framer-motion animation honours reduced motion.
  • Alias re-exports, duplicate helpers, and duplicate scripts are removed. Placeholder JSDoc is replaced.

Also resolves the fast-uri Dependabot alert: this branch pins 3.1.8.

Verification

pnpm check, pnpm build, and the uploader tests pass locally through the pre-push hook.

…dling, and streamline uploads

- Updated `pnpm-workspace.yaml` to adjust dependency overrides for security patches.
- Enhanced argument parsing in `args.py` to validate city and country inputs.
- Introduced `validate_path_segment` function in `config.py` to prevent path traversal and Windows alias issues.
- Refactored media directory construction in `build_media_dir` to ensure safe paths.
- Added `confined_path` function to restrict path resolution within designated roots.
- Improved error handling in `get_env` for environment variable validation.
- Streamlined file uploads in `image.py` and `video.py` by consolidating upload logic into `upload_file`.
- Added new `paths.py` and `storage.py` modules to encapsulate path management and storage interactions.
- Implemented regression tests in `test_uploader.py` to ensure robustness against path traversal and upload failures.
A legacy stop marked as a layover now stays part of its journey even when
it spans a night, instead of becoming a stay. An overnight connection in
Milan is travelling, not a visit to Milan.
Rebuild the trip page around how a trip is remembered:

- Each journey and each place slept in is a numbered chapter (getting there,
  moving on, going home), joined by a line so the order reads at a glance.
- Rides show their clock times, duration, distance, airline and flight
  number, all visible; a connection that waited overnight shows a night in
  transit, including small-hours arrivals before a morning departure.
- A stay lists its day trips under their dates, with every ride and place,
  and folds the remaining days into one line.
- Every place with photos has its own row that opens its gallery.
- The trip card mirrors its card in the trips list and carries the trip's
  days, nights, distance and per-mode totals underneath, replacing the
  stats strip.
The trip story now uses the same numbered chapter frame as the public trip
page: journeys and stays carry a badge, a "what and when" line and a title,
day trips sit in tinted day boxes, and each ride row shows its clock times
on the right with duration, distance and operator underneath. Stay titles
show the country flag from the editor's bundled flags.
…upload settings

Every endpoint now reports errors through sendError: request and schema
failures keep a readable 4xx message, a refused origin is a 403, a missing
snapshot a 404, and anything else is logged on the dev server and answered
with a 500 instead of a silent "Invalid request."

Upload settings in .env are parsed with Zod at startup, so a typo such as
COMPRESSED_MAX_SIZE=15OO stops the editor with the variable named rather
than encoding a gallery at the default size. A malformed site.config.json
is no longer mistaken for a missing one when resolving the media root.
The gallery and lightbox loaders returned null for an unknown city and
the components destructured it anyway, so a stale link crashed into the
generic error page; an out-of-range photo index rendered an empty
lightbox. Loaders now parse their params with Zod and throw a 404, and
components read typed loader data instead of casting it.

Router history state is read through one schema, which also keeps a
gallery's return path inside the app. The video play mark is no longer a
button nested in the photo album's own button, and the gallery's chained
BEM class names are flattened. The unused ?from= parameter is removed.
groupTripsByYear replaces an inline IIFE that sorted twice and ended in a
cast, and gets tests for year order and side alternation. Two casts the
types already made redundant are dropped from the stats feature.
An unknown zone made the first date conversion throw a bare RangeError
from inside buildWorld. The schema now names the field instead.
- Lint rejects @/ imports in editor code, where the alias silently
  resolves into the public app.
- pre-push runs the uploader tests through its virtual environment, so
  they can import Pillow, and hooks are pinned to LF line endings.
- Drop ignore entries for directories that no longer exist, and the app
  .gitignore that ignored the react-doctor hooks the repo tracks.
- Bump urllib3 to 2.8.0 for three advisories, and normalise the
  requirements file's doubled carriage returns.
- Record the braces advisory as a scoped audit exception: it reaches only
  dev tooling and no fixed release exists yet.
Document the new trust boundaries (route params, history state, editor
upload settings), the editor's single error-response shape, and the
uploader's unit tests. Remove the README's claim that the editor uses DnD
Kit, mention the editor's built-in uploader, and explain the editor's @/
alias.
Share the world polygons between the app and editor, drop react-transition-group and the editor's topojson-client, remove alias re-exports and duplicate scripts, honour reduced motion in framer-motion, and replace placeholder JSDoc summaries.
@thisispivi
thisispivi merged commit 80b2dd6 into main Oct 4, 2026
4 checks passed
@thisispivi
thisispivi deleted the trips-v2 branch October 4, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant