m038 7ce02d642a feat: scaffold travel-memories Flask app and test infrastructure
Adds services/travel-memories/ with Flask factory (create_app), stub
route blueprints, pytest/playwright smoke test infra (httpserver session
fix, pytest.ini pythonpath), phase2–6 fixture JSONs, Dockerfile, and
docker-compose service entry. Smoke test (test_health) passes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 15:46:32 +02:00
2026-06-21 12:48:04 +02:00

into the east — Grav CMS

Grav CMS travel blog. Local dev via Docker; production on a VPS managed entirely through make.


Repository structure

Two git repos:

Repo Contents Location
intotheeast.com (this repo) Docker setup, Makefile, scripts, plugins.txt ./
intotheeast.com-content Site config, pages, theme user/ (standalone git repo)

The user/ directory is a standalone git repo — its changes are pushed/pulled independently to Gitea. The Grav Sync plugin on the server automatically pulls from Gitea when content is pushed.


Prerequisites

  • Docker (for local dev)
  • SSH access to the production server
  • Both Gitea repos created and accessible
  • A Gitea personal access token with repo read/write access

Local development setup

cp .env.example .env   # fill in your values — never commit this file
make setup             # start Docker container and install plugins

Site runs at http://localhost:8081.

Clone the user content repo into user/ if not already present:

git clone $USER_REPO user/

First-time server setup

1. Fill in .env — copy .env.example and set all values including REMOTE_USER, REMOTE_HOST, USER_REPO, MAIN_REPO, and Gitea credentials.

2. Run the install:

make remote-install

This SSHes into the server, downloads Grav, clones both repos (user content + this config repo), installs plugins, and prints the server's SSH public key.

3. Add the SSH key to Gitea — copy the printed public key and add it as a read-only deploy key to both Gitea repos. After this, make remote-fetch works without credentials.


Content sync workflow

To pull editor changes locally:

make content-pull   # pull latest user/ content from Gitea → local

To push local changes to Gitea (triggers server sync):

git -C user add -A && git -C user commit -m "content: describe change"
make content-push   # push local user/ commits → Gitea

All commands

Local

Command Description
make start Start the local Docker container
make stop Stop the local Docker container
make setup Start container and install all plugins from plugins.txt
make install-plugins (Re)install plugins from plugins.txt in the local container
make content-push Push local user/ commits to Gitea
make content-pull Pull latest user/ content from Gitea

Remote credentials

Command Description
make remote-env-setup Write Gitea credentials to ~/.env-intotheeast on the server
make remote-env-remove Delete ~/.env-intotheeast from the server

Always run make remote-env-remove when done. Credentials must not persist on the server.

Remote server management

Command Description
make remote-install First-time install: download Grav, clone both repos, install plugins
make remote-fetch Pull latest config repo (Makefile, scripts, plugins.txt) on the server
make remote-install-plugins Install/update plugins from local plugins.txt on the server
make remote-upgrade-grav Upgrade Grav core on the server
make remote-clean Clear Grav cache on the server
make remote-maintenance-on Enable maintenance mode (visitors see offline page)
make remote-maintenance-off Disable maintenance mode

Typical upgrade workflow

make remote-maintenance-on
make remote-upgrade-grav
make remote-install-plugins
make remote-clean
make remote-maintenance-off

Plugins

Plugins are not committed to git. The full list is in plugins.txt — one plugin name per line.

  • Locally: make install-plugins
  • On server: make remote-install-plugins

Template behaviour

Key design decisions that affect how pages render:

Context Sort order Reason
Trip page (trip.html.twig) Ascending (oldest first) Trip reads as a narrative from start to finish
Homepage active-trip feed (home.html.twig) Descending (newest first) Visitors want to see what's happening right now

Homepage modes — controlled by travelling in user/config/site.yaml:

travelling Homepage shows
true Active trip map + chronological feed (newest first)
false Map with highlight markers + curated highlights grid (max 6, 1 per trip, random)

Entries and stories opt into the highlights grid via featured: true in their frontmatter. The active_trip field stores a full page route (e.g. /trips/italy-2026-demo), not a bare slug.

Per-trip map settings — configurable in Admin2 under the Trip tab:

Setting Values Default Notes
use_gpx Yes / No Yes Draws uploaded GPX files as route lines on the map
autoconnect off / on / manual / intelligent_gpx on Controls connector lines between location markers

Connect markers behaviour:

Value Behaviour
off No connector lines; force_connect on entries is also ignored
on Dashed connector between every entry in date order
manual No automatic lines; only entries with force_connect: true are linked
intelligent_gpx Suppresses the connector where a GPX track covers the route; force_connect overrides. Requires use_gpx enabled — falls back to on if GPX is off or no files are present

use_gpx and autoconnect are independent: you can show GPX tracks without connector lines or vice versa.


Security

  • .env is gitignored. Never commit it — it contains your server credentials and Gitea token.
  • GITEA_TOKEN exists only in .env locally, and in ~/.env-intotheeast on the server only during active sessions. Always run make remote-env-remove after use.
  • ~/.env-intotheeast has chmod 600 — readable only by the SSH user.
  • The server pulls from Gitea using its SSH deploy key (read-only). No long-lived token is stored on the server after initial install.
  • scripts/server-install.sh writes ~/.netrc for the initial clone only, and deletes it immediately after via a trap handler — even if the script fails.
  • Credentials are never passed as command-line arguments (they would appear in server process listings). They are passed as environment variables within the SSH session.
S
Description
No description provided
Readme 556 KiB
Languages
JavaScript 56.1%
Python 20.7%
Shell 11%
Makefile 5.9%
HTML 5%
Other 1.3%