From 4cd6ab4fd21e0be6cfc7a0eeb40ffe47ced5006b Mon Sep 17 00:00:00 2001 From: Sean Morley Date: Sat, 6 Jun 2026 21:42:05 -0400 Subject: [PATCH] Refactor Docker Compose files and update documentation - Commented out build configurations in docker-compose files for AIO, dev, and standard setups to simplify deployment. - Updated the documentation homepage with a new layout, including a hero section, features overview, and installation options. - Introduced new Vue components for enhanced user experience on the documentation site, including HomeHero, HomeFeatures, and HomeInstall. - Improved SEO metadata for better visibility and searchability of the documentation. --- docker-compose.aio.yml | 8 +- docker-compose.dev.yml | 4 +- docker-compose.yml | 18 +- documentation/.vitepress/config.mts | 392 +++-- documentation/.vitepress/seo.ts | 306 ++++ .../theme/components/HomeFeatures.vue | 50 + .../theme/components/HomeFinalCta.vue | 30 + .../.vitepress/theme/components/HomeHero.vue | 127 ++ .../theme/components/HomeInstall.vue | 178 +++ .../theme/components/HomePillars.vue | 54 + .../theme/components/HomeShowcase.vue | 98 ++ .../theme/components/HomeSocialProof.vue | 56 + .../.vitepress/theme/components/HomeTech.vue | 33 + documentation/.vitepress/theme/home.css | 1296 +++++++++++++++++ documentation/.vitepress/theme/index.ts | 34 +- documentation/.vitepress/theme/style.css | 17 +- documentation/docs/changelogs/v0-7-1.md | 2 +- .../configuration/advanced_configuration.md | 67 +- documentation/docs/configuration/api_keys.md | 2 +- .../configuration/environment_variables.md | 159 ++ .../docs/configuration/operations.md | 140 ++ .../docs/configuration/s3_storage.md | 4 +- .../docs/configuration/social_auth.md | 15 +- documentation/docs/configuration/updating.md | 54 +- documentation/docs/guides/admin_panel.md | 45 +- documentation/docs/install/aio.md | 7 +- documentation/docs/install/docker.md | 29 +- documentation/docs/install/getting_started.md | 96 +- documentation/docs/install/quick_start.md | 78 +- documentation/docs/install/traefik.md | 52 +- .../docs/intro/adventurelog_overview.md | 6 +- documentation/docs/usage/usage.md | 23 +- documentation/index.md | 304 +--- documentation/public/robots.txt | 4 + 34 files changed, 3168 insertions(+), 620 deletions(-) create mode 100644 documentation/.vitepress/seo.ts create mode 100644 documentation/.vitepress/theme/components/HomeFeatures.vue create mode 100644 documentation/.vitepress/theme/components/HomeFinalCta.vue create mode 100644 documentation/.vitepress/theme/components/HomeHero.vue create mode 100644 documentation/.vitepress/theme/components/HomeInstall.vue create mode 100644 documentation/.vitepress/theme/components/HomePillars.vue create mode 100644 documentation/.vitepress/theme/components/HomeShowcase.vue create mode 100644 documentation/.vitepress/theme/components/HomeSocialProof.vue create mode 100644 documentation/.vitepress/theme/components/HomeTech.vue create mode 100644 documentation/.vitepress/theme/home.css create mode 100644 documentation/docs/configuration/environment_variables.md create mode 100644 documentation/docs/configuration/operations.md create mode 100644 documentation/public/robots.txt diff --git a/docker-compose.aio.yml b/docker-compose.aio.yml index 6c5297b0..ae487729 100644 --- a/docker-compose.aio.yml +++ b/docker-compose.aio.yml @@ -1,9 +1,9 @@ services: app: - build: - context: . - dockerfile: docker/Dockerfile - target: aio + # build: + # context: . + # dockerfile: docker/Dockerfile + # target: aio image: ghcr.io/seanmorley15/adventurelog-aio:latest container_name: adventurelog-aio restart: unless-stopped diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ab68840d..683d4be7 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,7 +1,7 @@ services: web: build: ./frontend/ - image: ghcr.io/seanmorley15/adventurelog-frontend:latest + # image: ghcr.io/seanmorley15/adventurelog-frontend:latest container_name: adventurelog-frontend restart: unless-stopped user: root @@ -51,7 +51,7 @@ services: server: build: ./backend/ - image: ghcr.io/seanmorley15/adventurelog-backend:latest + # image: ghcr.io/seanmorley15/adventurelog-backend:latest container_name: adventurelog-backend restart: unless-stopped env_file: .env diff --git a/docker-compose.yml b/docker-compose.yml index 6f8149f4..70cc9dbc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,9 @@ services: web: - build: - context: . - dockerfile: docker/Dockerfile - target: frontend + # build: + # context: . + # dockerfile: docker/Dockerfile + # target: frontend image: ghcr.io/seanmorley15/adventurelog-frontend:latest container_name: adventurelog-frontend restart: unless-stopped @@ -45,11 +45,11 @@ services: start_period: 10s server: - build: - context: . - dockerfile: docker/Dockerfile - target: backend - image: ghcr.io/seanmorley15/adventurelog-backend:latest + # build: + # context: . + # dockerfile: docker/Dockerfile + # target: backend + # image: ghcr.io/seanmorley15/adventurelog-backend:latest container_name: adventurelog-backend restart: unless-stopped env_file: .env diff --git a/documentation/.vitepress/config.mts b/documentation/.vitepress/config.mts index cddfb5a2..5ea1db65 100644 --- a/documentation/.vitepress/config.mts +++ b/documentation/.vitepress/config.mts @@ -1,10 +1,10 @@ import { defineConfig } from "vitepress"; +import { buildPageHead, pageSeo } from "./seo"; // https://vitepress.dev/reference/site-config export default defineConfig({ head: [ ["link", { rel: "icon", href: "/adventurelog.png" }], - [ "script", { @@ -13,7 +13,6 @@ export default defineConfig({ "data-website-id": "a7552764-5a1d-4fe7-80c2-5331e1a53cb6", }, ], - [ "link", { @@ -24,79 +23,164 @@ export default defineConfig({ ], ignoreDeadLinks: "localhostLinks", title: "AdventureLog", - description: "The ultimate travel companion.", + description: + "Self-hosted, open-source travel companion for tracking locations, planning trips, and sharing adventures.", lang: "en-US", sitemap: { hostname: "https://adventurelog.app", }, - transformPageData(pageData) { - if (pageData.relativePath === "index.md") { - const jsonLd = { - "@context": "https://schema.org", - "@type": "SoftwareApplication", - name: "AdventureLog", - url: "https://adventurelog.app", - applicationCategory: "TravelApplication", - operatingSystem: "Web, Docker, Linux", - description: - "AdventureLog is a self-hosted platform for tracking and planning travel experiences. Built for modern explorers, it offers trip planning, journaling, tracking and location mapping in one privacy-respecting package.", - creator: { - "@type": "Person", - name: "Sean Morley", - url: "https://seanmorley.com", - }, - offers: { - "@type": "Offer", - price: "0.00", - priceCurrency: "USD", - description: "Open-source version available for self-hosting.", - }, - softwareVersion: "v0.12.1", - license: - "https://github.com/seanmorley15/adventurelog/blob/main/LICENSE", - screenshot: - "https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/screenshots/adventures.png", - downloadUrl: "https://github.com/seanmorley15/adventurelog", - sameAs: ["https://github.com/seanmorley15/adventurelog"], - keywords: [ - "self-hosted travel log", - "open source trip planner", - "travel journaling app", - "docker travel diary", - "map-based travel tracker", - "privacy-focused travel app", - "adventure log software", - "travel experience tracker", - "self-hosted travel app", - "open source travel software", - "trip planning tool", - "travel itinerary manager", - "location-based travel app", - "travel experience sharing", - "travel log application", - ], - }; + rewrites: { + "docs/Guides/nginx_migration.md": "docs/guides/v0-7-1_migration.md", + }, - return { - frontmatter: { - ...pageData.frontmatter, - head: [ - ["script", { type: "application/ld+json" }, JSON.stringify(jsonLd)], + transformPageData(pageData) { + const seo = + pageSeo[pageData.relativePath] ?? + ({ + description: + "AdventureLog documentation for self-hosted travel tracking, trip planning, and Docker deployment.", + } as const); + + const pageTitle = seo.title ?? pageData.title; + const head = buildPageHead(pageData.relativePath, pageTitle, seo); + + if (pageData.relativePath === "index.md") { + const siteUrl = "https://adventurelog.app"; + const screenshot = + "https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/screenshots/adventures.png"; + + const structuredData = [ + { + "@context": "https://schema.org", + "@type": "WebSite", + name: "AdventureLog", + url: siteUrl, + description: seo.description, + inLanguage: "en-US", + publisher: { + "@type": "Organization", + name: "AdventureLog", + url: siteUrl, + logo: `${siteUrl}/adventurelog.png`, + sameAs: [ + "https://github.com/seanmorley15/AdventureLog", + "https://discord.gg/wRbQ9Egr8C", + "https://x.com/AdventureLogApp", + "https://mastodon.social/@adventurelog", + ], + }, + }, + { + "@context": "https://schema.org", + "@type": "SoftwareApplication", + name: "AdventureLog", + url: siteUrl, + applicationCategory: "TravelApplication", + operatingSystem: "Web, Docker, Linux, macOS", + description: seo.description, + featureList: [ + "Location and visit tracking", + "Interactive world map", + "Trip itineraries and collections", + "World travel country and region tracker", + "Strava, Immich, and Wanderer integrations", + "Self-hosted Docker deployment", + ], + creator: { + "@type": "Person", + name: "Sean Morley", + url: "https://seanmorley.com", + }, + offers: { + "@type": "Offer", + price: "0", + priceCurrency: "USD", + description: "Free open-source self-hosted travel companion.", + }, + softwareVersion: "v0.12.1", + license: + "https://github.com/seanmorley15/adventurelog/blob/main/LICENSE", + screenshot, + downloadUrl: "https://github.com/seanmorley15/adventurelog", + installUrl: `${siteUrl}/docs/install/quick_start.html`, + sameAs: ["https://github.com/seanmorley15/adventurelog"], + keywords: (seo.keywords ?? []).join(", "), + }, + { + "@context": "https://schema.org", + "@type": "FAQPage", + mainEntity: [ + { + "@type": "Question", + name: "What is AdventureLog?", + acceptedAnswer: { + "@type": "Answer", + text: "AdventureLog is an open-source, self-hosted travel companion for tracking locations, planning trips with itineraries, and visualizing travels on an interactive world map.", + }, + }, + { + "@type": "Question", + name: "How do I install AdventureLog?", + acceptedAnswer: { + "@type": "Answer", + text: "Run curl -sSL https://get.adventurelog.app | bash to install with the official one-line Docker installer. It defaults to the All-in-One setup on port 8015.", + }, + }, + { + "@type": "Question", + name: "Is AdventureLog free?", + acceptedAnswer: { + "@type": "Answer", + text: "Yes. AdventureLog is GPL-3.0 open source and free to self-host. There are no subscriptions required for the self-hosted version.", + }, + }, + { + "@type": "Question", + name: "Can I self-host AdventureLog on a homelab or NAS?", + acceptedAnswer: { + "@type": "Answer", + text: "Yes. AdventureLog runs in Docker on homelabs, VPS, Proxmox, Synology NAS, Unraid, Kubernetes, and other Docker-capable platforms.", + }, + }, ], }, - }; + ]; + + for (const graph of structuredData) { + head.push([ + "script", + { type: "application/ld+json" }, + JSON.stringify(graph), + ]); + } } - return {}; + const description = + pageData.frontmatter.description ?? seo.description ?? pageData.description; + + return { + title: seo.title ?? pageData.title, + description, + frontmatter: { + ...pageData.frontmatter, + description, + head: [...(pageData.frontmatter.head ?? []), ...head], + }, + }; }, themeConfig: { - // https://vitepress.dev/reference/default-theme-config nav: [ { text: "Home", link: "/" }, - { text: "Docs", link: "/docs/intro/adventurelog_overview" }, + { text: "Install", link: "/docs/install/getting_started" }, + { text: "Configure", link: "/docs/configuration/environment_variables" }, + { text: "Usage", link: "/docs/usage/usage" }, + { + text: "GitHub", + link: "https://github.com/seanmorley15/AdventureLog", + }, ], search: { provider: "local", @@ -107,7 +191,7 @@ export default defineConfig({ }, footer: { - message: "AdventureLog", + message: "AdventureLog β€” self-hosted travel companion", copyright: "Copyright Β© 2023-2026 Sean Morley", }, @@ -115,37 +199,42 @@ export default defineConfig({ sidebar: [ { - text: "About AdventureLog", + text: "Introduction", items: [ { - text: "AdventureLog Overview", + text: "About AdventureLog", link: "/docs/intro/adventurelog_overview", }, ], }, - { text: "Installation", collapsed: false, items: [ { text: "Getting Started", link: "/docs/install/getting_started" }, - { text: "Quick Start Script ⏲️", link: "/docs/install/quick_start" }, - { text: "Docker πŸ‹", link: "/docs/install/docker" }, - { text: "Proxmox LXC 🐧", link: "/docs/install/proxmox_lxc" }, - { text: "Synology NAS ☁️", link: "/docs/install/synology_nas" }, + { text: "Quick Start Installer", link: "/docs/install/quick_start" }, + { text: "All-in-One Docker (AIO)", link: "/docs/install/aio" }, + { text: "Standard Docker", link: "/docs/install/docker" }, { - text: "Kubernetes and Kustomize 🌐", - link: "/docs/install/kustomize", - }, - { text: "Unraid 🧑", link: "/docs/install/unraid" }, - { - text: "Dev Container + WSL 🧰", + text: "Development Setup", link: "/docs/install/dev_container_wsl", }, - { - text: "With A Reverse Proxy", - collapsed: false, + text: "Platform Guides", + collapsed: true, + items: [ + { text: "Proxmox LXC", link: "/docs/install/proxmox_lxc" }, + { text: "Synology NAS", link: "/docs/install/synology_nas" }, + { text: "Unraid", link: "/docs/install/unraid" }, + { + text: "Kubernetes (Kustomize)", + link: "/docs/install/kustomize", + }, + ], + }, + { + text: "Reverse Proxy", + collapsed: true, items: [ { text: "Nginx Proxy Manager", @@ -161,10 +250,7 @@ export default defineConfig({ text: "Usage", collapsed: false, items: [ - { - text: "How to use AdventureLog", - link: "/docs/usage/usage", - }, + { text: "How to Use AdventureLog", link: "/docs/usage/usage" }, ], }, { @@ -172,29 +258,22 @@ export default defineConfig({ collapsed: false, items: [ { - text: "Immich Integration", - link: "/docs/configuration/immich_integration", + text: "Environment Variables", + link: "/docs/configuration/environment_variables", }, { - text: "Google Maps Integration", - link: "/docs/configuration/google_maps_integration", + text: "Operations & Maintenance", + link: "/docs/configuration/operations", }, + { text: "Updating", link: "/docs/configuration/updating" }, { - text: "Strava Integration", - link: "/docs/configuration/strava_integration", - }, - { - text: "Wanderer Integration", - link: "/docs/configuration/wanderer_integration", - }, - { - text: "Social Auth and OIDC", - link: "/docs/configuration/social_auth", - }, - { - text: "Authentication Providers", - collapsed: false, + text: "Authentication", + collapsed: true, items: [ + { + text: "Social Auth & OIDC", + link: "/docs/configuration/social_auth", + }, { text: "Authentik", link: "/docs/configuration/social_auth/authentik", @@ -203,39 +282,60 @@ export default defineConfig({ text: "GitHub", link: "/docs/configuration/social_auth/github", }, - { - text: "Authelia", - link: "https://www.authelia.com/integration/openid-connect/adventure-log/", - }, { text: "Pocket ID", link: "/docs/configuration/social_auth/pocket_id", }, { - text: "Open ID Connect", + text: "OpenID Connect", link: "/docs/configuration/social_auth/oidc", }, + { + text: "Authelia", + link: "https://www.authelia.com/integration/openid-connect/adventure-log/", + }, + { + text: "Disable Registration", + link: "/docs/configuration/disable_registration", + }, + { text: "API Keys", link: "/docs/configuration/api_keys" }, + ], + }, + { + text: "Integrations", + collapsed: true, + items: [ + { + text: "Immich", + link: "/docs/configuration/immich_integration", + }, + { + text: "Google Maps", + link: "/docs/configuration/google_maps_integration", + }, + { + text: "Strava", + link: "/docs/configuration/strava_integration", + }, + { + text: "Wanderer", + link: "/docs/configuration/wanderer_integration", + }, ], }, { - text: "Update App", - link: "/docs/configuration/updating", + text: "Storage & Email", + collapsed: true, + items: [ + { text: "S3 Media Storage", link: "/docs/configuration/s3_storage" }, + { text: "SMTP Email", link: "/docs/configuration/email" }, + ], }, { - text: "Disable Registration", - link: "/docs/configuration/disable_registration", - }, - { text: "SMTP Email", link: "/docs/configuration/email" }, - { text: "Umami Analytics", link: "/docs/configuration/analytics" }, - { text: "S3 Storage", link: "/docs/configuration/s3_storage" }, - { - text: "API Keys", - link: "/docs/configuration/api_keys", - }, - { - text: "Advanced Configuration", + text: "Advanced Settings", link: "/docs/configuration/advanced_configuration", }, + { text: "Umami Analytics", link: "/docs/configuration/analytics" }, ], }, { @@ -243,15 +343,15 @@ export default defineConfig({ collapsed: true, items: [ { - text: "No Images Displaying", + text: "Images Not Displaying", link: "/docs/troubleshooting/no_images", }, { - text: "Login and Registration Unresponsive", + text: "Login Unresponsive", link: "/docs/troubleshooting/login_unresponsive", }, { - text: "Failed to Start Nginx", + text: "Nginx Failed to Start", link: "/docs/troubleshooting/nginx_failed", }, ], @@ -260,16 +360,10 @@ export default defineConfig({ text: "Guides", collapsed: true, items: [ + { text: "Admin Panel", link: "/docs/guides/admin_panel" }, + { text: "Invite a User", link: "/docs/guides/invite_user" }, { - text: "Admin Panel", - link: "/docs/guides/admin_panel", - }, - { - text: "Invite a User", - link: "/docs/guides/invite_user", - }, - { - text: "v0.7.1 Migration Guide", + text: "v0.7.1 Migration", link: "/docs/guides/v0-7-1_migration", }, ], @@ -282,38 +376,14 @@ export default defineConfig({ text: "Development Timeline", link: "/docs/changelogs/development_timeline", }, - { - text: "v0.12.1", - link: "/docs/changelogs/v0-12-1", - }, - { - text: "v0.12.0", - link: "/docs/changelogs/v0-12-0", - }, - { - text: "v0.11.0", - link: "/docs/changelogs/v0-11-0", - }, - { - text: "v0.10.0", - link: "/docs/changelogs/v0-10-0", - }, - { - text: "v0.9.0", - link: "/docs/changelogs/v0-9-0", - }, - { - text: "v0.8.0", - link: "/docs/changelogs/v0-8-0", - }, - { - text: "v0.7.1", - link: "/docs/changelogs/v0-7-1", - }, - { - text: "v0.7.0", - link: "/docs/changelogs/v0-7-0", - }, + { text: "v0.12.1", link: "/docs/changelogs/v0-12-1" }, + { text: "v0.12.0", link: "/docs/changelogs/v0-12-0" }, + { text: "v0.11.0", link: "/docs/changelogs/v0-11-0" }, + { text: "v0.10.0", link: "/docs/changelogs/v0-10-0" }, + { text: "v0.9.0", link: "/docs/changelogs/v0-9-0" }, + { text: "v0.8.0", link: "/docs/changelogs/v0-8-0" }, + { text: "v0.7.1", link: "/docs/changelogs/v0-7-1" }, + { text: "v0.7.0", link: "/docs/changelogs/v0-7-0" }, ], }, ], diff --git a/documentation/.vitepress/seo.ts b/documentation/.vitepress/seo.ts new file mode 100644 index 00000000..038f671e --- /dev/null +++ b/documentation/.vitepress/seo.ts @@ -0,0 +1,306 @@ +export type PageSeo = { + title?: string; + description: string; + keywords?: string[]; +}; + +const DEFAULT_OG_IMAGE = + "https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/screenshots/adventures.png"; + +const SITE_ORIGIN = "https://adventurelog.app"; + +/** Per-page SEO metadata keyed by VitePress relativePath. URLs are preserved for search rankings. */ +export const pageSeo: Record = { + "index.md": { + title: "AdventureLog β€” Travel Log, Trip Planner & World Map", + description: + "Log locations with photos and notes, plan multi-day itineraries with flights and lodging, and track countries on an interactive world map. AdventureLog is the open-source travel companion for remembering every trip.", + keywords: [ + "travel log app", + "trip planner", + "world travel tracker", + "travel itinerary app", + "location travel journal", + "interactive travel map", + "open source travel app", + "AdventureLog", + ], + }, + "docs/intro/adventurelog_overview.md": { + description: + "Learn what AdventureLog is, its core features for location tracking and trip planning, and why it is a modern open-source alternative to closed travel apps.", + keywords: ["AdventureLog features", "open source travel app", "trip planning"], + }, + "docs/install/getting_started.md": { + description: + "Choose the right AdventureLog installation path: quick-start installer, All-in-One Docker, standard Docker, Kubernetes, or platform-specific guides.", + keywords: ["AdventureLog install", "self-hosted travel app setup"], + }, + "docs/install/quick_start.md": { + description: + "Install AdventureLog in seconds with the official curl installer. Defaults to All-in-One Docker with interactive configuration and a built-in management menu.", + keywords: ["AdventureLog quick start", "one line docker install"], + }, + "docs/install/aio.md": { + description: + "Run AdventureLog in a single Docker container on one port. Minimal .env.aio configuration with automatic URL and secret derivation for homelabs and VPS installs.", + keywords: ["AdventureLog AIO", "all in one docker", "single container travel app"], + }, + "docs/install/docker.md": { + description: + "Standard multi-container Docker setup for AdventureLog with separate frontend, backend, and PostGIS services. Full environment variable reference for production deployments.", + keywords: ["AdventureLog docker compose", "self-hosted docker travel log"], + }, + "docs/install/dev_container_wsl.md": { + description: + "Develop AdventureLog on Windows with WSL 2 and VS Code Dev Containers using docker-compose.dev.yml and hot reload for frontend and backend.", + keywords: ["AdventureLog development", "dev container", "WSL docker"], + }, + "docs/install/proxmox_lxc.md": { + description: + "Install AdventureLog on Proxmox using an LXC container with Docker for a lightweight homelab deployment.", + keywords: ["AdventureLog Proxmox", "LXC homelab install"], + }, + "docs/install/synology_nas.md": { + description: + "Self-host AdventureLog on a Synology NAS using Docker or Container Manager with step-by-step setup guidance.", + keywords: ["AdventureLog Synology", "NAS docker install"], + }, + "docs/install/kustomize.md": { + description: + "Deploy AdventureLog on Kubernetes with Kustomize manifests in k8s/base/, including PostGIS and ingress configuration.", + keywords: ["AdventureLog kubernetes", "kustomize deployment"], + }, + "docs/install/unraid.md": { + description: + "Install AdventureLog on Unraid with Docker templates for frontend, backend, and PostGIS database containers.", + keywords: ["AdventureLog Unraid", "homelab docker template"], + }, + "docs/install/nginx_proxy_manager.md": { + description: + "Put AdventureLog behind Nginx Proxy Manager with HTTPS, path routing, and trusted origin configuration for Django and SvelteKit.", + keywords: ["AdventureLog nginx proxy manager", "reverse proxy HTTPS"], + }, + "docs/install/traefik.md": { + description: + "Deploy AdventureLog with Traefik using the official docker-compose-traefik.yaml for automatic HTTPS and path-based routing.", + keywords: ["AdventureLog Traefik", "docker reverse proxy"], + }, + "docs/install/caddy.md": { + description: + "Run AdventureLog behind Caddy for automatic HTTPS and simple reverse proxy configuration on a single domain.", + keywords: ["AdventureLog Caddy", "automatic HTTPS proxy"], + }, + "docs/usage/usage.md": { + description: + "User guide for AdventureLog: locations, visits, collections, itineraries, world travel, integrations, and collaborative trip planning.", + keywords: ["how to use AdventureLog", "travel log tutorial"], + }, + "docs/configuration/environment_variables.md": { + description: + "Complete AdventureLog environment variable reference for standard Docker, AIO, and optional integrations including URLs, security, and storage.", + keywords: ["AdventureLog environment variables", "docker env configuration"], + }, + "docs/configuration/operations.md": { + description: + "Operate AdventureLog in production: deploy.sh updates, backup and restore scripts, validate-env checks, management menu, and first-boot behavior.", + keywords: ["AdventureLog backup", "deploy update", "docker operations"], + }, + "docs/configuration/updating.md": { + description: + "Update AdventureLog Docker images safely with deploy.sh, the installer management menu, manual compose commands, and region data refresh.", + keywords: ["AdventureLog update", "docker pull upgrade"], + }, + "docs/configuration/immich_integration.md": { + description: + "Connect AdventureLog to Immich for photo imports and linking images to travel locations from your self-hosted media library.", + keywords: ["AdventureLog Immich integration", "photo travel log"], + }, + "docs/configuration/google_maps_integration.md": { + description: + "Enable Google Maps in AdventureLog for enhanced map tiles and place search using a Google Maps API key.", + keywords: ["AdventureLog Google Maps", "maps API key"], + }, + "docs/configuration/strava_integration.md": { + description: + "Import Strava activities into AdventureLog locations with GPX tracks, distance, and elevation data.", + keywords: ["AdventureLog Strava", "activity import"], + }, + "docs/configuration/wanderer_integration.md": { + description: + "Link Wanderer trails to AdventureLog locations for hiking routes with distance and elevation context.", + keywords: ["AdventureLog Wanderer", "trail integration"], + }, + "docs/configuration/social_auth.md": { + description: + "Configure social and OIDC login for AdventureLog with GitHub, Authentik, Pocket ID, Authelia, and generic OpenID Connect providers.", + keywords: ["AdventureLog OIDC", "social login self-hosted"], + }, + "docs/configuration/social_auth/authentik.md": { + description: + "Set up Authentik as an OpenID Connect provider for AdventureLog single sign-on and account linking.", + keywords: ["AdventureLog Authentik", "OIDC SSO"], + }, + "docs/configuration/social_auth/github.md": { + description: + "Enable GitHub OAuth login for AdventureLog using django-allauth social application configuration.", + keywords: ["AdventureLog GitHub login", "OAuth"], + }, + "docs/configuration/social_auth/pocket_id.md": { + description: + "Configure Pocket ID as an OIDC identity provider for AdventureLog authentication.", + keywords: ["AdventureLog Pocket ID", "OIDC login"], + }, + "docs/configuration/social_auth/oidc.md": { + description: + "Connect any OpenID Connect provider to AdventureLog for enterprise or self-hosted identity management.", + keywords: ["AdventureLog OpenID Connect", "generic OIDC"], + }, + "docs/configuration/disable_registration.md": { + description: + "Disable public user registration on a self-hosted AdventureLog instance while keeping invites and social signup options.", + keywords: ["AdventureLog disable registration", "private instance"], + }, + "docs/configuration/email.md": { + description: + "Configure SMTP email in AdventureLog for account verification, password reset, and invitation messages.", + keywords: ["AdventureLog SMTP", "email configuration"], + }, + "docs/configuration/analytics.md": { + description: + "Optionally add Umami analytics to AdventureLog for privacy-friendly usage tracking on your self-hosted instance.", + keywords: ["AdventureLog Umami analytics"], + }, + "docs/configuration/s3_storage.md": { + description: + "Store AdventureLog media on S3-compatible object storage including AWS S3, Cloudflare R2, MinIO, and DigitalOcean Spaces.", + keywords: ["AdventureLog S3 storage", "R2 media", "object storage"], + }, + "docs/configuration/api_keys.md": { + description: + "Create and use AdventureLog REST API keys for scripts and integrations with the locations, collections, and stats endpoints.", + keywords: ["AdventureLog API keys", "REST API authentication"], + }, + "docs/configuration/advanced_configuration.md": { + description: + "Advanced AdventureLog settings: rate limits, Gunicorn workers, email verification, social-only login, and first-boot world data options.", + keywords: ["AdventureLog advanced config", "rate limits", "gunicorn"], + }, + "docs/troubleshooting/no_images.md": { + description: + "Fix AdventureLog images not displaying: URL configuration, media paths, S3 settings, and reverse proxy routing for /media.", + keywords: ["AdventureLog images not showing", "media troubleshooting"], + }, + "docs/troubleshooting/login_unresponsive.md": { + description: + "Resolve AdventureLog login and registration failures caused by CSRF, ORIGIN, SITE_URL, or reverse proxy misconfiguration.", + keywords: ["AdventureLog login broken", "CSRF troubleshooting"], + }, + "docs/troubleshooting/nginx_failed.md": { + description: + "Diagnose 'Starting nginx: nginx failed' errors in the AdventureLog backend container during Docker startup.", + keywords: ["AdventureLog nginx failed", "backend container error"], + }, + "docs/guides/admin_panel.md": { + description: + "Use the Django admin panel at /admin to manage AdventureLog users, locations, and database objects as a staff administrator.", + keywords: ["AdventureLog admin panel", "Django admin"], + }, + "docs/guides/invite_user.md": { + description: + "Invite users to a private AdventureLog instance using django-invitations from the admin panel or in-app invite flow.", + keywords: ["AdventureLog invite user", "private instance"], + }, + "docs/guides/v0-7-1_migration.md": { + description: + "Migrate AdventureLog to v0.7.1 with the updated in-container nginx and gunicorn Docker Compose layout.", + keywords: ["AdventureLog v0.7.1 migration", "nginx migration"], + }, + "docs/changelogs/development_timeline.md": { + description: + "The origin story and development timeline of AdventureLog from first commit to a full-featured self-hosted travel platform.", + keywords: ["AdventureLog history", "development timeline"], + }, + "docs/changelogs/v0-12-1.md": { + description: "AdventureLog v0.12.1 release notes, bug fixes, and improvements.", + keywords: ["AdventureLog v0.12.1 changelog"], + }, + "docs/changelogs/v0-12-0.md": { + description: + "AdventureLog v0.12.0 release: trip planning improvements, itineraries, and budget features.", + keywords: ["AdventureLog v0.12.0 changelog"], + }, + "docs/changelogs/v0-11-0.md": { + description: + "AdventureLog v0.11.0 release: Strava and Wanderer integrations, redesigned UI, and new features.", + keywords: ["AdventureLog v0.11.0 changelog"], + }, + "docs/changelogs/v0-10-0.md": { + description: + "AdventureLog v0.10.0 release: trip maps, Google Maps integration, and quick deploy script.", + keywords: ["AdventureLog v0.10.0 changelog"], + }, + "docs/changelogs/v0-9-0.md": { + description: + "AdventureLog v0.9.0 release: smart recommendations, attachments, and map improvements.", + keywords: ["AdventureLog v0.9.0 changelog"], + }, + "docs/changelogs/v0-8-0.md": { + description: + "AdventureLog v0.8.0 release: Immich integration, calendar view, and UI customization.", + keywords: ["AdventureLog v0.8.0 changelog"], + }, + "docs/changelogs/v0-7-1.md": { + description: + "AdventureLog v0.7.1 release: in-container nginx migration, gunicorn, and adventure sorting improvements.", + keywords: ["AdventureLog v0.7.1 changelog"], + }, + "docs/changelogs/v0-7-0.md": { + description: "AdventureLog v0.7.0 release notes and feature summary.", + keywords: ["AdventureLog v0.7.0 changelog"], + }, +}; + +export function pagePathToUrl(relativePath: string): string { + if (relativePath === "index.md") { + return `${SITE_ORIGIN}/`; + } + + const slug = relativePath.replace(/\.md$/, "").replace(/\/index$/, ""); + return `${SITE_ORIGIN}/${slug}.html`; +} + +export function buildPageHead( + relativePath: string, + pageTitle: string, + seo: PageSeo, +): Array<[string, Record] | [string, Record, string]> { + const description = seo.description; + const canonicalUrl = pagePathToUrl(relativePath); + const ogTitle = seo.title ?? pageTitle; + + const head: Array< + [string, Record] | [string, Record, string] + > = [ + ["meta", { name: "description", content: description }], + ["meta", { property: "og:title", content: ogTitle }], + ["meta", { property: "og:description", content: description }], + ["meta", { property: "og:url", content: canonicalUrl }], + ["meta", { property: "og:type", content: "article" }], + ["meta", { property: "og:image", content: DEFAULT_OG_IMAGE }], + ["meta", { property: "og:site_name", content: "AdventureLog" }], + ["meta", { name: "twitter:card", content: "summary_large_image" }], + ["meta", { name: "twitter:title", content: ogTitle }], + ["meta", { name: "twitter:description", content: description }], + ["meta", { name: "twitter:image", content: DEFAULT_OG_IMAGE }], + ["link", { rel: "canonical", href: canonicalUrl }], + ]; + + if (seo.keywords?.length) { + head.push(["meta", { name: "keywords", content: seo.keywords.join(", ") }]); + } + + return head; +} + +export { DEFAULT_OG_IMAGE, SITE_ORIGIN }; diff --git a/documentation/.vitepress/theme/components/HomeFeatures.vue b/documentation/.vitepress/theme/components/HomeFeatures.vue new file mode 100644 index 00000000..bc37f156 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeFeatures.vue @@ -0,0 +1,50 @@ + + + diff --git a/documentation/.vitepress/theme/components/HomeFinalCta.vue b/documentation/.vitepress/theme/components/HomeFinalCta.vue new file mode 100644 index 00000000..a0ecce85 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeFinalCta.vue @@ -0,0 +1,30 @@ + diff --git a/documentation/.vitepress/theme/components/HomeHero.vue b/documentation/.vitepress/theme/components/HomeHero.vue new file mode 100644 index 00000000..4633c588 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeHero.vue @@ -0,0 +1,127 @@ + + + diff --git a/documentation/.vitepress/theme/components/HomeInstall.vue b/documentation/.vitepress/theme/components/HomeInstall.vue new file mode 100644 index 00000000..5d18a15c --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeInstall.vue @@ -0,0 +1,178 @@ + + + diff --git a/documentation/.vitepress/theme/components/HomePillars.vue b/documentation/.vitepress/theme/components/HomePillars.vue new file mode 100644 index 00000000..6df6ebc6 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomePillars.vue @@ -0,0 +1,54 @@ + + + diff --git a/documentation/.vitepress/theme/components/HomeShowcase.vue b/documentation/.vitepress/theme/components/HomeShowcase.vue new file mode 100644 index 00000000..bfe9d1c8 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeShowcase.vue @@ -0,0 +1,98 @@ + + + diff --git a/documentation/.vitepress/theme/components/HomeSocialProof.vue b/documentation/.vitepress/theme/components/HomeSocialProof.vue new file mode 100644 index 00000000..daaff214 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeSocialProof.vue @@ -0,0 +1,56 @@ + + + diff --git a/documentation/.vitepress/theme/components/HomeTech.vue b/documentation/.vitepress/theme/components/HomeTech.vue new file mode 100644 index 00000000..cbc23b99 --- /dev/null +++ b/documentation/.vitepress/theme/components/HomeTech.vue @@ -0,0 +1,33 @@ + + + diff --git a/documentation/.vitepress/theme/home.css b/documentation/.vitepress/theme/home.css new file mode 100644 index 00000000..813e464e --- /dev/null +++ b/documentation/.vitepress/theme/home.css @@ -0,0 +1,1296 @@ +/* ─── Landing page layout ─────────────────────────────────────────── */ + +.VPHome { + padding-bottom: 0 !important; +} + +.VPHome .VPContent { + max-width: none !important; + padding: 0 !important; +} + +.VPHome .vp-doc { + max-width: none; + padding: 0; +} + +.VPHome .vp-doc > div { + max-width: none; +} + +/* VitePress doc typography bleeds into custom landing sections β€” reset it */ +.VPHome .vp-doc section h2, +.VPHome .vp-doc section h3 { + border-top: none !important; + padding-top: 0 !important; + margin-top: 0 !important; + letter-spacing: -0.02em; +} + +.VPHome .vp-doc section p { + margin-top: 0; +} + +.VPHome .vp-doc section ul { + list-style: none !important; + padding-left: 0 !important; + margin-top: 0; +} + +.VPHome .vp-doc section li { + margin-top: 0; +} + +.VPHome .vp-doc section li + li { + margin-top: 0; +} + +.VPHome .container { + max-width: 1180px; + margin: 0 auto; + padding: 0 24px; +} + +/* Hide default VitePress hero β€” custom HomeHero replaces it */ +.VPHome .VPHero { + display: none !important; +} + +/* ─── SaaS Hero ───────────────────────────────────────────────────── */ + +.al-hero { + position: relative; + padding: 48px 24px 56px; + overflow: hidden; +} + +.al-hero__backdrop { + position: absolute; + inset: 0; + pointer-events: none; + overflow: hidden; +} + +.al-hero__grid { + position: absolute; + inset: 0; + background-image: + linear-gradient(var(--vp-c-divider) 1px, transparent 1px), + linear-gradient(90deg, var(--vp-c-divider) 1px, transparent 1px); + background-size: 64px 64px; + mask-image: radial-gradient(ellipse 80% 70% at 50% 0%, black 20%, transparent 75%); + opacity: 0.45; +} + +.al-hero__orb { + position: absolute; + border-radius: 50%; + filter: blur(80px); +} + +.al-hero__orb--green { + width: 520px; + height: 520px; + top: -180px; + left: 50%; + transform: translateX(-60%); + background: rgba(28, 145, 63, 0.22); +} + +.al-hero__orb--blue { + width: 400px; + height: 400px; + top: -60px; + right: -80px; + background: rgba(31, 115, 241, 0.14); +} + +.dark .al-hero__orb--green { + background: rgba(28, 145, 63, 0.16); +} + +.dark .al-hero__orb--blue { + background: rgba(31, 115, 241, 0.1); +} + +.al-hero__inner { + position: relative; + z-index: 1; + max-width: 1180px; + margin: 0 auto; + display: grid; + grid-template-columns: 1fr 1.05fr; + gap: 48px; + align-items: center; +} + +.al-hero__copy { + max-width: 540px; +} + +.al-hero__pill { + display: inline-flex; + align-items: center; + gap: 8px; + margin-bottom: 24px; + padding: 6px 14px 6px 10px; + border-radius: 999px; + font-size: 0.8rem; + font-weight: 600; + color: var(--vp-c-text-2); + background: var(--vp-c-bg); + border: 1px solid var(--vp-c-divider); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); +} + +.al-hero__pill-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--vp-c-brand-1); + box-shadow: 0 0 0 3px var(--vp-c-brand-soft); + animation: al-pulse 2.5s ease-in-out infinite; +} + +@keyframes al-pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.al-hero__title { + margin: 0 0 20px; + font-size: clamp(2.5rem, 4.5vw, 3.75rem); + font-weight: 800; + line-height: 1.05; + letter-spacing: -0.04em; + color: var(--vp-c-text-1); + border: none; + padding: 0; +} + +.al-hero__title-accent { + display: block; + background: linear-gradient(135deg, #159947 0%, #1c913f 40%, #1f73f1 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.al-hero__lead { + margin: 0 0 28px; + font-size: 1.125rem; + line-height: 1.65; + color: var(--vp-c-text-2); + max-width: 480px; +} + +.al-hero__actions { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-bottom: 20px; +} + +.al-hero__btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 22px; + border-radius: 10px; + font-size: 0.95rem; + font-weight: 600; + text-decoration: none !important; + transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease; +} + +.al-hero__btn:hover { + transform: translateY(-1px); +} + +.al-hero__btn--primary { + color: #fff !important; + background: linear-gradient(135deg, #1a9e4a 0%, #1c913f 50%, #178f3a 100%); + box-shadow: + 0 1px 2px rgba(0, 0, 0, 0.06), + 0 8px 24px rgba(28, 145, 63, 0.32); +} + +.al-hero__btn--primary:hover { + box-shadow: + 0 1px 2px rgba(0, 0, 0, 0.06), + 0 12px 32px rgba(28, 145, 63, 0.4); +} + +.al-hero__btn--secondary { + color: var(--vp-c-text-1) !important; + background: var(--vp-c-bg); + border: 1px solid var(--vp-c-divider); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); +} + +.al-hero__btn--secondary:hover { + border-color: var(--vp-c-text-3); + background: var(--vp-c-bg-soft); +} + +.al-hero__install { + display: flex; + align-items: center; + gap: 8px; + max-width: 100%; + margin-bottom: 28px; + padding: 4px 4px 4px 14px; + border-radius: 10px; + background: var(--vp-c-bg-soft); + border: 1px solid var(--vp-c-divider); +} + +.al-hero__cmd { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 0.78rem; + color: var(--vp-c-text-2); + background: transparent; +} + +.al-hero__prompt { + color: var(--vp-c-brand-1); + margin-right: 6px; + user-select: none; +} + +.al-hero__copy-btn { + flex-shrink: 0; + padding: 6px 12px; + border-radius: 7px; + background: var(--vp-c-bg); + color: var(--vp-c-text-2); + font-size: 0.75rem; + font-weight: 600; + cursor: pointer; + border: 1px solid var(--vp-c-divider); + transition: background 0.15s ease; +} + +.al-hero__copy-btn:hover { + background: var(--vp-c-default-soft); + color: var(--vp-c-text-1); +} + +.al-hero__stats { + display: flex; + flex-wrap: wrap; + gap: 20px 28px; + margin: 0; + padding: 0; + list-style: none; +} + +.al-hero__stats li { + min-width: 120px; + font-size: 0.88rem; + color: var(--vp-c-text-3); +} + +.al-hero__stats strong { + display: block; + font-size: 0.95rem; + font-weight: 800; + letter-spacing: -0.02em; + color: var(--vp-c-text-1); + margin-bottom: 2px; +} + +/* Hero visual / browser mockup */ +.al-hero__visual { + position: relative; + min-height: 320px; +} + +.al-hero__glow { + position: absolute; + inset: 15% 0 5%; + background: linear-gradient(135deg, rgba(28, 145, 63, 0.3), rgba(31, 115, 241, 0.2)); + filter: blur(56px); + border-radius: 24px; + z-index: 0; +} + +.al-hero__frame { + position: relative; + z-index: 1; + border-radius: 14px; + overflow: hidden; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + box-shadow: + 0 0 0 1px rgba(255, 255, 255, 0.05) inset, + 0 24px 48px -12px rgba(0, 0, 0, 0.18), + 0 48px 96px -24px rgba(28, 145, 63, 0.12); + transform: perspective(1200px) rotateY(-4deg) rotateX(2deg); + transition: transform 0.4s ease; +} + +.al-hero__frame:hover { + transform: perspective(1200px) rotateY(-2deg) rotateX(1deg); +} + +.dark .al-hero__frame { + box-shadow: + 0 0 0 1px rgba(255, 255, 255, 0.06) inset, + 0 24px 48px -12px rgba(0, 0, 0, 0.5), + 0 48px 96px -24px rgba(28, 145, 63, 0.08); +} + +.al-hero__chrome { + display: flex; + align-items: center; + gap: 6px; + padding: 10px 14px; + background: var(--vp-c-bg-soft); + border-bottom: 1px solid var(--vp-c-divider); +} + +.al-hero__chrome span { + width: 10px; + height: 10px; + border-radius: 50%; + background: var(--vp-c-divider); +} + +.al-hero__chrome span:nth-child(1) { + background: #ff5f57; +} +.al-hero__chrome span:nth-child(2) { + background: #febc2e; +} +.al-hero__chrome span:nth-child(3) { + background: #28c840; +} + +.al-hero__url { + flex: 1; + margin-left: 8px; + padding: 4px 12px; + border-radius: 6px; + font-size: 0.72rem; + color: var(--vp-c-text-3); + text-align: center; + background: var(--vp-c-bg); + border: 1px solid var(--vp-c-divider); +} + +.al-hero__shot { + display: block; + width: 100%; + height: auto; +} + +.al-hero__shot--back { + display: none; +} + +.al-hero__float { + position: absolute; + z-index: 2; + display: flex; + align-items: center; + gap: 10px; + padding: 10px 14px; + border-radius: 12px; + background: var(--vp-c-bg); + border: 1px solid var(--vp-c-divider); + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1); + animation: al-float 5s ease-in-out infinite; +} + +.al-hero__float strong { + display: block; + font-size: 0.82rem; + color: var(--vp-c-text-1); +} + +.al-hero__float small { + font-size: 0.72rem; + color: var(--vp-c-text-3); +} + +.al-hero__float-icon { + font-size: 1.25rem; + line-height: 1; +} + +.al-hero__float--map { + left: -16px; + bottom: 28%; + animation-delay: 0s; +} + +.al-hero__float--docker { + right: -12px; + top: 18%; + animation-delay: -2.5s; +} + +@keyframes al-float { + 0%, + 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-6px); + } +} + +/* Hide default VitePress features β€” custom HomeFeatures replaces them */ +.VPHome .VPFeatures { + display: none !important; +} + +/* ─── Feature cards ───────────────────────────────────────────────── */ + +.al-features { + padding: 56px 24px 72px; + border-top: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg-soft); +} + +.al-features__inner { + max-width: 1180px; + margin: 0 auto; +} + +.al-features__head { + max-width: 640px; + margin: 0 auto 48px; + text-align: center; +} + +.al-features__head h2 { + margin: 0 0 14px; + font-size: clamp(1.5rem, 2.8vw, 2rem); + line-height: 1.2; + letter-spacing: -0.02em; + border: none; + padding: 0; +} + +.al-features__lead { + margin: 0; + font-size: 1.05rem; + line-height: 1.65; + color: var(--vp-c-text-2); +} + +.al-features__grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 28px; +} + +.al-features__card { + position: relative; + display: flex; + flex-direction: column; + gap: 0; + padding: 32px 28px 28px; + border-radius: 20px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; +} + +.al-features__card:hover { + transform: translateY(-4px); + border-color: var(--vp-c-brand-soft); + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.08); +} + +.dark .al-features__card:hover { + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.25); +} + +.al-features__step { + position: absolute; + top: 20px; + right: 22px; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.06em; + color: var(--vp-c-text-3); + opacity: 0.6; +} + +.al-features__icon { + display: flex; + align-items: center; + justify-content: center; + width: 52px; + height: 52px; + margin-bottom: 20px; + border-radius: 14px; + font-size: 1.5rem; + background: var(--vp-c-brand-soft); + border: 1px solid transparent; +} + +.al-features__card h3 { + margin: 0 0 8px; + font-size: 1.2rem; + font-weight: 700; + letter-spacing: -0.02em; + border: none; + padding: 0; + color: var(--vp-c-text-1); +} + +.al-features__summary { + margin: 0 0 14px; + font-size: 0.95rem; + font-weight: 600; + line-height: 1.45; + color: var(--vp-c-text-1); +} + +.al-features__details { + margin: 0; + font-size: 0.9rem; + line-height: 1.65; + color: var(--vp-c-text-2); + flex: 1; +} + +/* ─── Shared section styles ───────────────────────────────────────── */ + +.al-eyebrow { + display: inline-block; + margin: 0 0 10px; + font-size: 0.78rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--vp-c-brand-1); +} + +.al-section-head { + max-width: 720px; + margin-bottom: 36px; +} + +.al-section-head--center { + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.al-section-head h2 { + margin: 0 0 12px; + font-size: clamp(1.6rem, 3vw, 2.2rem); + line-height: 1.2; + letter-spacing: -0.02em; + border: none; + padding: 0; +} + +.al-section-lead { + margin: 0; + font-size: 1.05rem; + line-height: 1.65; + color: var(--vp-c-text-2); +} + +.al-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 10px 20px; + border-radius: 10px; + font-weight: 600; + font-size: 0.95rem; + text-decoration: none !important; + transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease; +} + +.al-btn:hover { + transform: translateY(-1px); +} + +.al-btn--brand { + background: var(--vp-c-brand-3); + color: #fff !important; + box-shadow: 0 6px 20px rgba(28, 145, 63, 0.25); +} + +.al-btn--brand:hover { + background: var(--vp-c-brand-2); +} + +.al-btn--ghost { + border: 1px solid var(--vp-c-divider); + color: var(--vp-c-text-1) !important; + background: var(--vp-c-bg); +} + +.al-btn--ghost:hover { + border-color: var(--vp-c-brand-1); + color: var(--vp-c-brand-1) !important; +} + +.al-btn--lg { + padding: 12px 24px; + font-size: 1rem; +} + +/* ─── Install section ───────────────────────────────────────────── */ + +.al-install { + padding: 80px 24px; + background: linear-gradient(180deg, var(--vp-c-bg) 0%, var(--vp-c-bg-soft) 100%); +} + +.al-install__inner { + max-width: 1180px; + margin: 0 auto; + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 56px; + align-items: center; +} + +.al-install__copy { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 20px; +} + +.al-install__copy .al-eyebrow { + margin: 0; +} + +.al-install__copy h2 { + margin: 0; + font-size: clamp(1.5rem, 2.5vw, 2rem); + line-height: 1.2; + font-weight: 800; + border: none; + padding: 0; + color: var(--vp-c-text-1); +} + +.al-install__desc { + margin: 0; + max-width: 42ch; + color: var(--vp-c-text-2); + line-height: 1.65; + font-size: 1rem; +} + +.al-install__badges { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin: 0; + padding: 0; + list-style: none; +} + +.al-install__badges li { + margin: 0; + padding: 8px 14px; + border-radius: 999px; + font-size: 0.82rem; + font-weight: 600; + line-height: 1.2; + white-space: nowrap; + background: var(--vp-c-brand-soft); + color: var(--vp-c-brand-1); + border: 1px solid transparent; +} + +.al-install__links { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 4px; +} + +/* Install paths panel */ +.al-install__panel { + display: flex; + flex-direction: column; + gap: 16px; +} + +.al-install__panel-label { + margin: 0; + font-size: 0.78rem; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--vp-c-text-3); +} + +.al-install__group + .al-install__group { + margin-top: 18px; +} + +.al-install__group-label { + margin: 0 0 8px; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--vp-c-text-3); +} + +.al-install__paths { + margin: 0; + padding: 0; + list-style: none; + display: flex; + flex-direction: column; + gap: 10px; +} + +.al-install__paths li { + margin: 0; +} + +.al-install__path { + display: flex; + align-items: center; + gap: 14px; + padding: 14px 16px; + border-radius: 14px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + text-decoration: none !important; + transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease; +} + +.al-install__path:hover { + border-color: var(--vp-c-brand-1); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06); + transform: translateY(-1px); +} + +.al-install__path-icon { + flex-shrink: 0; + font-size: 1.25rem; + line-height: 1; +} + +.al-install__path-text { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 3px; +} + +.al-install__path-text strong { + font-size: 0.95rem; + font-weight: 700; + color: var(--vp-c-text-1); +} + +.al-install__path-text small { + font-size: 0.82rem; + line-height: 1.45; + color: var(--vp-c-text-2); +} + +.al-install__path-arrow { + flex-shrink: 0; + font-size: 1rem; + color: var(--vp-c-text-3); + transition: color 0.15s ease, transform 0.15s ease; +} + +.al-install__path:hover .al-install__path-arrow { + color: var(--vp-c-brand-1); + transform: translateX(2px); +} + +.al-install__quick { + padding: 14px 16px; + border-radius: 14px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg-soft); +} + +.al-install__quick-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 10px; + font-size: 0.78rem; + font-weight: 600; + color: var(--vp-c-text-3); +} + +.al-install__quick-copy { + padding: 4px 10px; + border-radius: 6px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + color: var(--vp-c-text-2); + font-size: 0.72rem; + font-weight: 600; + cursor: pointer; +} + +.al-install__quick-copy:hover { + border-color: var(--vp-c-brand-1); + color: var(--vp-c-brand-1); +} + +.al-install__quick-cmd { + display: block; + margin: 0; + padding: 12px 14px; + border-radius: 10px; + font-size: 0.8rem; + line-height: 1.5; + overflow-x: auto; + white-space: nowrap; + color: var(--vp-c-text-2); + background: #0d1117; +} + +.dark .al-install__quick-cmd { + background: #161b22; +} + +.al-prompt { + color: var(--vp-c-brand-1); + user-select: none; +} + +/* ─── Showcase ────────────────────────────────────────────────────── */ + +.al-showcase { + padding: 80px 24px; +} + +.al-showcase__tabs { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 28px; + max-width: 1180px; + margin-left: auto; + margin-right: auto; +} + +.al-showcase__tab { + padding: 10px 18px; + border-radius: 999px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + color: var(--vp-c-text-2); + font-weight: 600; + font-size: 0.88rem; + cursor: pointer; + transition: all 0.15s ease; +} + +.al-showcase__tab:hover { + border-color: var(--vp-c-brand-1); + color: var(--vp-c-brand-1); +} + +.al-showcase__tab.is-active { + background: var(--vp-c-brand-soft); + border-color: var(--vp-c-brand-1); + color: var(--vp-c-brand-1); +} + +.al-showcase__panel { + max-width: 1180px; + margin: 0 auto; + display: grid; + grid-template-columns: 280px 1fr; + gap: 32px; + align-items: start; +} + +.al-showcase__text h3 { + margin: 0 0 10px; + font-size: 1.25rem; + border: none; + padding: 0; +} + +.al-showcase__text p { + margin: 0; + color: var(--vp-c-text-2); + line-height: 1.65; +} + +.al-showcase__frame { + margin: 0; + border-radius: 14px; + overflow: hidden; + border: 1px solid var(--vp-c-divider); + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12); +} + +.al-showcase__frame img { + display: block; + width: 100%; + height: auto; +} + +/* ─── Pillars ─────────────────────────────────────────────────────── */ + +.al-pillars { + padding: 80px 24px; + background: var(--vp-c-bg-soft); + border-top: 1px solid var(--vp-c-divider); + border-bottom: 1px solid var(--vp-c-divider); +} + +.al-pillars__lead { + margin: 0 auto 40px; + max-width: 560px; + text-align: center; + font-size: 1.05rem; + line-height: 1.65; + color: var(--vp-c-text-2); +} + +.al-pillars__grid { + max-width: 1180px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; +} + +.al-pillar { + padding: 24px; + border-radius: 16px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.al-pillar:hover { + transform: translateY(-3px); + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.08); +} + +.al-pillar__icon { + font-size: 1.5rem; + display: block; + margin-bottom: 12px; +} + +.al-pillar h3 { + margin: 0 0 8px; + font-size: 1.05rem; + border: none; + padding: 0; +} + +.al-pillar p { + margin: 0; + font-size: 0.92rem; + line-height: 1.6; + color: var(--vp-c-text-2); +} + +/* ─── Social proof ────────────────────────────────────────────────── */ + +.al-proof { + padding: 80px 24px; +} + +.al-proof__grid { + max-width: 1180px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20px; +} + +.al-quote { + margin: 0; + padding: 24px; + border-radius: 16px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg-soft); + display: flex; + flex-direction: column; + gap: 16px; +} + +.al-quote p { + margin: 0; + font-size: 1rem; + line-height: 1.65; + font-style: italic; + color: var(--vp-c-text-1); +} + +.al-quote footer { + display: flex; + flex-wrap: wrap; + gap: 6px 12px; + font-size: 0.85rem; + color: var(--vp-c-text-2); +} + +.al-quote cite { + font-style: normal; + font-weight: 700; + color: var(--vp-c-text-1); +} + +.al-quote__rank { + padding: 2px 8px; + border-radius: 6px; + background: var(--vp-c-brand-soft); + color: var(--vp-c-brand-1); + font-weight: 700; + font-size: 0.78rem; +} + +.al-quote a { + font-size: 0.88rem; + font-weight: 600; +} + +/* ─── Tech ────────────────────────────────────────────────────────── */ + +.al-tech { + padding: 80px 24px; + background: var(--vp-c-bg-soft); +} + +.al-tech__grid { + max-width: 900px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; +} + +.al-tech__card { + padding: 24px; + border-radius: 16px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg); + text-align: center; +} + +.al-tech__card h3 { + margin: 0 0 14px; + font-size: 1rem; + border: none; + padding: 0; +} + +.al-tech__card ul { + margin: 0; + padding: 0; + list-style: none; +} + +.al-tech__card li { + padding: 6px 0; + font-size: 0.9rem; + color: var(--vp-c-text-2); +} + +/* ─── Final CTA ───────────────────────────────────────────────────── */ + +.al-final { + position: relative; + padding: 96px 24px; + overflow: hidden; + text-align: center; +} + +.al-final__glow { + position: absolute; + inset: 0; + background: radial-gradient(ellipse 70% 80% at 50% 100%, rgba(28, 145, 63, 0.2), transparent); + pointer-events: none; +} + +.al-final__inner { + position: relative; + z-index: 1; + max-width: 720px; + margin: 0 auto; +} + +.al-final h2 { + margin: 0 0 14px; + font-size: clamp(1.6rem, 3vw, 2.4rem); + line-height: 1.2; + letter-spacing: -0.02em; + border: none; + padding: 0; +} + +.al-final > .al-final__inner > p { + margin: 0 0 28px; + font-size: 1.1rem; + line-height: 1.65; + color: var(--vp-c-text-2); +} + +.al-final__actions { + display: flex; + flex-wrap: wrap; + gap: 12px; + justify-content: center; + margin-bottom: 20px; +} + +.al-final__support { + margin: 0; + font-size: 0.9rem; + color: var(--vp-c-text-2); +} + +.al-final__support a { + font-weight: 600; +} + +/* ─── Responsive ──────────────────────────────────────────────────── */ + +@media (max-width: 768px) { + .al-features__grid { + grid-template-columns: 1fr; + gap: 20px; + max-width: 520px; + margin: 0 auto; + } + + .al-features { + padding: 48px 24px 56px; + } +} + +@media (max-width: 960px) { + .al-hero__inner { + grid-template-columns: 1fr; + gap: 40px; + } + + .al-hero__copy { + max-width: none; + text-align: center; + } + + .al-hero__lead { + margin-left: auto; + margin-right: auto; + } + + .al-hero__actions, + .al-hero__install, + .al-hero__stats { + justify-content: center; + } + + .al-hero__actions { + display: flex; + } + + .al-hero__install { + max-width: 520px; + margin-left: auto; + margin-right: auto; + } + + .al-hero__stats { + display: flex; + justify-content: center; + } + + .al-hero__frame { + transform: none; + max-width: 640px; + margin: 0 auto; + } + + .al-hero__frame:hover { + transform: none; + } + + .al-hero__float { + display: none; + } + + .al-install__inner, + .al-showcase__panel { + grid-template-columns: 1fr; + gap: 40px; + } + + .al-install__copy { + align-items: stretch; + text-align: left; + } + + .al-install__desc { + max-width: none; + } + + .al-install__links .al-btn { + flex: 1 1 auto; + justify-content: center; + min-width: 160px; + } + + .al-install__panel { + max-width: 560px; + margin: 0 auto; + width: 100%; + } + + .al-pillars__grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 640px) { + .al-hero { + padding-top: 32px; + } + + .al-hero__title { + font-size: 2.25rem; + } + + .al-hero__btn { + flex: 1; + justify-content: center; + min-width: 140px; + } + + .al-pillars__grid, + .al-proof__grid, + .al-tech__grid { + grid-template-columns: 1fr; + } +} + +/* Hide default home footer padding clash */ +.VPHome .VPFooter { + margin-top: 0; +} diff --git a/documentation/.vitepress/theme/index.ts b/documentation/.vitepress/theme/index.ts index def4cfc8..fa8d0d06 100644 --- a/documentation/.vitepress/theme/index.ts +++ b/documentation/.vitepress/theme/index.ts @@ -1,17 +1,29 @@ -// https://vitepress.dev/guide/custom-theme -import { h } from 'vue' -import type { Theme } from 'vitepress' -import DefaultTheme from 'vitepress/theme' -import './style.css' +import { h } from "vue"; +import type { Theme } from "vitepress"; +import DefaultTheme from "vitepress/theme"; +import HomeHero from "./components/HomeHero.vue"; +import HomeFeatures from "./components/HomeFeatures.vue"; +import "./style.css"; +import "./home.css"; export default { extends: DefaultTheme, Layout: () => { return h(DefaultTheme.Layout, null, { - // https://vitepress.dev/guide/extending-default-theme#layout-slots - }) + "home-hero-before": () => h(HomeHero), + "home-features-before": () => h(HomeFeatures), + }); }, - enhanceApp({ app, router, siteData }) { - // ... - } -} satisfies Theme + enhanceApp({ app }) { + const components = import.meta.glob("./components/Home*.vue", { + eager: true, + }) as Record; + + for (const path in components) { + const name = path.split("/").pop()!.replace(".vue", ""); + if (name !== "HomeHero" && name !== "HomeFeatures") { + app.component(name, components[path].default); + } + } + }, +} satisfies Theme; diff --git a/documentation/.vitepress/theme/style.css b/documentation/.vitepress/theme/style.css index 25e756b9..693ebbc4 100644 --- a/documentation/.vitepress/theme/style.css +++ b/documentation/.vitepress/theme/style.css @@ -92,18 +92,19 @@ :root { --vp-home-hero-name-color: transparent; - --vp-home-hero-name-background: -webkit-linear-gradient( - 120deg, - #1c913f 30%, - #1f73f1 + --vp-home-hero-name-background: linear-gradient( + 135deg, + #159947 0%, + #1c913f 35%, + #1f73f1 100% ); --vp-home-hero-image-background-image: linear-gradient( - -45deg, - #1c913f 50%, - #1f73f1 50% + 135deg, + rgba(28, 145, 63, 0.5) 0%, + rgba(31, 115, 241, 0.4) 100% ); - --vp-home-hero-image-filter: blur(44px); + --vp-home-hero-image-filter: blur(56px); } @media (min-width: 640px) { diff --git a/documentation/docs/changelogs/v0-7-1.md b/documentation/docs/changelogs/v0-7-1.md index 54aef566..88f7a315 100644 --- a/documentation/docs/changelogs/v0-7-1.md +++ b/documentation/docs/changelogs/v0-7-1.md @@ -10,7 +10,7 @@ Hi everyone! I am super excited to announce the release of AdventureLog v0.7.1. > [!IMPORTANT] > _While the app will still function normally without these changes_, they are recommended for the best support and stability -> The **migration guide** can be found here: https://docs.adventurelog.app/docs/Guides/nginx_migration +> The **migration guide** can be found here: [v0.7.1 Migration Guide](../guides/v0-7-1_migration.md) - Migrated nginx inside of server container for easier deployment, removed external nginx requirement - App now uses gunicorn for better performance at scale diff --git a/documentation/docs/configuration/advanced_configuration.md b/documentation/docs/configuration/advanced_configuration.md index fcd1a096..47fc1342 100644 --- a/documentation/docs/configuration/advanced_configuration.md +++ b/documentation/docs/configuration/advanced_configuration.md @@ -1,9 +1,64 @@ # Advanced Configuration -In addition to the primary configuration variables listed above, there are several optional environment variables that can be set to further customize your AdventureLog instance. These variables are not required for a basic setup but can enhance functionality and security. +Optional environment variables for security hardening, performance tuning, and authentication behavior. For the complete reference, see [Environment Variables](environment_variables.md). -| Name | Required | Description | Default Value | Variable Location | -| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ----------------- | -| `ACCOUNT_EMAIL_VERIFICATION` | No | Enable email verification for new accounts. Options are `none`, `optional`, or `mandatory` | `none` | Backend | -| `FORCE_SOCIALACCOUNT_LOGIN` | No | When set to `True`, only social login is allowed (no password login). The login page will show only social providers or redirect directly to the first provider if only one is configured. | `False` | Backend | -| `SOCIALACCOUNT_ALLOW_SIGNUP` | No | When set to `True`, signup will be allowed via social providers even if registration is disabled. | `False` | Backend | +## Authentication behavior + +| Variable | Default | Description | +| -------- | ------- | ----------- | +| `ACCOUNT_EMAIL_VERIFICATION` | `none` | `none`, `optional`, or `mandatory` email verification for new accounts | +| `FORCE_SOCIALACCOUNT_LOGIN` | `False` | When `True`, disables password login β€” social/OIDC providers only | +| `SOCIALACCOUNT_ALLOW_SIGNUP` | `False` | Allow new accounts via social providers even when `DISABLE_REGISTRATION=True` | + +Related: [Social Auth](social_auth.md), [Disable Registration](disable_registration.md), [SMTP Email](email.md). + +## Rate limiting + +Enable in production to protect against abuse: + +```env +ENABLE_RATE_LIMITS=True +``` + +Per-endpoint overrides (all optional): + +| Variable | Default | Endpoint | +| -------- | ------- | -------- | +| `RATE_LIMIT_USER` | `10000/hour` | Authenticated API requests | +| `RATE_LIMIT_IMAGE_PROXY` | `60/minute` | Image proxy | +| `RATE_LIMIT_IMAGE_IMPORT` | `12/minute` | Image import | +| `RATE_LIMIT_EXTERNAL_GEOCODE` | `120/minute` | External geocoding | +| `RATE_LIMIT_EXTERNAL_RECOMMENDATIONS` | `30/minute` | Recommendations | +| `RATE_LIMIT_EXTERNAL_WIKIPEDIA` | `60/minute` | Wikipedia lookups | +| `RATE_LIMIT_EXTERNAL_SUN_TIMES` | `30/minute` | Sun times API | + +## Performance + +| Variable | Default | Description | +| -------- | ------- | ----------- | +| `GUNICORN_WORKERS` | `2` | Gunicorn worker count. Use `1` on small VPS instances; `(2 Γ— CPU cores) + 1` on larger servers. | +| `SKIP_WORLD_DATA` | unset | Set to `1` to skip the first-boot `download-countries` import. Saves RAM on low-memory hosts; world travel data can be imported later. | + +The installer offers `SKIP_WORLD_DATA=1` automatically when it detects limited RAM. + +## Multi-factor authentication + +MFA (TOTP) is configured per-user in the app, not via environment variables: + +1. Log in and open **Settings β†’ Security** +2. Enable **Multi-Factor Authentication** +3. Scan the QR code with an authenticator app + +## Mobile QR login + +AdventureLog supports QR-based mobile login from **Settings β†’ Security**. No server-side configuration is required. + +## Cloud billing (hosted only) + +These variables apply only to the hosted AdventureLog cloud service, not self-hosted installs: + +| Variable | Description | +| -------- | ----------- | +| `CLOUD_MODE` | Enable cloud billing features | +| `CLOUD_TRIAL_DAYS` | Trial period length | +| `STRIPE_*` | Stripe payment integration keys | diff --git a/documentation/docs/configuration/api_keys.md b/documentation/docs/configuration/api_keys.md index fa871b9b..5d47a046 100644 --- a/documentation/docs/configuration/api_keys.md +++ b/documentation/docs/configuration/api_keys.md @@ -29,7 +29,7 @@ Authorization: Api-Key al_your_key_here ### Example with `curl` ```bash -curl https://your-adventurelog-instance.com/api/adventures/ \ +curl https://your-adventurelog-instance.com/api/locations/ \ -H "X-API-Key: al_your_key_here" ``` diff --git a/documentation/docs/configuration/environment_variables.md b/documentation/docs/configuration/environment_variables.md new file mode 100644 index 00000000..446fa763 --- /dev/null +++ b/documentation/docs/configuration/environment_variables.md @@ -0,0 +1,159 @@ +# Environment Variables + +AdventureLog configuration is driven by environment variables. The file you edit depends on your install type: + +| Install type | Env file | Compose file | +| ------------ | -------- | ------------ | +| All-in-One (AIO) | `.env.aio` | `docker-compose.aio.yml` | +| Standard Docker | `.env` | `docker-compose.yml` | +| Traefik | `.env` | `docker-compose-traefik.yaml` | +| Development | `.env` | `docker-compose.dev.yml` | + +Validate before deploying: + +```bash +bash scripts/validate-env.sh +# or for AIO: +bash scripts/validate-env.sh .env.aio +``` + +::: tip AIO minimal setup +AIO only requires `POSTGRES_PASSWORD` in `.env.aio`. URLs, `SECRET_KEY`, and admin defaults are derived at container startup. See [All-in-One Docker](../install/aio.md). +::: + +## URL and networking + +These variables control how the browser, SvelteKit SSR, and Django talk to each other. + +| Variable | Required | Used by | Description | Default | +| -------- | -------- | ------- | ----------- | ------- | +| `SITE_URL` | No | Both | Single public URL when frontend and backend share one domain. Derives `ORIGIN`, `FRONTEND_URL`, `PUBLIC_URL`, and `CSRF_TRUSTED_ORIGINS` when those are unset. | β€” | +| `PUBLIC_SERVER_URL` | Yes | Frontend SSR | Internal backend URL for server-side requests. **Keep `http://server:8000` in standard Docker.** AIO uses `http://127.0.0.1:8000`. | `http://server:8000` | +| `ORIGIN` | Sometimes | Frontend | Public frontend origin (needed without HTTPS). | `http://localhost:8015` | +| `FRONTEND_URL` | Yes | Backend | Public frontend URL for emails and redirects. | `http://localhost:8015` | +| `PUBLIC_URL` | Yes | Backend | Public backend URL for media and OAuth callbacks. | `http://localhost:8016` | +| `CSRF_TRUSTED_ORIGINS` | Yes | Backend | Comma-separated browser origins allowed to submit forms. | `http://localhost:8015,http://localhost:8016` | +| `FRONTEND_PORT` | Yes | Compose | Host port for the frontend container. | `8015` | +| `BACKEND_PORT` | Yes | Compose | Host port for the backend container. | `8016` | +| `HOST_PORT` | No | AIO compose | Host port mapped to the AIO container. | `8015` | +| `BODY_SIZE_LIMIT` | Yes | Frontend | Maximum upload size in bytes. | `Infinity` | + +See [Standard Docker](../install/docker.md#url-mental-model) for a visual explanation of the URL model. + +## Database (PostgreSQL / PostGIS) + +| Variable | Required | Description | Default | +| -------- | -------- | ----------- | ------- | +| `PGHOST` | Yes | Database hostname inside Docker network. | `db` | +| `POSTGRES_DB` / `PGDATABASE` | Yes | Database name. | `database` | +| `POSTGRES_USER` / `PGUSER` | Yes | Database user. | `adventure` | +| `POSTGRES_PASSWORD` / `PGPASSWORD` | Yes | Database password. Change in production. | `changeme123` | + +## Django core + +| Variable | Required | Description | Default | +| -------- | -------- | ----------- | ------- | +| `SECRET_KEY` | Yes | Django secret key. Auto-generated on AIO if unset. | `changeme123` | +| `DEBUG` | No | Enable debug mode. Use `False` in production. | `False` | +| `DJANGO_ADMIN_USERNAME` | Yes | First-boot superuser username. | `admin` | +| `DJANGO_ADMIN_PASSWORD` | Yes | First-boot superuser password. | `admin` | +| `DJANGO_ADMIN_EMAIL` | Yes | First-boot superuser email. | `admin@example.com` | +| `GUNICORN_WORKERS` | No | Gunicorn worker processes. Use `1` on small hosts; `(2 Γ— CPU) + 1` on larger servers. | `2` | +| `SKIP_WORLD_DATA` | No | Set to `1` to skip the first-boot `download-countries` import (saves RAM; world travel data loads later). | unset | + +## Registration and authentication + +| Variable | Required | Description | Default | +| -------- | -------- | ----------- | ------- | +| `DISABLE_REGISTRATION` | No | Block new account signups. | `False` | +| `DISABLE_REGISTRATION_MESSAGE` | No | Message shown when registration is disabled. | Custom message | +| `SOCIALACCOUNT_ALLOW_SIGNUP` | No | Allow new accounts via social providers when registration is disabled. | `False` | +| `FORCE_SOCIALACCOUNT_LOGIN` | No | Disable password login; social/OIDC only. | `False` | +| `ACCOUNT_EMAIL_VERIFICATION` | No | `none`, `optional`, or `mandatory`. | `none` | + +Related guides: [Social Auth](social_auth.md), [Disable Registration](disable_registration.md), [API Keys](api_keys.md). + +## Rate limiting + +| Variable | Required | Description | Default | +| -------- | -------- | ----------- | ------- | +| `ENABLE_RATE_LIMITS` | No | Enable API rate limiting. Recommended in production. | `False` | +| `RATE_LIMIT_USER` | No | Default authenticated user throttle. | `10000/hour` | +| `RATE_LIMIT_IMAGE_PROXY` | No | Image proxy endpoint limit. | `60/minute` | +| `RATE_LIMIT_IMAGE_IMPORT` | No | Image import limit. | `12/minute` | +| `RATE_LIMIT_EXTERNAL_GEOCODE` | No | External geocoding limit. | `120/minute` | +| `RATE_LIMIT_EXTERNAL_RECOMMENDATIONS` | No | Recommendations API limit. | `30/minute` | +| `RATE_LIMIT_EXTERNAL_WIKIPEDIA` | No | Wikipedia lookup limit. | `60/minute` | +| `RATE_LIMIT_EXTERNAL_SUN_TIMES` | No | Sun times API limit. | `30/minute` | + +See [Advanced Configuration](advanced_configuration.md) for usage notes. + +## Email (SMTP) + +| Variable | Required | Description | +| -------- | -------- | ----------- | +| `EMAIL_BACKEND` | No | `console` (logs only) or `email` (SMTP). | +| `EMAIL_HOST` | If SMTP | SMTP server hostname. | +| `EMAIL_PORT` | No | SMTP port. Default `587`. | +| `EMAIL_USE_TLS` | No | Enable TLS. Default `true`. | +| `EMAIL_USE_SSL` | No | Enable SSL. Default `false`. | +| `EMAIL_HOST_USER` | If SMTP | SMTP username. | +| `EMAIL_HOST_PASSWORD` | If SMTP | SMTP password. | +| `DEFAULT_FROM_EMAIL` | If SMTP | Sender address. | + +See [SMTP Email](email.md). + +## Media storage + +| Variable | Required | Description | Default | +| -------- | -------- | ----------- | ------- | +| `MEDIA_STORAGE` | No | `local` or `s3`. | `local` | +| `MEDIA_STORAGE_LIMIT_MB` | No | Per-user storage cap in MB (`0` = unlimited). | `0` | +| `MEDIA_STORAGE_LIMIT_BYTES` | No | Overrides MB limit when set. | `0` | +| `AWS_ACCESS_KEY_ID` | If S3 | S3 access key. | β€” | +| `AWS_SECRET_ACCESS_KEY` | If S3 | S3 secret key. | β€” | +| `AWS_STORAGE_BUCKET_NAME` | If S3 | Bucket name. | β€” | +| `AWS_S3_ENDPOINT_URL` | If non-AWS | Provider endpoint (R2, MinIO, Spaces). | β€” | +| `AWS_S3_REGION_NAME` | No | Region (`auto` for Cloudflare R2). | β€” | +| `AWS_S3_CUSTOM_DOMAIN` | No | CDN or custom domain for media URLs. | β€” | + +See [S3 Media Storage](s3_storage.md). + +## Integrations + +| Variable | Required | Description | +| -------- | -------- | ----------- | +| `GOOGLE_MAPS_API_KEY` | If enabled | Google Maps tiles and place search. | +| `STRAVA_CLIENT_ID` | If enabled | Strava OAuth client ID. | +| `STRAVA_CLIENT_SECRET` | If enabled | Strava OAuth client secret. | +| `PUBLIC_UMAMI_SRC` | If enabled | Umami analytics script URL. | +| `PUBLIC_UMAMI_WEBSITE_ID` | If enabled | Umami website ID. | + +## Traefik compose + +Used with `docker-compose-traefik.yaml`: + +| Variable | Required | Description | +| -------- | -------- | ----------- | +| `ACME_EMAIL` | Yes | Let's Encrypt registration email. | +| `TRAEFIK_DOMAIN` | Yes | Public domain for the Traefik router. | + +## Operations + +These are not application settings but affect management scripts: + +| Variable | Description | Default | +| -------- | ----------- | ------- | +| `COMPOSE_FILE` | Override compose file (`deploy.sh`, backup, restore). | Auto-detected | +| `ADVENTURELOG_COMPOSE` | Set to `aio` to prefer AIO when both env files exist. | unset | +| `BACKUP_DIR` | Backup output directory for `scripts/backup.sh`. | `backups` | +| `ADVENTURELOG_REF` | Git ref for installer downloads. | `main` | + +See [Operations & Maintenance](operations.md). + +## Source of truth + +- Standard env template: [`.env.example`](https://github.com/seanmorley15/AdventureLog/blob/main/.env.example) +- AIO env template: [`.env.aio.example`](https://github.com/seanmorley15/AdventureLog/blob/main/.env.aio.example) +- Django settings: [`backend/server/main/settings.py`](https://github.com/seanmorley15/AdventureLog/blob/main/backend/server/main/settings.py) +- AIO derivation: [`aio/env-setup.sh`](https://github.com/seanmorley15/AdventureLog/blob/main/aio/env-setup.sh) diff --git a/documentation/docs/configuration/operations.md b/documentation/docs/configuration/operations.md new file mode 100644 index 00000000..c3c5f196 --- /dev/null +++ b/documentation/docs/configuration/operations.md @@ -0,0 +1,140 @@ +# Operations & Maintenance + +Day-to-day tasks for a self-hosted AdventureLog instance: updates, backups, validation, and the installer management menu. + +## Management menu + +Re-run the installer to open the interactive management menu: + +```bash +curl -sSL https://get.adventurelog.app | bash +``` + +Or from your install directory: + +```bash +bash install_adventurelog.sh --manage +``` + +Available actions: + +| Action | What it does | +| ------ | ------------ | +| **Status** | Shows container health and `/health` endpoint | +| **Update** | Pulls latest images and redeploys (optional backup first) | +| **Reconfigure** | Re-runs the configuration wizard | +| **Backup** | Runs `scripts/backup.sh` | +| **Restore** | Runs `scripts/restore.sh` from a backup folder | +| **Logs** | Follows container logs | +| **Restart** | Restarts the compose stack | +| **Uninstall** | Stops containers, removes volumes | + +## Compose file detection + +`deploy.sh`, `scripts/backup.sh`, and `scripts/restore.sh` auto-detect your setup: + +| Condition | Compose file | Env file | +| --------- | ------------ | -------- | +| Only `.env.aio` exists | `docker-compose.aio.yml` | `.env.aio` | +| `ADVENTURELOG_COMPOSE=aio` with both env files | `docker-compose.aio.yml` | `.env.aio` | +| Otherwise | `docker-compose.yml` | `.env` | + +Override manually: + +```bash +COMPOSE_FILE=docker-compose.aio.yml bash deploy.sh --backup +``` + +Always pass `--env-file` when running `docker compose` directly: + +```bash +docker compose --env-file .env.aio -f docker-compose.aio.yml ps +``` + +## Updating + +See [Updating](updating.md) for full details. Quick reference: + +```bash +# Recommended β€” validates env, backs up, pulls, and waits for health +bash deploy.sh --backup + +# AIO with explicit compose file +COMPOSE_FILE=docker-compose.aio.yml bash deploy.sh --backup +``` + +## Backup + +`scripts/backup.sh` creates a timestamped folder under `backups/` containing: + +- Your env file (`.env` or `.env.aio`) +- PostgreSQL dump (`database.sql`) +- Media volume archive (`media.tar.gz`) + +```bash +bash scripts/backup.sh +# Custom output directory: +BACKUP_DIR=/mnt/backups bash scripts/backup.sh +``` + +::: warning Legacy script +The root `backup.sh` only archives the media volume and does **not** include the database. Use `scripts/backup.sh` instead. +::: + +## Restore + +```bash +bash scripts/restore.sh backups/20260101-120000 +``` + +This stops the stack, restores env + database + media, and brings containers back up. + +## Environment validation + +Run before every deploy or after editing env files: + +```bash +bash scripts/validate-env.sh +bash scripts/validate-env.sh .env.aio +``` + +The validator catches common mistakes such as `PUBLIC_SERVER_URL` pointing at the host backend port instead of the internal Docker service name. + +## First boot behavior + +On first start, the backend container: + +1. Runs database migrations +2. Creates the Django superuser from `DJANGO_ADMIN_*` variables +3. Imports world geography data (`download-countries`) unless `SKIP_WORLD_DATA=1` + +The geography import needs **~2 GB RAM** on first boot. Steady-state use is typically **~1 GB**. The installer offers `SKIP_WORLD_DATA=1` on low-memory hosts. + +## Scheduled tasks + +Inside the backend container, a cron job runs nightly (UTC midnight): + +```bash +python manage.py sync_visited_regions +``` + +This keeps world-travel region visit status in sync with location data. + +## In-app backup vs shell scripts + +AdventureLog also has backup/restore features in **Settings** that operate through the REST API. These are separate from `scripts/backup.sh` and are useful for app-level exports. For full disaster recovery (database + media + env), use the shell scripts. + +## Security checklist + +- [ ] Change default `POSTGRES_PASSWORD`, `SECRET_KEY`, and admin credentials +- [ ] Set `ENABLE_RATE_LIMITS=True` in production +- [ ] Configure `CSRF_TRUSTED_ORIGINS` / `SITE_URL` for your public domain +- [ ] Use HTTPS via a reverse proxy +- [ ] Review [API Keys](api_keys.md) and revoke unused keys +- [ ] Enable MFA in **Settings β†’ Security** for admin accounts + +## Related docs + +- [Environment Variables](environment_variables.md) +- [Updating](updating.md) +- [Troubleshooting](../troubleshooting/login_unresponsive.md) diff --git a/documentation/docs/configuration/s3_storage.md b/documentation/docs/configuration/s3_storage.md index 1da02385..d1c8076e 100644 --- a/documentation/docs/configuration/s3_storage.md +++ b/documentation/docs/configuration/s3_storage.md @@ -1,6 +1,6 @@ -## S3-compatible media storage +# S3 Media Storage -This document explains how to enable optional S3-compatible object storage for AdventureLog's user-uploaded media (images, files). Use S3 when you want scalable, durable media hosting separate from the application container. +Store AdventureLog user uploads (images, attachments) on S3-compatible object storage instead of the local filesystem. Supported providers include AWS S3, Cloudflare R2, DigitalOcean Spaces, and MinIO. ### Recommendation diff --git a/documentation/docs/configuration/social_auth.md b/documentation/docs/configuration/social_auth.md index 9d4a2313..dfae8787 100644 --- a/documentation/docs/configuration/social_auth.md +++ b/documentation/docs/configuration/social_auth.md @@ -4,12 +4,17 @@ AdventureLog support authentication via 3rd party services and self-hosted ident The steps for each service varies so please refer to the specific service's documentation for more information. -## Supported Services +## Supported providers -- [Authentik](social_auth/authentik.md) (self-hosted) -- [GitHub](social_auth/github.md) -- [Open ID Connect](social_auth/oidc.md) -- [Authelia](https://www.authelia.com/integration/openid-connect/adventure-log/) +| Provider | Type | Guide | +| -------- | ---- | ----- | +| Authentik | Self-hosted OIDC | [Setup guide](social_auth/authentik.md) | +| GitHub | OAuth | [Setup guide](social_auth/github.md) | +| Pocket ID | Self-hosted OIDC | [Setup guide](social_auth/pocket_id.md) | +| OpenID Connect | Generic OIDC | [Setup guide](social_auth/oidc.md) | +| Authelia | Self-hosted OIDC | [External guide](https://www.authelia.com/integration/openid-connect/adventure-log/) | + +Providers are configured in the Django admin panel under **Social applications**. See the [Admin Panel](../guides/admin_panel.md) for access requirements. ## Linking Existing Accounts diff --git a/documentation/docs/configuration/updating.md b/documentation/docs/configuration/updating.md index 1f3a4e35..a62bd2b0 100644 --- a/documentation/docs/configuration/updating.md +++ b/documentation/docs/configuration/updating.md @@ -1,54 +1,68 @@ -# Updating +# Updating AdventureLog -Updating AdventureLog when using Docker is straightforward. **Back up your instance before updating.** +Keep your self-hosted instance current with the latest images and database migrations. **Always back up before updating.** -### Option 1: Re-run the installer (management menu) +## Option 1: Installer management menu ```bash curl -sSL https://get.adventurelog.app | bash ``` -Choose **Update to latest images** (optionally with backup). +Choose **Update to latest images** (with optional backup). -### Option 2: deploy.sh (cron-safe) +## Option 2: deploy.sh (recommended) -Make sure you are in the same directory as your compose file. +From your install directory (where `deploy.sh` and your compose file live): ```bash bash deploy.sh --backup -bash deploy.sh --logs # optional: follow container logs after deploy +bash deploy.sh --logs # optional: follow logs after deploy ``` -For AIO installs, pass the compose file explicitly or rely on auto-detection when only `.env.aio` exists: +`deploy.sh` validates your env file, creates a backup, pulls images, and runs `docker compose up -d --wait`. + +For AIO installs: ```bash COMPOSE_FILE=docker-compose.aio.yml bash deploy.sh --backup ``` -### Option 3: Manual +See [Operations & Maintenance](operations.md) for compose auto-detection details. + +## Option 3: Manual compose ```bash bash scripts/backup.sh -docker compose pull -docker compose up -d --wait + +# Standard +docker compose --env-file .env -f docker-compose.yml pull +docker compose --env-file .env -f docker-compose.yml up -d --wait + +# AIO +docker compose --env-file .env.aio -f docker-compose.aio.yml pull +docker compose --env-file .env.aio -f docker-compose.aio.yml up -d --wait ``` -To restore from a backup directory: +## Restore from backup ```bash bash scripts/restore.sh backups/YYYYMMDD-HHMMSS ``` -## Updating the Region Data +## Updating region data -Region and Country data in AdventureLog is provided by an open source project: [dr5hn/countries-states-cities-database](https://github.com/dr5hn/countries-states-cities-database). If you would like to update the region data in your AdventureLog instance, you can do so by running the following command. This will make sure your database is up to date with the latest region data for your version of AdventureLog. For security reasons, the region data is not automatically updated to the latest and is release version is controlled in the `settings.py` file. - -```bash -docker exec -it bash -``` - -Once you are in the container run the following command to resync the region data. +Country and region reference data comes from [dr5hn/countries-states-cities-database](https://github.com/dr5hn/countries-states-cities-database). To refresh it manually: ```bash +docker exec -it bash python manage.py download-countries --force ``` + +Region data version is pinned per AdventureLog release in `settings.py` and is not auto-updated on every deploy. + +## What happens during an update + +1. New container images are pulled +2. Containers restart with your existing env and volumes +3. Database migrations run automatically on backend startup +4. The `/health` endpoint confirms the stack is ready diff --git a/documentation/docs/guides/admin_panel.md b/documentation/docs/guides/admin_panel.md index bd13d66a..26880aec 100644 --- a/documentation/docs/guides/admin_panel.md +++ b/documentation/docs/guides/admin_panel.md @@ -1,11 +1,42 @@ -# AdventureLog Admin Panel +# Admin Panel -The AdventureLog Admin Panel, powered by Django, is a web-based interface that allows administrators to manage objects in the AdventureLog database. The Admin Panel is accessible at the `/admin` endpoint of the AdventureLog server. Example: `https://al-server.yourdomain.com/admin`. +The AdventureLog admin panel is powered by Django and is available at `/admin` on your backend URL. In AIO installs, that is the same domain as the frontend (for example `https://adventurelog.example.com/admin`). -Features of the Admin Panel include: +## Access requirements -- **User Management**: Administrators can view and manage user accounts, including creating new users, updating user information, and deleting users. -- **Adventure Management**: Administrators can view and manage adventures, including creating new adventures, updating adventure information, and deleting adventures. -- **Security**: The Admin Panel enforces access control to ensure that only authorized administrators can access and manage the database. This means that only users with the `is_staff` flag set to `True` can access the Admin Panel. +Only users with the **staff** flag (`is_staff=True`) can access the admin panel. The first-boot superuser created from `DJANGO_ADMIN_*` environment variables has staff access by default. -Note: the `CSRF_TRUSTED_ORIGINS` setting in your `docker-compose.yml` file must include the domain of the server. For example, if your server is hosted at `https://al-server.yourdomain.com`, you should add `al-server.yourdomain.com` to the `CSRF_TRUSTED_ORIGINS` setting. +## What you can manage + +| Section | Description | +| ------- | ----------- | +| **Users** | Create, edit, and deactivate user accounts | +| **Locations** | View and manage location records in the database | +| **Social applications** | Configure OAuth/OIDC providers (GitHub, OIDC, etc.) | +| **Invitations** | Send invite links for private instances | +| **World data** | Countries, regions, and cities reference data | + +## CSRF configuration + +If the admin panel loads but form submissions fail, verify `CSRF_TRUSTED_ORIGINS` in your `.env` or `.env.aio` includes your public domain: + +```env +CSRF_TRUSTED_ORIGINS=https://adventurelog.example.com +``` + +When using a single domain, set `SITE_URL` instead and the origins are derived automatically. See [Environment Variables](../configuration/environment_variables.md#url-and-networking). + +## Social auth setup + +OAuth and OIDC providers are configured in the admin panel under **Social applications** and **Social accounts**. Step-by-step guides: + +- [Social Auth overview](../configuration/social_auth.md) +- [GitHub](../configuration/social_auth/github.md) +- [Authentik](../configuration/social_auth/authentik.md) +- [Pocket ID](../configuration/social_auth/pocket_id.md) +- [OpenID Connect](../configuration/social_auth/oidc.md) + +## Related guides + +- [Invite a User](invite_user.md) +- [Disable Registration](../configuration/disable_registration.md) diff --git a/documentation/docs/install/aio.md b/documentation/docs/install/aio.md index 11031f68..0fe6e715 100644 --- a/documentation/docs/install/aio.md +++ b/documentation/docs/install/aio.md @@ -105,6 +105,9 @@ docker compose --env-file .env.aio -f docker-compose.aio.yml build See [`docker/README.md`](https://github.com/seanmorley15/AdventureLog/blob/main/docker/README.md) for all build targets. -## Optional settings +## Operations -Advanced options (S3 media, OAuth, email, etc.) can still be passed as environment variables on the `app` service in `docker-compose.aio.yml`. See the full [Docker configuration](docker.md) reference for available variables. +- [Operations & Maintenance](../configuration/operations.md) β€” backups, updates, management menu +- [Environment Variables](../configuration/environment_variables.md) β€” full reference including optional S3, OAuth, and email settings + +Advanced options can be added to `.env.aio` or the `environment` block in `docker-compose.aio.yml`. diff --git a/documentation/docs/install/docker.md b/documentation/docs/install/docker.md index 6cda23d3..740bf6d7 100644 --- a/documentation/docs/install/docker.md +++ b/documentation/docs/install/docker.md @@ -1,10 +1,10 @@ -# Docker πŸ‹ +# Standard Docker -Docker is the preferred way to run AdventureLog on your local machine. It is a lightweight containerization technology that allows you to run applications in isolated environments called containers. +Run AdventureLog as three containers: SvelteKit frontend, Django backend, and PostGIS database. This layout gives full control over environment variables and is the best fit for reverse proxies and custom integrations. -> **Looking for the simplest setup?** See the [All-in-One (AIO)](aio.md) guide β€” one container, one port, two environment variables. - -> **Note**: This guide mainly focuses on installation with a Linux-based host machine, but the steps are similar for other operating systems. +> **Looking for the simplest setup?** See [All-in-One Docker (AIO)](aio.md) β€” one container, one port, two required env vars. +> +> **Full env reference:** [Environment Variables](../configuration/environment_variables.md) ## Prerequisites @@ -52,7 +52,7 @@ bash scripts/validate-env.sh ## Configuration -The `.env` file contains all the configuration settings for your AdventureLog instance. Here’s a breakdown of each section: +The `.env` file contains all configuration for your instance. Below are the most important variables β€” see [Environment Variables](../configuration/environment_variables.md) for the complete reference. ### 🌐 Frontend (web) @@ -95,12 +95,21 @@ The `.env` file contains all the configuration settings for your AdventureLog in - [Immich Integration](../configuration/immich_integration.md) - [Umami Analytics](../configuration/analytics.md) -## Running the Containers +## Running the containers -Once you've configured `.env`, you can start AdventureLog with: +Validate and start: ```bash -docker compose up -d +bash scripts/validate-env.sh +docker compose --env-file .env -f docker-compose.yml up -d --wait ``` -Enjoy using AdventureLog! πŸŽ‰ +Open **http://localhost:8015** (or your configured `ORIGIN` / `SITE_URL`). + +Default admin login: `admin` / `admin` β€” change this after first login. + +## Next steps + +- [Operations & Maintenance](../configuration/operations.md) β€” backups, updates, management menu +- [Reverse proxy guides](getting_started.md#reverse-proxy) β€” HTTPS on a custom domain +- [Configuration](../configuration/environment_variables.md) β€” integrations and advanced settings diff --git a/documentation/docs/install/getting_started.md b/documentation/docs/install/getting_started.md index a2113381..fd89d7ab 100644 --- a/documentation/docs/install/getting_started.md +++ b/documentation/docs/install/getting_started.md @@ -1,38 +1,74 @@ -# πŸš€ Install Options for AdventureLog +# Install AdventureLog -AdventureLog can be installed in a variety of ways, depending on your platform or preference. +AdventureLog runs on Docker in most setups. Pick the guide that matches your environment β€” from a one-line installer to platform-specific homelab and NAS instructions. -## Which setup should I use? +## Quick start -| Your situation | Recommended path | -| -------------- | ---------------- | -| New homelab / quick install | [Quick start installer](quick_start.md) β€” AIO by default, interactive setup | -| Full env control, split containers, or custom integrations | [Standard Docker](docker.md) β€” full `.env.example` (also available in installer advanced mode) | -| Split domains or path-based reverse proxy (Traefik, NPM, Caddy) | Standard Docker + [reverse proxy docs](#advanced--alternative-setups) | -| Kubernetes cluster | [Kubernetes + Kustomize](kustomize.md) β€” see `k8s/base/` | - -## πŸ“¦ Docker Quick Start - -::: tip Quick Start Script -**The fastest way to get started:** -[Install AdventureLog with a single command β†’](quick_start.md) -Perfect for Docker beginners. +::: tip Fastest install +```bash +curl -sSL https://get.adventurelog.app | bash +``` ::: -## 🐳 Popular Installation Methods +The [Quick Start Installer](quick_start.md) walks you through setup (AIO by default), writes your env files, and starts AdventureLog. Re-run the same command for updates, backups, and configuration changes. -- [All-in-One Docker (AIO)](aio.md) β€” Single container, one port, minimal config -- [Docker](docker.md) β€” Standard multi-container setup -- [Proxmox LXC](proxmox_lxc.md) β€” Lightweight virtual environment -- [Synology NAS](synology_nas.md) β€” Self-host on your home NAS -- [Kubernetes + Kustomize](kustomize.md) β€” Advanced, scalable deployment -- [Unraid](unraid.md) β€” Easy integration for homelabbers -- [Umbrel](https://apps.umbrel.com/app/adventurelog) β€” Home server app store -- [TrueNAS](https://apps.truenas.com/catalog/adventurelog/) β€” TrueNAS app catalog +## Choose your setup -## βš™οΈ Advanced & Alternative Setups +### Docker -- [Nginx Proxy Manager](nginx_proxy_manager.md) - Easy reverse proxy config -- [Traefik](traefik.md) β€” Dynamic reverse proxy with automation -- [Caddy](caddy.md) β€” Automatic HTTPS with a clean config -- [Dev Container + WSL](dev_container_wsl.md) - Windows dev environment with WSL 2 + Dev Containers +| I want to… | Guide | +| ---------- | ----- | +| Guided install on a VPS or homelab | [Quick Start Installer](quick_start.md) | +| One container, one port, minimal config | [All-in-One Docker (AIO)](aio.md) | +| Separate frontend, backend, and database | [Standard Docker](docker.md) | +| HTTPS on a custom domain | [Reverse proxy guides](#reverse-proxy) | + +### Homelab & NAS platforms + +| Platform | Guide | +| -------- | ----- | +| Proxmox LXC | [Proxmox LXC](proxmox_lxc.md) | +| Synology NAS | [Synology NAS](synology_nas.md) | +| Unraid | [Unraid](unraid.md) | +| Umbrel | [Umbrel](https://apps.umbrel.com/app/adventurelog) β€” community app | +| TrueNAS SCALE | [TrueNAS](https://apps.truenas.com/catalog/adventurelog/) β€” community app | + +These guides use the same AdventureLog Docker images, adapted for each platform. + +### Kubernetes + +| Platform | Guide | +| -------- | ----- | +| Kubernetes cluster | [Kubernetes + Kustomize](kustomize.md) | + +### Development + +| Use case | Guide | +| -------- | ----- | +| Local development on Windows / WSL | [Dev Container + WSL](dev_container_wsl.md) | + +### Reverse proxy {#reverse-proxy} + +Use these when AdventureLog sits behind HTTPS on a custom domain: + +| Proxy | Guide | +| ----- | ----- | +| Nginx Proxy Manager | [Nginx Proxy Manager](nginx_proxy_manager.md) | +| Traefik | [Traefik](traefik.md) β€” includes `docker-compose-traefik.yaml` | +| Caddy | [Caddy](caddy.md) | + +Set `SITE_URL` to your public HTTPS URL so Django CSRF and SvelteKit origins stay correct. See [Environment Variables](../configuration/environment_variables.md#url-and-networking). + +## After installation + +1. Log in with your admin credentials (default `admin` / `admin` β€” change immediately) +2. Review [How to Use AdventureLog](../usage/usage.md) +3. Configure optional features in [Configuration](../configuration/environment_variables.md) +4. Set up [backups](../configuration/operations.md#backup) before going to production + +## Requirements + +- Docker Engine + Docker Compose v2 (for Docker-based installs) +- **2 GB RAM** on first boot (world geography import); ~1 GB afterward +- Linux server, VPS, homelab, or macOS with Docker Desktop +- Optional: domain name and reverse proxy for HTTPS diff --git a/documentation/docs/install/quick_start.md b/documentation/docs/install/quick_start.md index e500c9aa..c02ee4d0 100644 --- a/documentation/docs/install/quick_start.md +++ b/documentation/docs/install/quick_start.md @@ -1,47 +1,48 @@ -# πŸš€ Quick Start Install +# Quick Start Installer -Install **AdventureLog** in seconds using our automated installer. The script defaults to the **All-in-One (AIO)** setup β€” one URL, one port, minimal configuration. +Install AdventureLog in seconds with the official curl installer. It defaults to the **All-in-One (AIO)** layout β€” one URL, one port, minimal configuration β€” and includes a management menu for updates and backups. -## πŸ§ͺ One-Liner Install +## One-line install ```bash curl -sSL https://get.adventurelog.app | bash ``` -This will: +## What the installer does -- Check dependencies (Docker, Docker Compose, RAM, architecture) -- Detect ARM hosts and configure a compatible PostGIS image automatically -- Set up the `./adventurelog` project directory -- Download `docker-compose.aio.yml`, `.env.aio`, and management scripts -- Walk you through core and optional configuration (S3, email, integrations, etc.) -- Start AdventureLog and wait for the health check +1. Checks dependencies (Docker, Compose v2, RAM, CPU architecture) +2. Detects ARM hosts and configures a compatible PostGIS image automatically +3. Creates the `./adventurelog` project directory (configurable via `INSTALL_DIR`) +4. Downloads `docker-compose.aio.yml` or `docker-compose.yml`, env files, and management scripts +5. Walks you through site URL, admin credentials, and optional features (S3, email, integrations) +6. Starts containers and waits for the `/health` endpoint +7. Saves credentials to `credentials.txt` when generated -## βœ… Requirements +## Requirements -- Docker + Docker Compose v2 -- **2 GB RAM** recommended on first boot (world geography import); ~1 GB afterward -- Linux server, VPS, or macOS with Docker Desktop -- Optional: domain name for HTTPS (set `SITE_URL` to your public URL) +| Requirement | Details | +| ----------- | ------- | +| Docker + Compose v2 | Required | +| RAM | 2 GB recommended on first boot; ~1 GB afterward | +| OS | Linux server, VPS, or macOS with Docker Desktop | +| Domain | Optional β€” set `SITE_URL` for HTTPS behind a reverse proxy | ::: tip ARM / Apple Silicon -The installer automatically uses `imresamu/postgis:16-3.5-alpine` on ARM hosts. AdventureLog AIO images are multi-arch. +The installer automatically uses `imresamu/postgis:16-3.5-alpine` on ARM hosts. AdventureLog images are multi-arch. ::: -## πŸ” What It Does +## Setup modes -The script automatically: +During installation you can choose: -1. Verifies Docker is installed and running -2. Offers **All-in-One** (recommended) or **Standard** (separate frontend/backend) setup -3. Downloads compose files, `.env.aio` or `.env`, `deploy.sh`, and backup scripts -4. Prompts for site URL, admin credentials, and optional features -5. Waits for `/health` (first boot may take several minutes) -6. Saves optional credentials to `credentials.txt` +| Mode | Compose file | Env file | When to use | +| ---- | ------------ | -------- | ----------- | +| **All-in-One** (default) | `docker-compose.aio.yml` | `.env.aio` | Simplest β€” one port, auto-derived URLs | +| **Standard** | `docker-compose.yml` | `.env` | Full env control, separate frontend/backend ports | -## πŸ”„ Management (Re-run the installer) +## Management menu -Re-run the same command to open the **management menu** when an install already exists: +Re-run the installer when an install already exists: ```bash curl -sSL https://get.adventurelog.app | bash @@ -49,22 +50,29 @@ curl -sSL https://get.adventurelog.app | bash bash install_adventurelog.sh --manage ``` -Management options include: +Options include status, update, reconfigure, backup, restore, logs, restart, and uninstall. See [Operations & Maintenance](../configuration/operations.md). -- Check status and health -- Update to latest images (`deploy.sh --backup`) -- Edit configuration -- Backup and restore -- View logs, restart, or uninstall +## Dry run -## 🧼 Uninstall +Preview what the installer would do without making changes: + +```bash +ADVENTURELOG_SKIP_GUM=1 bash install_adventurelog.sh --dry-run --force-install +``` + +## Uninstall From the management menu, choose **Uninstall**, or manually: ```bash cd adventurelog -docker compose -f docker-compose.aio.yml down -v +docker compose --env-file .env.aio -f docker-compose.aio.yml down -v rm -rf adventurelog ``` -Need more control? See [All-in-One Docker](aio.md), [Standard Docker](docker.md), or other [install options](getting_started.md). +## Next steps + +- [All-in-One Docker](aio.md) β€” how the AIO container works +- [Standard Docker](docker.md) β€” multi-container configuration +- [Environment Variables](../configuration/environment_variables.md) β€” full reference +- [Other install options](getting_started.md) diff --git a/documentation/docs/install/traefik.md b/documentation/docs/install/traefik.md index 2923136b..b95331e0 100644 --- a/documentation/docs/install/traefik.md +++ b/documentation/docs/install/traefik.md @@ -1,7 +1,51 @@ -# Installation with Traefik +# Traefik Reverse Proxy -Traefik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. It is designed to be simple to use and configure, and it integrates well with Docker. +Deploy AdventureLog behind [Traefik](https://traefik.io/) with automatic HTTPS and path-based routing using the official compose file. -AdventureLog has a built-in Traefik configuration that makes it easy to deploy and manage your AdventureLog instance. +## Official compose file -The most recent version of the Traefik `docker-compose.yml` file can be found in the [AdventureLog GitHub repository](https://github.com/seanmorley15/AdventureLog/blob/main/docker-compose-traefik.yaml). +Download [`docker-compose-traefik.yaml`](https://github.com/seanmorley15/AdventureLog/blob/main/docker-compose-traefik.yaml) from the repository. It includes: + +- Traefik v2.11 with Let's Encrypt +- Prebuilt `adventurelog-frontend` and `adventurelog-backend` images (no local build required) +- Path-based routing: frontend pages on `/`, backend on `/media`, `/admin`, `/accounts`, `/static` + +## Required environment variables + +Add these to your `.env` alongside the standard AdventureLog variables: + +| Variable | Description | Example | +| -------- | ----------- | ------- | +| `ACME_EMAIL` | Let's Encrypt registration email | `you@example.com` | +| `TRAEFIK_DOMAIN` | Public domain for the router | `adventurelog.example.com` | +| `SITE_URL` | Public HTTPS URL (derives CSRF and frontend origins) | `https://adventurelog.example.com` | + +See [Environment Variables](../configuration/environment_variables.md) for the full list. + +## Getting started + +```bash +wget https://raw.githubusercontent.com/seanmorley15/AdventureLog/main/docker-compose-traefik.yaml +wget https://raw.githubusercontent.com/seanmorley15/AdventureLog/main/.env.example +cp .env.example .env +# Edit .env: set SITE_URL, ACME_EMAIL, TRAEFIK_DOMAIN, POSTGRES_PASSWORD, SECRET_KEY +bash scripts/validate-env.sh +docker compose -f docker-compose-traefik.yaml up -d +``` + +## Routing overview + +Traefik routes traffic to two containers on a single domain: + +| Path prefix | Service | +| ----------- | ------- | +| `/`, `/api`, `/auth`, app pages | Frontend (SvelteKit) | +| `/media`, `/admin`, `/accounts`, `/static` | Backend (Django/Gunicorn) | + +This matches the internal routing model used by the [All-in-One](aio.md) container, but with separate frontend and backend services. + +## Related guides + +- [Standard Docker](docker.md) β€” base configuration without Traefik +- [Environment Variables](../configuration/environment_variables.md) β€” URL and CSRF settings +- [Nginx Proxy Manager](nginx_proxy_manager.md) β€” alternative reverse proxy diff --git a/documentation/docs/intro/adventurelog_overview.md b/documentation/docs/intro/adventurelog_overview.md index 35ff8361..5e34f5de 100644 --- a/documentation/docs/intro/adventurelog_overview.md +++ b/documentation/docs/intro/adventurelog_overview.md @@ -1,8 +1,8 @@ # About AdventureLog -Starting from a simple idea of tracking travel locations, AdventureLog has grown into a full-fledged travel companion. With AdventureLog, you can log your adventures, keep track of where you've been on the world map, plan your next trip collaboratively, and share your experiences with friends and family. **AdventureLog is the ultimate travel companion for the modern-day explorer**. +AdventureLog is a self-hosted, open-source travel companion for tracking where you have been, planning where you are going, and sharing trips with the people you travel with. -## Features +## Core features - **Track Your Adventures** 🌍: Log your adventures and keep track of where you've been on the world map. - Locations can store a variety of information, including the location, date, and description. @@ -32,4 +32,4 @@ Hi, I'm [Sean Morley](https://seanmorley.com), the creator of AdventureLog. I'm I hope you enjoy using AdventureLog as much as I enjoy creating it! If you have any questions, feedback, or suggestions, feel free to reach out to me via the email address listed on my website. I'm always happy to hear from users and help in any way I can. Thank you for using AdventureLog, and happy travels! 🌍 -If you want to check out the origins of AdventureLog and the timeline, process, and story of its development, check out the [Development Timeline](/docs/changelogs/development_timeline.md). +If you want to check out the origins of AdventureLog and the timeline, process, and story of its development, check out the [Development Timeline](../changelogs/development_timeline.md). diff --git a/documentation/docs/usage/usage.md b/documentation/docs/usage/usage.md index 579f0304..7e8b2e49 100644 --- a/documentation/docs/usage/usage.md +++ b/documentation/docs/usage/usage.md @@ -1,8 +1,25 @@ -# How to use AdventureLog +# How to Use AdventureLog -Welcome to AdventureLog! This guide will help you get started with AdventureLog and provide you with an overview of the features available to you. +Welcome to AdventureLog! This guide covers core concepts and features. For server configuration, see [Environment Variables](../configuration/environment_variables.md). -## Key Terms +## App sections + +| Page | Route | Purpose | +| ---- | ----- | ------- | +| Dashboard | `/dashboard` | Travel statistics and overview | +| Locations | `/locations` | Browse, filter, and manage locations | +| Map | `/map` | Interactive world map with location pins | +| Collections | `/collections` | Trips, folders, and itineraries | +| Calendar | `/calendar` | View collections and visits by date | +| World Travel | `/worldtravel` | Countries, regions, and cities visited | +| Search | `/search` | Full-text search across your data | +| Settings | `/settings` | Profile, integrations, security, API keys | +| Invites | `/invites` | Accept invitations to private instances | +| Admin | `/admin` | Django admin panel (staff only) | + +Configure integrations (Immich, Strava, Wanderer, Google Maps) and security (MFA, API keys) from **Settings**. + +## Key terms #### Locations diff --git a/documentation/index.md b/documentation/index.md index a63b6fdd..9e425965 100644 --- a/documentation/index.md +++ b/documentation/index.md @@ -1,306 +1,18 @@ --- -# https://vitepress.dev/reference/default-theme-home-page layout: home -hero: - name: "AdventureLog" - text: "The ultimate travel companion." - tagline: Discover new places, track your adventures, and share your experiences with friends and family. - actions: - - theme: brand - text: Get Started - link: /docs/install/getting_started - - theme: alt - text: About - link: /docs/intro/adventurelog_overview - - theme: alt - text: Demo - link: https://demo.adventurelog.app - image: - src: ./adventurelog.svg - alt: AdventureLog Map Logo - -features: - - title: "Track Your Adventures" - details: "Log your adventures and keep track of where you've been on the world map." - icon: πŸ“ - - title: "Plan Your Next Trip" - details: "Take the guesswork out of planning your next adventure with an easy-to-use itinerary planner." - icon: πŸ“… - - title: "Share Your Experiences" - details: "Share your adventures with friends and family and collaborate on trips together." - icon: πŸ“Έ +title: AdventureLog β€” Self-Hosted Travel Log & Trip Planner +description: Log locations with photos and notes, plan multi-day itineraries, and track countries on an interactive world map. AdventureLog is the open-source travel companion for remembering every trip. --- -## ⚑️ Quick Start + -Get AdventureLog running in under 60 seconds: + -```bash [One-Line Install] -curl -sSL https://get.adventurelog.app | bash -``` + -You can also explore our [full installation guide](/docs/install/getting_started) for plenty of options, including Docker, Proxmox, Synology NAS, and more. + -## πŸ“Έ See It In Action + -::: details πŸ—‚οΈ **Location Overview & Management** -Manage your full list of locations with ease. View upcoming and past trips, filter and sort by status, date, or category to find exactly what you want quickly. -Location Overview -::: - -::: details πŸ“‹ **Detailed Adventure Logs** -Capture rich details for every location: name, dates, precise locations, vivid descriptions, personal ratings, photos, and customizable categories. Your memories deserve to be more than just map pins β€” keep them alive with full, organized logs. -Detailed Adventure Logs -::: - -::: details πŸ—ΊοΈ **Interactive World Map** -Track every destination you’ve visited or plan to visit with our beautifully detailed, interactive world map. Easily filter locations by visit status β€” visited or planned β€” and add new locations by simply clicking on the map. Watch your travel story unfold visually as your journey grows. -Interactive World Map -Interactive World Map -::: - -::: details ✈️ **Comprehensive Trip Planning** -Organize your multi-day trips with detailed itineraries, including flight information, daily activities, collaborative notes, packing checklists, and handy resource links. Stay on top of your plans and ensure every adventure runs smoothly. -Comprehensive Trip Planning -::: - -::: details πŸ“Š **Travel Statistics Dashboard** -Unlock insights into your travel habits and milestones through elegant, easy-to-understand analytics. Track total countries visited, regions explored, cities logged, and more. Visualize your world travels with ease and celebrate your achievements. -Travel Statistics Dashboard -::: - -::: details ✏️ **Edit & Customize Locations** -Make quick updates or deep customizations to any location using a clean and intuitive editing interface. Add photos, update notes, adjust dates, and moreβ€”keeping your records accurate and personal. -Edit Location Modal -::: - -::: details 🌍 **Countries & Regions Explorer** -Explore and manage the countries you’ve visited or plan to visit with an organized list, filtering by visit status. Dive deeper into each country’s regions, complete with interactive maps to help you visually select and track your regional travels. -Countries List -Regions Explorer -::: - -## πŸ’¬ What People Are Saying - -::: details ✈️ **XDA Travel Week Reviews** - -> β€œI stumbled upon AdventureLog. It's an open-source, self-hosted travel planner that's completely free to use and has a bunch of cool features that make it a treat to plan, organize, and log your journey across the world. Safe to say, it's become a mainstay in Docker for me.” -> -> β€” _Sumukh Rao, Senior Author at XDA_ - -[Article Link](https://www.xda-developers.com/i-self-hosted-this-app-to-plan-itinerary-when-traveling/) - -::: - -::: details 🧳 **Rich Edmonds, XDA** - -**Overall Ranking: #1** - -> β€œThe most important part of travelling in this socially connected world is to log everything and showcase all of your adventures. AdventureLog is aptly named, as it allows you to do just that. It just so happens to be one of the best apps for the job and can be fully self-hosted at home.” -> -> β€” _Rich Edmonds, Lead PC Hardware Editor at XDA_ - -[Article Link](https://www.xda-developers.com/these-self-hosted-apps-are-perfect-for-those-on-the-go/) - -::: - -::: details πŸ“† **Open Source Daily** - -> β€œYour travel memories are your personal treasuresβ€”don’t let them be held hostage by closed platforms, hidden fees, or privacy risks. AdventureLog represents a new era of travel tracking: open, private, comprehensive, and truly yours. Whether you’re a casual traveler, digital nomad, family vacation planner, or anyone who values their adventures, AdventureLog offers a compelling alternative that puts you back in control.” -> -> β€” _Open Source Daily_ - -[Article Link](https://opensourcedaily.blog/adventurelog-private-open-source-travel-tracking-trip-planning/) - -::: - -::: details πŸ“± **Android Authority** - -> "AdventureLog behaves more like a super-charged travel journal than yet another travel app.” -> -> β€” _Dhruv Bhutani, Android Authority_ - -[Article Link](https://www.androidauthority.com/self-hosted-travel-app-3572353/) - -::: - -## πŸ—οΈ Built With Excellence - -
- -
- -### **Frontend Excellence** - -- 🎨 **SvelteKit** - Lightning-fast, modern web framework -- πŸ’¨ **TailwindCSS** - Utility-first styling for beautiful designs -- 🎭 **DaisyUI** - Beautiful, accessible component library -- πŸ—ΊοΈ **MapLibre** - Interactive, customizable mapping - -
- -
- -### **Backend Power** - -- 🐍 **Django** - Robust, scalable web framework -- πŸ—ΊοΈ **PostGIS** - Advanced geospatial database capabilities -- πŸ”Œ **Django REST** - Modern API architecture -- πŸ” **AllAuth** - Comprehensive authentication system - -
- -
- -## 🌟 Join the Adventure - -
- -
- -### 🎯 **Active Development** - -Regular updates, new features, and community-driven improvements keep AdventureLog at the forefront of travel technology. - -
- -
- -### πŸ’¬ **Thriving Community** - -Join thousands of travelers sharing tips, contributing code, and building the future of travel documentation together. - -
- -
- -### πŸš€ **Open Source Freedom** - -GPL 3.0 licensed, fully transparent, and built for the community. By travelers, for travelers. - -
- -
- -## πŸ’– Support the Project - -AdventureLog is lovingly maintained by passionate developers and supported by amazing users like you: - -- ⭐ [Star us on GitHub](https://github.com/seanmorley15/AdventureLog) -- πŸ’¬ [Join our Discord community](https://discord.gg/wRbQ9Egr8C) -- πŸ’– [Sponsor The Project](https://seanmorley.com/sponsor) to help us keep improving AdventureLog -- πŸ› [Report bugs & request features](https://github.com/seanmorley15/AdventureLog/issues) - ---- - - - - + diff --git a/documentation/public/robots.txt b/documentation/public/robots.txt new file mode 100644 index 00000000..d63c6acb --- /dev/null +++ b/documentation/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://adventurelog.app/sitemap.xml