Skip to content

hashimminhas/Earth-Scanner

Repository files navigation

EarthScanner - Sustainable Travel Booking Platform

A comprehensive travel booking platform focused on sustainable transportation options

Built with Phoenix LiveView & Elixir

Team 12: Mohoshena Ahkter, Hashim Ali, Jamal Muradov, Tobias Rothe


πŸ“– Table of Contents


🌍 About the Project

EarthScanner is a modern web application designed to help travelers find and book sustainable transportation options across Europe. The platform connects travelers with eco-friendly trip options while providing comprehensive tools for trip management, search functionality, and personalized recommendations.

Project Goals

  • Sustainability Focus: Help users make environmentally conscious travel decisions by displaying CO2 emissions for each trip
  • User Experience: Provide intuitive search, filtering, and booking capabilities with real-time updates
  • Admin Efficiency: Enable admins to easily manage trips, track performance metrics, and monitor bookings
  • Personalization: Offer personalized recommendations, search history, and favorite routes

What Makes It Unique

  • Real-time trip availability and booking management
  • Smart recommendation engine (fastest, cheapest, least polluting)
  • Comprehensive search history tracking
  • Similar trip suggestions
  • Performance analytics for administrators
  • Role-based access control (Admin/User)

✨ Key Features

For Users

πŸ” Smart Search & Filtering

  • Search trips by source/destination city
  • Filter by transport type (plane, bus, train)
  • Filter by maximum CO2 emissions
  • View only future trips
  • Access last 5 search queries for quick repeat searches

πŸ’‘ Intelligent Recommendations

  • Fastest Trip: Shortest travel duration
  • Cheapest Trip: Best price option
  • Least Polluting: Lowest CO2 emissions
  • Highlighted section above search results

🎫 Booking Management

  • Real-time seat availability
  • Instant booking confirmation
  • View all active and past bookings
  • Cancel bookings for future trips
  • Automatic booking status updates (active β†’ completed)

⭐ Personalization Features

  • Save favorite routes for quick access
  • Rate completed trips (1-5 stars)
  • View trip ratings from other users
  • Search history automatically saved
  • Similar trip suggestions on trip detail pages

πŸ‘€ Account Management

  • Secure user registration and authentication
  • Password hashing with PBKDF2
  • Update profile information
  • Change password securely
  • Delete account with data cleanup

For Administrators

πŸš€ Trip Management

  • Create new trips with multiple dates
  • Upload trip images
  • Edit trip details and pricing
  • Delete trips (with confirmation)
  • Bulk date management

πŸ“Š Performance Analytics

  • Total bookings per trip
  • Revenue tracking
  • Seat occupancy rates
  • Past vs. Future trip filtering
  • Comprehensive trip dashboards

🎯 Admin Dashboard

  • View all trips at a glance
  • Filter by time (all, future, past)
  • Quick access to trip details
  • Performance metrics visualization

πŸ›  Technology Stack

Backend

  • Elixir 1.15+: Functional programming language for scalability
  • Phoenix 1.8: Modern web framework
  • Phoenix LiveView: Real-time, server-rendered UI updates
  • Ecto: Database wrapper and query generator
  • PostgreSQL 17: Relational database

Frontend

  • Phoenix LiveView: Server-rendered reactive components
  • Tailwind CSS 4.0: Utility-first styling
  • Heroicons: Beautiful SVG icons
  • Alpine.js (via Phoenix hooks): Lightweight JavaScript

Authentication & Security

  • Guardian: JWT-based authentication
  • Pbkdf2: Password hashing
  • CSRF Protection: Built-in Phoenix security

Development Tools

  • Credo: Static code analysis
  • ExUnit: Unit testing framework
  • White Bread: BDD testing with Gherkin
  • Hound: Browser automation for integration tests
  • Docker: Containerized development environment

DevOps

  • Mix: Build tool and task runner
  • esbuild: JavaScript bundler
  • Docker Compose: Local development orchestration

πŸ— Architecture

Design Patterns

Phoenix Context Pattern: Business logic is organized into contexts:

  • Accounts: User authentication and management
  • Trips: Trip and trip date management
  • Bookings: Booking lifecycle and cancellations
  • Favorites: User favorite routes
  • TripSearch: Search and filtering logic

LiveView Components: Real-time UI with server-side rendering

  • No need for REST APIs for most interactions
  • WebSocket-based state management
  • Automatic DOM diffing and patching

Database Design

  • UUID primary keys for security
  • Enum types for status fields
  • Proper foreign key constraints
  • Cascading deletes where appropriate
  • Unique constraints for data integrity

Key Architectural Decisions

  1. Server-Side Rendering: Phoenix LiveView eliminates the need for a separate frontend framework
  2. Real-Time Updates: WebSocket connections keep UI in sync without polling
  3. Role-Based Authorization: Middleware pipeline for route protection
  4. UTC Timestamps: All dates stored in UTC for consistency
  5. Image Storage: Binary image data stored in database with content type

πŸš€ Getting Started

Prerequisites

  • Elixir 1.15+ and Erlang/OTP 26+
  • PostgreSQL 17 (or use Docker)
  • Node.js 18+ (for asset compilation)
  • Git

Installation

  1. Clone the repository

    git clone https://github.com/yourusername/earthscanner-group12.git
    cd earthscanner-group12
  2. Install dependencies

    mix setup

    This runs:

    • mix deps.get - Install Elixir dependencies
    • mix ecto.setup - Create and migrate database
    • mix assets.setup - Install frontend dependencies
    • mix assets.build - Compile assets
  3. Start PostgreSQL (if using Docker)

    docker-compose up -d
  4. Seed the database (optional)

    mix run priv/repo/seeds.exs
  5. Start the Phoenix server

    mix phx.server
  6. Visit the application

Environment Configuration

Create a .env file or configure the following in config/dev.exs:

config :earthscanner_group12, EarthScannerGroup12.Repo,
  username: "postgres",
  password: "postgres",
  hostname: "localhost",
  database: "earthscanner_group12_dev",
  port: 5432

πŸ’» Development Workflow

Running the Application

# Start with live reload
mix phx.server

# Start with IEx console
iex -S mix phx.server

Database Commands

# Create database
mix ecto.create

# Run migrations
mix ecto.migrate

# Rollback migration
mix ecto.rollback

# Reset database
mix ecto.reset

# Seed data
mix run priv/repo/seeds.exs

Code Quality

# Run pre-commit checks (recommended before committing)
mix precommit

This runs:

  • Compilation with warnings as errors
  • Dependency cleanup
  • Code formatting
  • All tests
# Format code
mix format

# Run Credo linter
mix credo

# Check for unused dependencies
mix deps.unlock --unused

πŸ§ͺ Testing

Test Suite

The project uses multiple testing approaches:

  1. Unit Tests: ExUnit for context and schema testing
  2. Integration Tests: Controller and LiveView testing
  3. BDD Tests: White Bread with Gherkin feature files

Running Tests

# Run all tests
mix test

# Run specific test file
mix test test/earthscanner_group12/trips_test.exs

# Run tests with coverage
mix test --cover

# Run BDD feature tests
mix white_bread.run

# Run failed tests only
mix test --failed

# Run tests in watch mode (requires external tool)
mix test.watch

Test Structure

test/
β”œβ”€β”€ earthscanner_group12/        # Context tests
β”‚   β”œβ”€β”€ accounts_test.exs
β”‚   β”œβ”€β”€ bookings_test.exs
β”‚   β”œβ”€β”€ trips_test.exs
β”‚   └── ...
β”œβ”€β”€ earthscanner_group12_web/    # Controller/LiveView tests
β”‚   └── controllers/
β”œβ”€β”€ features/                     # BDD feature tests
β”‚   β”œβ”€β”€ booking_test.exs
β”‚   β”œβ”€β”€ trips_search_test.exs
β”‚   └── ...
└── support/                      # Test helpers
    β”œβ”€β”€ conn_case.ex
    β”œβ”€β”€ data_case.ex
    └── fixtures/

Writing Tests

Unit Test Example:

test "creates booking with valid data" do
  user = user_fixture()
  trip_date = trip_date_fixture()
  
  assert {:ok, booking} = Bookings.create_booking(user, trip_date)
  assert booking.status == :active
end

BDD Feature Example:

Feature: Trip search
  Scenario: User searches for trips
    Given I am logged in as a user
    When I search for trips with city "Tallinn"
    Then I should see text "Tallinn"
    And I should see text "Trips found: 1"

🚒 Deployment

Production Server

The application is deployed to a production server with the following setup:

  • Server: Ubuntu Linux
  • IP: 193.40.11.123
  • Application Path: /home/ubuntu/earthscanner_group12
  • Process Manager: systemd
  • Web Server: Cowboy (built-in)

Deployment Process

  1. Automated deployment script:

    ./scripts/deploy.sh
  2. Manual deployment:

    # Build release
    MIX_ENV=prod mix release
    
    # Copy to server
    scp -r _build/prod/rel/earthscanner_group12 user@server:/path/
    
    # Start application
    /path/earthscanner_group12/bin/earthscanner_group12 start
  3. Database migrations on production:

    /path/bin/earthscanner_group12 eval "EarthScannerGroup12.Release.migrate()"

Environment Variables

Set the following in production:

export DATABASE_URL="ecto://user:pass@localhost/db"
export SECRET_KEY_BASE="your-secret-key"
export PHX_HOST="yourdomain.com"
export PORT=4000

For detailed deployment instructions, see DEPLOYMENT.md.


πŸ“ Project Structure

earthscanner-group12-main/
β”œβ”€β”€ assets/                      # Frontend assets
β”‚   β”œβ”€β”€ css/                    # Stylesheets
β”‚   β”‚   └── app.css            # Main CSS with Tailwind
β”‚   β”œβ”€β”€ js/                     # JavaScript
β”‚   β”‚   └── app.js             # Main JS entry point
β”‚   └── vendor/                 # Third-party assets
β”‚
β”œβ”€β”€ config/                      # Configuration files
β”‚   β”œβ”€β”€ config.exs              # Base configuration
β”‚   β”œβ”€β”€ dev.exs                 # Development config
β”‚   β”œβ”€β”€ prod.exs                # Production config
β”‚   β”œβ”€β”€ runtime.exs             # Runtime configuration
β”‚   └── test.exs                # Test configuration
β”‚
β”œβ”€β”€ docs/                        # Documentation
β”‚   └── diagrams/
β”‚       └── erd.puml            # Entity relationship diagram
β”‚
β”œβ”€β”€ features/                    # BDD feature files (Gherkin)
β”‚   β”œβ”€β”€ booking.feature
β”‚   β”œβ”€β”€ trips.feature
β”‚   β”œβ”€β”€ trip_search.feature
β”‚   β”œβ”€β”€ favorites.feature
β”‚   β”œβ”€β”€ ratings.feature
β”‚   └── ... (20+ feature files)
β”‚
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ earthscanner_group12/          # Core business logic
β”‚   β”‚   β”œβ”€β”€ accounts/                  # User management
β”‚   β”‚   β”‚   β”œβ”€β”€ user.ex
β”‚   β”‚   β”‚   └── password.ex
β”‚   β”‚   β”œβ”€β”€ auth/                      # Authentication
β”‚   β”‚   β”‚   └── auth_pipeline.ex
β”‚   β”‚   β”œβ”€β”€ bookings/                  # Booking management
β”‚   β”‚   β”‚   └── booking.ex
β”‚   β”‚   β”œβ”€β”€ favorites/                 # Favorites management
β”‚   β”‚   β”‚   └── favorite.ex
β”‚   β”‚   β”œβ”€β”€ trips/                     # Trip management
β”‚   β”‚   β”‚   β”œβ”€β”€ trip.ex
β”‚   β”‚   β”‚   β”œβ”€β”€ trip_date.ex
β”‚   β”‚   β”‚   β”œβ”€β”€ trips.ex
β”‚   β”‚   β”‚   β”œβ”€β”€ rating.ex
β”‚   β”‚   β”‚   └── trip_search.ex
β”‚   β”‚   β”œβ”€β”€ accounts.ex                # Accounts context
β”‚   β”‚   β”œβ”€β”€ bookings.ex                # Bookings context
β”‚   β”‚   β”œβ”€β”€ favorites.ex               # Favorites context
β”‚   β”‚   β”œβ”€β”€ application.ex             # OTP application
β”‚   β”‚   β”œβ”€β”€ repo.ex                    # Database repository
β”‚   β”‚   └── mailer.ex                  # Email functionality
β”‚   β”‚
β”‚   └── earthscanner_group12_web/      # Web interface
β”‚       β”œβ”€β”€ controllers/               # HTTP controllers
β”‚       β”‚   β”œβ”€β”€ session_controller.ex
β”‚       β”‚   β”œβ”€β”€ user_controller.ex
β”‚       β”‚   β”œβ”€β”€ trip_controller.ex
β”‚       β”‚   β”œβ”€β”€ booking_controller.ex
β”‚       β”‚   └── ...
β”‚       β”œβ”€β”€ live/                      # LiveView modules
β”‚       β”‚   β”œβ”€β”€ trips_live.ex
β”‚       β”‚   β”œβ”€β”€ admin_trips_live.ex
β”‚       β”‚   β”œβ”€β”€ bookings_live.ex
β”‚       β”‚   └── ...
β”‚       β”œβ”€β”€ components/                # Reusable components
β”‚       β”‚   └── core_components.ex
β”‚       β”œβ”€β”€ plugs/                     # Custom plugs
β”‚       β”œβ”€β”€ endpoint.ex                # Phoenix endpoint
β”‚       β”œβ”€β”€ router.ex                  # Route definitions
β”‚       └── gettext.ex                 # Internationalization
β”‚
β”œβ”€β”€ priv/
β”‚   β”œβ”€β”€ repo/
β”‚   β”‚   β”œβ”€β”€ migrations/                # Database migrations
β”‚   β”‚   └── seeds.exs                  # Seed data
β”‚   β”œβ”€β”€ static/                        # Static files
β”‚   └── gettext/                       # Translations
β”‚
β”œβ”€β”€ test/                              # Test suite
β”‚   β”œβ”€β”€ earthscanner_group12/         # Context tests
β”‚   β”œβ”€β”€ earthscanner_group12_web/     # Web tests
β”‚   β”œβ”€β”€ features/                      # BDD tests
β”‚   └── support/                       # Test helpers
β”‚
β”œβ”€β”€ scripts/                           # Deployment scripts
β”‚   β”œβ”€β”€ deploy.sh
β”‚   β”œβ”€β”€ setup_server.sh
β”‚   └── earthscanner_group12.service
β”‚
β”œβ”€β”€ mix.exs                            # Project configuration
β”œβ”€β”€ docker-compose.yml                 # Docker setup
β”œβ”€β”€ README.md                          # This file
β”œβ”€β”€ DEPLOYMENT.md                      # Deployment guide
└── AGENTS.md                          # AI coding guidelines

πŸ—„ Database Schema

Core Entities

Users

- id (UUID, PK)
- username (string, unique)
- email (string, unique)
- password_hash (string)
- phone_number (string)
- role (enum: admin, user)
- first_name, last_name (string)
- birthdate (date)
- nationality (string)
- residence_address (string)
- timestamps

Trips

- id (UUID, PK)
- admin_id (UUID, FK β†’ users)
- transport_type (enum: plane, bus, train)
- source_city (string)
- destination_city (string)
- duration (interval)
- price (decimal)
- co2_pollution (decimal)
- available_tickets (integer)
- departure_time (utc_datetime)
- arrival_time (utc_datetime)
- image (binary)
- image_content_type (string)
- timestamps

Trip Dates

- id (UUID, PK)
- trip_id (UUID, FK β†’ trips, cascade delete)
- seats_total (integer)
- seats_available (integer)
- departure_datetime (utc_datetime)
- arrival_datetime (utc_datetime)
- travel_date (date)
- active (boolean)
- timestamps

Bookings

- id (UUID, PK)
- user_id (UUID, FK β†’ users, cascade delete)
- trip_date_id (UUID, FK β†’ trip_dates, cascade delete)
- status (enum: active, completed, cancelled_by_user, cancelled_by_admin)
- price_paid_cents (integer)
- returned_at (utc_datetime)
- timestamps

UNIQUE CONSTRAINT: user_id + trip_date_id (for active bookings)

Favorites

- id (UUID, PK)
- user_id (UUID, FK β†’ users, cascade delete)
- trip_id (UUID, FK β†’ trips, cascade delete)
- timestamps

UNIQUE CONSTRAINT: user_id + trip_id

Trip Ratings

- id (UUID, PK)
- user_id (UUID, FK β†’ users, cascade delete)
- trip_id (UUID, FK β†’ trips, cascade delete)
- rating (integer, 1-5)
- timestamps

UNIQUE CONSTRAINT: user_id + trip_id

User Searches

- id (UUID, PK)
- user_id (UUID, FK β†’ users, cascade delete)
- source_city (string)
- destination_city (string)
- search_params (jsonb)
- inserted_at (utc_datetime)

LIMIT: Last 5 searches per user

Relationships

  • One Admin β†’ Many Trips
  • One Trip β†’ Many Trip Dates
  • One Trip Date β†’ Many Bookings
  • One User β†’ Many Bookings
  • One User β†’ Many Favorites
  • One User β†’ Many Ratings
  • One User β†’ Many Searches (max 5)

πŸ›£ API & Routes

Public Routes

GET  /                          # Home page
GET  /sessions/new              # Login page
POST /sessions                  # Login action
GET  /users/new                 # Registration page
POST /users                     # Registration action

Authenticated User Routes

# User Management
GET    /users/me                # Current user profile
GET    /users/:id/edit          # Edit profile
PUT    /users/:id               # Update profile
GET    /users/:id/change_password  # Change password form
PUT    /users/:id/update_password  # Update password
DELETE /users/:id               # Delete account

# Trip Browsing
GET  /tripdates                 # List all available trips
GET  /tripdates/:id             # Trip date details
GET  /trips/:id                 # Trip details (LiveView)
LIVE /trips                     # Browse trips (LiveView)

# Bookings
GET    /bookings/new            # New booking form
POST   /bookings                # Create booking
GET    /bookings/:id            # Booking details
GET    /bookings/:id/cancel     # Cancel booking
LIVE   /bookings                # User bookings list

# Favorites
POST   /favorites               # Add favorite
POST   /favorites/:trip_id      # Add favorite (alt)
DELETE /favorites/:trip_id      # Remove favorite

# Ratings
POST   /ratings                 # Create rating
DELETE /ratings/:id             # Delete rating

Admin Routes

LIVE /admin/trips               # Admin trips dashboard
LIVE /admin/trips/:id           # Admin trip details
LIVE /trips/new                 # Create new trip (LiveView)

# Trip Management
GET    /trips/new               # New trip form
POST   /trips                   # Create trip
GET    /trips/:id/edit          # Edit trip form
PUT    /trips/:id               # Update trip
DELETE /trips/:id               # Delete trip

Authorization Middleware

  • :require_authenticated - Must be logged in
  • :require_user - Must be logged in as regular user
  • :require_admin - Must be logged in as admin
  • :require_no_admin - Must be logged in as non-admin

πŸ‘₯ Contributing

Code Style

  • Follow the Elixir Style Guide
  • Run mix format before committing
  • Run mix credo to check code quality
  • Use descriptive commit messages

Git Workflow

  1. Create a feature branch: git checkout -b feature/my-feature
  2. Make your changes
  3. Run tests: mix test
  4. Run pre-commit checks: mix precommit
  5. Commit: git commit -m "Add my feature"
  6. Push: git push origin feature/my-feature
  7. Create a Pull Request

Adding Features

  1. Write feature tests first (BDD)
  2. Implement the feature
  3. Add unit tests
  4. Update documentation
  5. Run full test suite

πŸ“‹ Diagrams

The docs/diagrams folder contains PlantUML source files for architectural diagrams:

  • erd.puml - Entity Relationship Diagram

Generating Diagrams

Install PlantUML (requires Java 8+):

macOS:

brew install plantuml

Windows:

choco install plantuml

Linux (Ubuntu/Debian):

sudo apt install plantuml graphviz

Generate:

plantuml docs/diagrams/*.puml

πŸ“„ License

This project was developed as part of an academic course assignment. All rights reserved to Team 12.


πŸ™ Acknowledgments

  • Phoenix Framework Team - For the excellent web framework
  • Elixir Community - For the supportive ecosystem
  • TailwindCSS - For the utility-first CSS framework
  • Course Instructors - For guidance and support

πŸ“§ Contact

Team 12

  • Hashim Ali
  • Jamal Muradov
  • Tobias Rothe

For questions or issues, please create an issue in the repository.


Built with ❀️ using Elixir & Phoenix LiveView

Making sustainable travel accessible to everyone

Development Setup

Database

We suggest using Docker:

  1. Make sure the Docker Daemon is running

  2. Setup up postgres database with docker-compose.yml.

    docker compose up -d

You can also setup the postgres database locally.

Core schema migration workflow

  • We keep the canonical database model in docs/diagrams/erd.puml. Any schema change starts there.

  • Generate a migration shell so Ecto registers the timestamped file:

    mix ecto.gen.migration create_earthscanner_core_tables
  • Edit the generated file (e.g. priv/repo/migrations/20251107111215_create_earthscanner_core_tables.exs) to match the ERD. It is normal for the generator to create an empty change/0; we replace it with explicit up/0/down/0 functions that:

    • create the user_role, transport_type, and booking_status enums
    • define all tables (users, trips, trip_dates, bookings, user_searches, favorites, trip_ratings, trip_recommendation)
    • add indexes, constraints, and foreign keys exactly as shown in the ERD

Local Deployment

  • Apply the migration locally:

    mix ecto.migrate
  • Every migration is reviewed before commit to ensure the schema and ERD stay in sync.

Start the Phoenix server

  1. Set the MIX_ENV

    $env:MIX_ENV="dev"
  2. Run mix setup to install and setup dependencies

  3. Start Phoenix endpoint with mix phx.server or inside IEx with iex -S mix phx.server

Now you can visit localhost:4000 from your browser.

Frequent errors

UI shows that there are unapplied migrations

  1. Delete _build/dev/lib/earthscanner_group12/priv/repo/migrations/ directory. This directory remembers migrations that were deleted and wants them to be applied.
  2. Run mix ecto.reset. This should now only build the current migrations to the mentioned directory.
  3. Restart the development server with mix phx.server.

Code quality

The CI in .gitlab-ci.yml checks these automatically.

Format

mix format [--check-formatted]

Lint

mix credo

Test

Unit tests

  1. Set the MIX_ENV

    $env:MIX_ENV="test"
  2. Run the tests

    mix test

BDD tests

  1. Set the MIX_ENV

    $env:MIX_ENV="test"
  2. Compile the dependencies for the test env.

    mix deps.get
    mix deps.compile
    mix compile
  3. Start the chromedriver (follow the lecture notes to install it on your device)

    chromedriver --port=55591
  4. Run all BDD tests

    mix white_bread.run --suite "All"

Frequent errors

If the dependencies don't compile and some Gherkin errors are thrown, this may be caused by misaligned package versions from old dependency installs. Delete your build/ and deps/ directories and restart from step 2.

this is the project repository for EarthScanner - Sustainable Travel Booking Platform

About

Agile-Project

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors