From feafb9d19e2609ac3ec7b5cad38378aa92373b48 Mon Sep 17 00:00:00 2001
From: Yonas Tewabe
Date: Tue, 30 Jun 2026 15:53:48 +0300
Subject: [PATCH 1/9] Update sync-env-from-server-jenkins.sh
---
scripts/deploy/sync-env-from-server-jenkins.sh | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/scripts/deploy/sync-env-from-server-jenkins.sh b/scripts/deploy/sync-env-from-server-jenkins.sh
index 74b9a3f13..e444996d6 100644
--- a/scripts/deploy/sync-env-from-server-jenkins.sh
+++ b/scripts/deploy/sync-env-from-server-jenkins.sh
@@ -12,24 +12,23 @@
# Server layout (one file per service):
# /home/user/environmen///freight-api.env
# /home/user/environmen///freight-portal.env
-
set -euo pipefail
-
DEPLOY_USER="${DEPLOY_USER:-tria}"
BRANCH="${BRANCH:?BRANCH is required}"
BRANCH_SLUG="${BRANCH_SLUG:-$(echo "${BRANCH}" | tr "[:upper:]" "[:lower:]" | sed -E "s/[^a-z0-9]+/-/g; s/^-+//; s/-+$//")}"
ENV_ROOT="${ENV_ROOT:-/home/${DEPLOY_USER}/environment/edr/${BRANCH_SLUG}/${PROJECT:?PROJECT is required}}"
CI_ENV_FILE="${CI_ENV_FILE:?CI_ENV_FILE is required (e.g. \${WORKSPACE}/.ci-env/.env)}"
-
if [[ ! -d "${ENV_ROOT}" ]]; then
echo "Environment directory not found: ${ENV_ROOT}" >&2
exit 1
fi
echo "Using environment directory: ${ENV_ROOT}"
-
mkdir -p "$(dirname "${CI_ENV_FILE}")"
+if [[ -d "${CI_ENV_FILE}" ]]; then
+ echo "Removing stale directory at ${CI_ENV_FILE}" >&2
+ rm -rf "${CI_ENV_FILE}"
+fi
: > "${CI_ENV_FILE}"
-
declare -A SERVICE_ENV_TARGET=(
["freight-api"]="apps/edr-freight-api/.env"
["freight-portal"]="apps/edr-freight-web/portal/.env"
@@ -39,36 +38,29 @@ declare -A SERVICE_ENV_TARGET=(
["passenger-backoffice"]="apps/edr-passenger-web/backoffice/.env"
["payment-api"]="apps/edr-payment-api/.env"
)
-
for service in "$@"; do
src="${ENV_ROOT}/${service}.env"
dest="${SERVICE_ENV_TARGET[${service}]:-}"
-
if [[ -z "${dest}" ]]; then
echo "Unknown service: ${service}" >&2
exit 1
fi
-
if [[ ! -f "${src}" ]]; then
echo "Missing env file: ${src}" >&2
exit 1
fi
-
mkdir -p "$(dirname "${dest}")"
cp "${src}" "${dest}"
echo "Synced ${src} -> ${dest}"
-
port_value=$(sed -n -E 's/^[[:space:]]*PORT[[:space:]]*=[[:space:]]*"?([^"#]+)"?[[:space:]]*(#.*)?$/\1/p' "${src}" | head -n1 | tr -d '[:space:]')
if [[ -z "${port_value}" ]]; then
echo "Missing required PORT in env file: ${src}" >&2
exit 1
fi
-
service_var=$(echo "${service}" | tr '[:lower:]-' '[:upper:]_')
echo "${service_var}_PORT=${port_value}" >> "${CI_ENV_FILE}"
echo "Exported ${service_var}_PORT from ${src}"
-
# Forward NEXT_PUBLIC_* and VITE_* vars so docker compose build can inject them as build args.
grep -E '^[[:space:]]*(NEXT_PUBLIC_|VITE_)[A-Za-z0-9_]+=' "${src}" \
| sed -E 's/^[[:space:]]*//' >> "${CI_ENV_FILE}" || true
-done
\ No newline at end of file
+done
From 1896c8d36c97fb5544606999652e6b585dec46b8 Mon Sep 17 00:00:00 2001
From: SennayT
Date: Tue, 14 Jul 2026 00:15:24 +0300
Subject: [PATCH 2/9] remove skip for now button
---
.../portal/src/app/booking/passengers/page.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx
index 4639bd196..bfbb621ad 100644
--- a/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx
+++ b/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx
@@ -1153,14 +1153,14 @@ function PassengersForm() {
Finish verifying Passenger {(verifyingIndex ?? 0) + 1} first
)}
-
+ */}
) : showManualEntryLink ? (
From 35eb4b37ac5d8edd6824d2f41b95b9c0102144a9 Mon Sep 17 00:00:00 2001
From: yonastewabe
Date: Tue, 14 Jul 2026 09:06:43 +0300
Subject: [PATCH 3/9] feat(seo): Add metadata and SEO improvements to passenger
portal
---
.github/workflows/deploy.yml | 1 -
.../portal/src/app/about/layout.tsx | 21 ++++
.../portal/src/app/contact/layout.tsx | 21 ++++
.../portal/src/app/guide/layout.tsx | 28 ++++++
.../portal/src/app/help/layout.tsx | 23 +++++
.../portal/src/app/layout.tsx | 97 ++++++++++++++++++-
.../portal/src/app/packages/[id]/layout.tsx | 80 +++++++++++++++
.../portal/src/app/packages/layout.tsx | 23 +++++
.../edr-passenger-web/portal/src/app/page.tsx | 17 ++++
.../portal/src/app/robots.ts | 37 +++++++
.../portal/src/app/services/layout.tsx | 23 +++++
.../portal/src/app/sitemap.ts | 59 +++++++++++
.../portal/src/components/JsonLd.tsx | 12 +++
.../portal/src/middleware.ts | 27 ++++--
14 files changed, 459 insertions(+), 10 deletions(-)
create mode 100644 apps/edr-passenger-web/portal/src/app/about/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/contact/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/guide/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/help/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/packages/[id]/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/packages/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/robots.ts
create mode 100644 apps/edr-passenger-web/portal/src/app/services/layout.tsx
create mode 100644 apps/edr-passenger-web/portal/src/app/sitemap.ts
create mode 100644 apps/edr-passenger-web/portal/src/components/JsonLd.tsx
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 057cb0c1b..f0beccd20 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -2,7 +2,6 @@ name: Deploy Stacks
on:
push:
branches:
- - main
- dev
- staging
workflow_dispatch:
diff --git a/apps/edr-passenger-web/portal/src/app/about/layout.tsx b/apps/edr-passenger-web/portal/src/app/about/layout.tsx
new file mode 100644
index 000000000..a7bb1b25d
--- /dev/null
+++ b/apps/edr-passenger-web/portal/src/app/about/layout.tsx
@@ -0,0 +1,21 @@
+import type { Metadata } from 'next';
+
+export const metadata: Metadata = {
+ title: 'About EDR – Connecting East Africa by Rail',
+ description:
+ 'Learn about the Ethio-Djibouti Railway (EDR): our mission to connect Ethiopia and Djibouti with comfortable, affordable, and sustainable train travel.',
+ alternates: {
+ canonical: '/about',
+ },
+ openGraph: {
+ title: 'About EDR – Connecting East Africa by Rail',
+ description:
+ 'Our mission is to provide reliable, affordable, and comfortable train travel connecting Ethiopia and Djibouti.',
+ url: '/about',
+ images: [{ url: '/edr-banner.jpg', width: 1200, height: 630, alt: 'EDR Railway – About Us' }],
+ },
+};
+
+export default function AboutLayout({ children }: { children: React.ReactNode }) {
+ return children;
+}
diff --git a/apps/edr-passenger-web/portal/src/app/contact/layout.tsx b/apps/edr-passenger-web/portal/src/app/contact/layout.tsx
new file mode 100644
index 000000000..3a5c61836
--- /dev/null
+++ b/apps/edr-passenger-web/portal/src/app/contact/layout.tsx
@@ -0,0 +1,21 @@
+import type { Metadata } from 'next';
+
+export const metadata: Metadata = {
+ title: 'Contact EDR – Get in Touch',
+ description:
+ 'Contact the Ethio-Djibouti Railway (EDR) support team. We are available to assist with your train journey.',
+ alternates: {
+ canonical: '/contact',
+ },
+ openGraph: {
+ title: 'Contact EDR – Get in Touch',
+ description:
+ 'Reach the EDR support team by phone, email, or in person. We are available to assist with your train journey.',
+ url: '/contact',
+ images: [{ url: '/edr-banner.jpg', width: 1200, height: 630, alt: 'EDR Railway – Contact Us' }],
+ },
+};
+
+export default function ContactLayout({ children }: { children: React.ReactNode }) {
+ return children;
+}
diff --git a/apps/edr-passenger-web/portal/src/app/guide/layout.tsx b/apps/edr-passenger-web/portal/src/app/guide/layout.tsx
new file mode 100644
index 000000000..417c46cf3
--- /dev/null
+++ b/apps/edr-passenger-web/portal/src/app/guide/layout.tsx
@@ -0,0 +1,28 @@
+import type { Metadata } from 'next';
+
+export const metadata: Metadata = {
+ title: 'How to Book a Train Ticket – EDR Step-by-Step Guide',
+ description:
+ 'Step-by-step guide to booking an EDR train ticket online: search trains, select your seat class, enter passenger details, and complete payment.',
+ alternates: {
+ canonical: '/guide',
+ },
+ openGraph: {
+ title: 'How to Book a Train Ticket – EDR Step-by-Step Guide',
+ description:
+ 'Follow our simple guide to book your EDR train journey in minutes.',
+ url: '/guide',
+ images: [
+ {
+ url: '/edr-banner.jpg',
+ width: 1200,
+ height: 630,
+ alt: 'EDR Railway – How to Book a Train Ticket',
+ },
+ ],
+ },
+};
+
+export default function GuideLayout({ children }: { children: React.ReactNode }) {
+ return children;
+}
diff --git a/apps/edr-passenger-web/portal/src/app/help/layout.tsx b/apps/edr-passenger-web/portal/src/app/help/layout.tsx
new file mode 100644
index 000000000..0211d6d23
--- /dev/null
+++ b/apps/edr-passenger-web/portal/src/app/help/layout.tsx
@@ -0,0 +1,23 @@
+import type { Metadata } from 'next';
+
+export const metadata: Metadata = {
+ title: 'Help & FAQs – EDR Train Booking',
+ description:
+ 'Find answers to common questions about booking EDR train tickets: how to book, passenger pricing, identity verification, seat classes, payment methods, and more.',
+ alternates: {
+ canonical: '/help',
+ },
+ openGraph: {
+ title: 'Help & FAQs – EDR Train Booking',
+ description:
+ 'Answers to your questions about booking EDR train tickets, payment methods, identity verification, and seat selection.',
+ url: '/help',
+ images: [
+ { url: '/edr-banner.jpg', width: 1200, height: 630, alt: 'EDR Railway – Help & FAQs' },
+ ],
+ },
+};
+
+export default function HelpLayout({ children }: { children: React.ReactNode }) {
+ return children;
+}
diff --git a/apps/edr-passenger-web/portal/src/app/layout.tsx b/apps/edr-passenger-web/portal/src/app/layout.tsx
index 1128124e3..a6d5c787f 100644
--- a/apps/edr-passenger-web/portal/src/app/layout.tsx
+++ b/apps/edr-passenger-web/portal/src/app/layout.tsx
@@ -7,10 +7,61 @@ import MobileTopBar from '@/components/MobileTopBar';
import BottomTabBar from '@/components/BottomTabBar';
import { LoadingIndicator } from '@/components/LoadingIndicator';
import SupportWidget from '@/features/support/SupportWidgetLazy';
+import { JsonLd } from '@/components/JsonLd';
+
+const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://passenger.edrsc.com';
export const metadata: Metadata = {
- title: 'EDR Passenger Portal - Book your train journey',
- description: 'Book train tickets on the Ethio-Djibouti Railway',
+ metadataBase: new URL(siteUrl),
+ title: {
+ default: 'EDR Passenger Portal – Book Train Tickets Online',
+ template: '%s | EDR Passenger Portal',
+ },
+ description:
+ 'Book train tickets on the Ethio-Djibouti Railway. Travel between Ethiopia and Djibouti with easy online booking, seat selection, and multiple payment options.',
+ authors: [{ name: 'EDR – Ethio-Djibouti Railway' }],
+ creator: 'EDR – Ethio-Djibouti Railway',
+ publisher: 'EDR – Ethio-Djibouti Railway',
+ robots: {
+ index: true,
+ follow: true,
+ googleBot: {
+ index: true,
+ follow: true,
+ 'max-snippet': -1,
+ 'max-image-preview': 'large',
+ 'max-video-preview': -1,
+ },
+ },
+ openGraph: {
+ type: 'website',
+ locale: 'en_US',
+ url: siteUrl,
+ siteName: 'EDR Passenger Portal',
+ title: 'EDR Passenger Portal – Book Train Tickets Online',
+ description:
+ 'Book train tickets on the Ethio-Djibouti Railway. Comfortable seats, flexible payment options, and easy online booking.',
+ images: [
+ {
+ url: '/edr-banner.jpg',
+ width: 1200,
+ height: 630,
+ alt: 'EDR Ethio-Djibouti Railway – Book your train journey',
+ },
+ ],
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: 'EDR Passenger Portal – Book Train Tickets Online',
+ description:
+ 'Book train tickets on the Ethio-Djibouti Railway. Comfortable seats, flexible payment options, and easy online booking.',
+ images: ['/edr-banner.jpg'],
+ },
+ icons: {
+ icon: '/edr-logo.png',
+ shortcut: '/edr-logo.png',
+ apple: '/edr-logo.png',
+ },
};
export default function RootLayout({
@@ -20,8 +71,48 @@ export default function RootLayout({
}) {
// Nonce set per-request by middleware; required for this inline script under the CSP.
const nonce = headers().get('x-nonce') ?? undefined;
+
+ const organizationSchema = {
+ '@context': 'https://schema.org',
+ '@type': 'Organization',
+ name: 'Ethio-Djibouti Railway (EDR)',
+ url: siteUrl,
+ logo: `${siteUrl}/edr-logo.png`,
+ contactPoint: {
+ '@type': 'ContactPoint',
+ telephone: '9546',
+ contactType: 'customer service',
+ availableLanguage: ['English', 'Amharic'],
+ },
+ address: {
+ '@type': 'PostalAddress',
+ addressLocality: 'Addis Ababa',
+ addressCountry: 'ET',
+ },
+ sameAs: [],
+ };
+
+ const websiteSchema = {
+ '@context': 'https://schema.org',
+ '@type': 'WebSite',
+ name: 'EDR Passenger Portal',
+ url: siteUrl,
+ potentialAction: {
+ '@type': 'SearchAction',
+ target: {
+ '@type': 'EntryPoint',
+ urlTemplate: `${siteUrl}/booking/search?q={search_term_string}`,
+ },
+ 'query-input': 'required name=search_term_string',
+ },
+ };
+
return (
-
+
+
+
+
+