Technical Architecture - ayothedoc3/Nordic-Explorer GitHub Wiki
π οΈ Technical Architecture
System Overview
Nordic Explorer is built as a modern, scalable web application using Streamlit framework with a focus on performance, multilingual support, and user experience optimization for adventure travel planning.
ποΈ Architecture Diagram
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Frontend β β Backend β β Data Layer β
β (Streamlit) βββββΊβ (Python) βββββΊβ (Pandas) β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β UI Components β β API Services β β File Storage β
β CSS Styling β β Session Mgmt β β Cache Layer β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
π₯οΈ Frontend Architecture
Streamlit Framework
# Main application structure
import streamlit as st
import pandas as pd
import plotly.express as px
# Page configuration
st.set_page_config(
page_title="Nordic Explorer",
page_icon="ποΈ",
layout="wide",
initial_sidebar_state="expanded"
)
Component Structure
nordic_explorer.py
βββ Language System
β βββ Multi-language dictionary
β βββ Dynamic text rendering
β βββ RTL support preparation
βββ Navigation System
β βββ Sidebar navigation
β βββ Page routing
β βββ State management
βββ Core Pages
β βββ Home Dashboard
β βββ Trip Planner
β βββ Adventure Catalog
β βββ Accommodation Booking
β βββ Analytics Dashboard
βββ Utility Functions
βββ Data processing
βββ Chart generation
βββ User interaction handlers
Custom CSS Integration
/* Nordic Theme Variables */
:root {
--nordic-blue: #2E86AB;
--aurora-purple: #A23B72;
--ice-white: #F8F9FA;
--forest-green: #4ECDC4;
--deep-grey: #333333;
}
/* Responsive Design */
@media (max-width: 768px) {
.main-header { font-size: 2.5rem; }
.adventure-card { margin: 0.5rem 0; }
}
π§ Backend Services
Session Management
# Streamlit session state management
if 'user_preferences' not in st.session_state:
st.session_state.user_preferences = {
'language': 'en',
'currency': 'EUR',
'trip_data': {},
'booking_cart': []
}
Data Processing Pipeline
def process_adventure_data():
"""
Adventure data processing workflow
"""
# Load adventure catalog
adventures_df = load_adventure_catalog()
# Apply filters and sorting
filtered_adventures = apply_user_filters(adventures_df)
# Calculate recommendations
recommendations = generate_recommendations(filtered_adventures)
return recommendations
API Integration Architecture
# Weather API integration
async def get_weather_data(location: str) -> dict:
"""
Fetch real-time weather data for adventure planning
"""
weather_api_key = os.getenv('WEATHER_API_KEY')
# Implementation details...
# Booking API integration
async def process_booking(booking_data: dict) -> dict:
"""
Process adventure booking through partner APIs
"""
booking_response = await booking_api.create_reservation(booking_data)
return booking_response
π Data Architecture
Data Models
# Adventure data model
class Adventure:
id: str
name: str
category: str
difficulty: str
duration: int
price: float
location: str
coordinates: tuple
rating: float
description: str
includes: list
requirements: list
# Accommodation data model
class Accommodation:
id: str
name: str
type: str # hotel, cabin, ice_hotel, treehouse
location: str
price_per_night: float
amenities: list
rating: float
availability: dict
unique_features: list
Database Schema (Conceptual)
-- Adventures table
CREATE TABLE adventures (
id VARCHAR(50) PRIMARY KEY,
name VARCHAR(200) NOT NULL,
category VARCHAR(50),
difficulty ENUM('Easy', 'Moderate', 'Challenging', 'Expert'),
duration INT, -- in hours
price DECIMAL(10,2),
location VARCHAR(100),
latitude DECIMAL(10,8),
longitude DECIMAL(11,8),
rating DECIMAL(3,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Bookings table
CREATE TABLE bookings (
id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50),
adventure_id VARCHAR(50),
booking_date DATE,
participants INT,
total_cost DECIMAL(10,2),
status ENUM('pending', 'confirmed', 'cancelled'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (adventure_id) REFERENCES adventures(id)
);
π Internationalization (i18n)
Language Support Implementation
# Language dictionary structure
languages = {
"en": {
"title": "Nordic Explorer",
"subtitle": "Discover Nordic Adventures",
"navigation": {
"home": "Home",
"planner": "Trip Planner",
"adventures": "Adventures",
"accommodations": "Stays"
}
},
"sv": {
"title": "Nordic Explorer",
"subtitle": "UpptΓ€ck nordiska Γ€ventyr",
"navigation": {
"home": "Hem",
"planner": "Reseplanerare",
"adventures": "Γventyr",
"accommodations": "Boende"
}
}
}
Dynamic Text Rendering
def get_text(key: str, lang: str = "en") -> str:
"""
Retrieve localized text based on language selection
"""
keys = key.split('.')
text_dict = languages.get(lang, languages["en"])
for k in keys:
text_dict = text_dict.get(k, key)
return text_dict if isinstance(text_dict, str) else key
π± Mobile Optimization
Responsive Design Strategy
/* Mobile-first approach */
.container {
width: 100%;
padding: 0 1rem;
}
@media (min-width: 768px) {
.container {
max-width: 750px;
margin: 0 auto;
}
}
@media (min-width: 1200px) {
.container {
max-width: 1140px;
}
}
Touch-Friendly Interactions
# Streamlit mobile optimizations
def create_mobile_friendly_filters():
"""
Create touch-friendly filter interface
"""
with st.expander("π Adventure Filters", expanded=False):
difficulty = st.selectbox("Difficulty Level", options)
category = st.multiselect("Activity Type", categories)
price_range = st.slider("Price Range (EUR)", 50, 500, (100, 300))
return difficulty, category, price_range
π Security Implementation
Data Validation
import re
from typing import Union
def validate_email(email: str) -> bool:
"""Validate email format"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
def sanitize_input(user_input: str) -> str:
"""Sanitize user input to prevent XSS"""
# Remove potentially dangerous characters
sanitized = re.sub(r'[<>"\']', '', user_input)
return sanitized.strip()
Session Security
def generate_session_token() -> str:
"""Generate secure session token"""
import secrets
return secrets.token_urlsafe(32)
def validate_session(token: str) -> bool:
"""Validate session token"""
# Implementation for session validation
return True # Placeholder
π Performance Optimization
Caching Strategy
@st.cache_data(ttl=3600) # Cache for 1 hour
def load_adventure_catalog():
"""Load and cache adventure data"""
# Expensive data loading operation
return pd.read_csv('adventures.csv')
@st.cache_data(ttl=1800) # Cache for 30 minutes
def generate_weather_data(location: str):
"""Cache weather data to reduce API calls"""
# Weather API call
return weather_data
Lazy Loading Implementation
def lazy_load_images():
"""Implement lazy loading for adventure images"""
placeholder = st.empty()
if st.button("Load More Adventures"):
with placeholder.container():
for adventure in next_batch_adventures:
display_adventure_card(adventure)
π API Integrations
External Service Integration
class WeatherService:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.openweathermap.org/data/2.5"
async def get_forecast(self, lat: float, lon: float) -> dict:
"""Get weather forecast for adventure location"""
# API implementation
pass
class BookingService:
def __init__(self, partner_api_key: str):
self.api_key = partner_api_key
async def check_availability(self, adventure_id: str, date: str) -> bool:
"""Check real-time availability"""
# Booking API implementation
pass
Error Handling
def handle_api_error(func):
"""Decorator for API error handling"""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except requests.RequestException as e:
st.error(f"Service temporarily unavailable: {str(e)}")
return None
except Exception as e:
st.error(f"An unexpected error occurred: {str(e)}")
return None
return wrapper
π Deployment Architecture
Streamlit Cloud Configuration
# .streamlit/config.toml
[server]
port = 8501
enableCORS = false
enableXsrfProtection = false
maxUploadSize = 50
[browser]
gatherUsageStats = false
serverAddress = "0.0.0.0"
[theme]
primaryColor = "#2E86AB"
backgroundColor = "#F8F9FA"
secondaryBackgroundColor = "#FFFFFF"
textColor = "#333333"
font = "sans serif"
CI/CD Pipeline
# .github/workflows/deploy.yml
name: Deploy to Streamlit Cloud
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Run tests
run: |
python -m pytest tests/
π Monitoring & Analytics
Performance Metrics
import time
from functools import wraps
def monitor_performance(func):
"""Monitor function execution time"""
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
execution_time = time.time() - start_time
# Log performance metrics
st.sidebar.metric("Page Load Time", f"{execution_time:.2f}s")
return result
return wrapper
User Analytics
def track_user_interaction(action: str, details: dict = None):
"""Track user interactions for analytics"""
analytics_data = {
'timestamp': datetime.now(),
'action': action,
'details': details or {},
'session_id': st.session_state.get('session_id'),
'user_agent': st.context.headers.get('User-Agent', 'Unknown')
}
# Send to analytics service
# analytics_service.track(analytics_data)
π§ͺ Testing Strategy
Unit Testing
import pytest
import pandas as pd
from nordic_explorer import process_adventure_data, filter_by_difficulty
def test_adventure_data_processing():
"""Test adventure data processing function"""
# Mock data
test_data = pd.DataFrame({
'name': ['Ice Climbing', 'Northern Lights'],
'difficulty': ['Expert', 'Easy'],
'price': [299, 89]
})
result = process_adventure_data(test_data)
assert len(result) == 2
assert result['name'].iloc[0] == 'Ice Climbing'
def test_difficulty_filter():
"""Test difficulty filtering"""
adventures = create_test_adventures()
filtered = filter_by_difficulty(adventures, 'Easy')
assert all(adv['difficulty'] == 'Easy' for adv in filtered)
Integration Testing
def test_booking_workflow():
"""Test complete booking workflow"""
# Test data
booking_data = {
'adventure_id': 'ice-climbing-001',
'participants': 2,
'date': '2025-02-15'
}
# Test booking process
result = process_booking(booking_data)
assert result['status'] == 'confirmed'
assert result['total_cost'] > 0
π Related Documentation: