Skip to main content

Architecture Overview

Roadtrip Planner follows modern Rails conventions with a component-based frontend architecture, emphasizing maintainability, testability, and performance.

High-Level Architecture

graph TB
subgraph "Client Layer"
Browser[Web Browser]
Mobile[Mobile Browser]
end

subgraph "Application Layer"
LB[Load Balancer]
Rails[Rails 8 Application]
BG[Background Jobs]
end

subgraph "Data Layer"
DB[(PostgreSQL 17)]
Cache[(Solid Cache)]
Files[File Storage]
end

subgraph "External Services"
Maps[Mapping APIs]
Email[Email Service]
end

Browser --> LB
Mobile --> LB
LB --> Rails
Rails --> DB
Rails --> Cache
Rails --> Files
Rails --> BG
BG --> DB
Rails --> Maps
Rails --> Email

Application Structure

Rails 8 Architecture

The application leverages Rails 8's modern architecture:

  • Solid Stack: Database-backed solutions for caching, queuing, and real-time features
  • Propshaft: Modern asset pipeline for optimized delivery
  • Component-Based Views: Phlex components instead of traditional ERB
  • Hotwire: Turbo and Stimulus for SPA-like experience

Directory Organization

app/
├── components/ # Phlex view components
│ ├── application_component.rb
│ ├── layouts/ # Layout components
│ ├── shared/ # Reusable components
│ └── features/ # Feature-specific components
├── controllers/ # Rails controllers
├── models/ # ActiveRecord models
├── services/ # Business logic services
├── jobs/ # Background jobs
├── mailers/ # Email templates
├── javascript/ # Stimulus controllers
└── assets/ # Stylesheets and images

Architectural Patterns

1. Component-Driven Development

Phlex Components replace traditional Rails views:

class ButtonComponent < ApplicationComponent
def initialize(text:, variant: :primary, **options)
@text = text
@variant = variant
@options = options
end

def view_template
button(**attributes) { @text }
end

private

def attributes
{
class: button_classes,
**@options
}
end

def button_classes
case @variant
when :primary
"bg-primary-600 text-white hover:bg-primary-700"
when :secondary
"bg-gray-200 text-gray-900 hover:bg-gray-300"
end
end
end

Benefits:

  • Type safety and IDE support
  • Reusable, testable components
  • Clear separation of concerns
  • Ruby-native templating

2. Service Objects Pattern

Business logic is extracted into service objects:

class RouteDistanceCalculator
def initialize(start_location, end_location)
@start_location = start_location
@end_location = end_location
end

def calculate
{
distance: calculated_distance,
duration: calculated_duration
}
end

private

def calculated_distance
# Distance calculation logic
end

def calculated_duration
# Duration calculation logic
end
end

Benefits:

  • Single responsibility principle
  • Testable business logic
  • Reusable across controllers/jobs
  • Clear interfaces

3. Domain-Driven Design

Models represent clear business domains:

  • User: Authentication and user management
  • RoadTrip: Trip planning and organization
  • Route: Individual trip segments
class RoadTrip < ApplicationRecord
belongs_to :user
has_many :routes, dependent: :destroy

validates :name, presence: true

def total_distance
routes.sum(&:distance_in_km)
end

def day_count
# Business logic for calculating trip duration
end
end

Data Architecture

Database Design

erDiagram
USERS {
id bigint PK
username string UK
password_digest string
created_at timestamp
updated_at timestamp
}

ROAD_TRIPS {
id bigint PK
user_id bigint FK
name string
description text
created_at timestamp
updated_at timestamp
}

ROUTES {
id bigint PK
road_trip_id bigint FK
user_id bigint FK
starting_location string
destination string
datetime timestamp
distance decimal
duration decimal
created_at timestamp
updated_at timestamp
}

USERS ||--o{ ROAD_TRIPS : owns
USERS ||--o{ ROUTES : creates
ROAD_TRIPS ||--o{ ROUTES : contains

Key Relationships

  • User has many RoadTrips and Routes
  • RoadTrip belongs to User and has many Routes
  • Route belongs to both User and RoadTrip

This design ensures:

  • Data integrity through foreign keys
  • User ownership validation
  • Efficient querying with proper indexes

Frontend Architecture

Component Hierarchy

graph TD
Layout[ApplicationLayout]
Layout --> Nav[Navigation]
Layout --> Main[Main Content]

Main --> Home[HomePage]
Main --> Auth[Authentication Pages]
Main --> Trips[Trip Pages]

Auth --> Login[LoginForm]
Auth --> Register[RegistrationForm]

Trips --> TripList[Trip List]
Trips --> TripForm[Trip Form]
Trips --> RouteList[Route List]

Styling Architecture

Tailwind CSS v4 with systematic approach:

/* app/assets/stylesheets/application.tailwind.css */
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

/* Custom component styles */
@layer components {
.btn-primary {
@apply bg-primary-600 text-white px-4 py-2 rounded hover:bg-primary-700;
}
}

Benefits:

  • Utility-first approach
  • Consistent design system
  • Responsive by default
  • Easy customization

JavaScript Architecture

Stimulus Controllers for progressive enhancement:

// app/javascript/controllers/form_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["output"]

connect() {
// Initialize form behavior
}

submit(event) {
// Handle form submission
}
}

Security Architecture

Authentication Flow

sequenceDiagram
participant User
participant App
participant Session
participant DB

User->>App: Login Request
App->>DB: Validate Credentials
DB-->>App: User Data
App->>Session: Create Session
Session-->>App: Session ID
App-->>User: Set Session Cookie

User->>App: Authenticated Request
App->>Session: Validate Session
Session-->>App: User ID
App->>DB: Fetch User Data
DB-->>App: User Object
App-->>User: Authorized Response

Security Measures

  • Password Hashing: bcrypt with secure defaults
  • Session Management: Rails secure sessions
  • CSRF Protection: Built-in Rails protection
  • SQL Injection Prevention: ActiveRecord parameterized queries
  • XSS Prevention: Automatic output escaping in Phlex

Performance Architecture

Caching Strategy

Solid Cache for application-level caching:

# Fragment caching in components
class TripListComponent < ApplicationComponent
def view_template
cache [@user, :trips, @user.road_trips.maximum(:updated_at)] do
render_trips
end
end
end

Background Processing

Solid Queue for asynchronous tasks:

class GpxExportJob < ApplicationJob
queue_as :default

def perform(route_id)
route = Route.find(route_id)
RouteGpxExporter.new(route).export
end
end

Deployment Architecture

Container Strategy

# Multi-stage build for optimization
FROM ruby:3.4-slim as base
# Dependencies and setup

FROM base as development
# Development dependencies

FROM base as production
# Production optimizations

Infrastructure Components

  • Application Server: Puma with multiple workers
  • Database: PostgreSQL with connection pooling
  • Asset Delivery: CDN-ready with Propshaft
  • Monitoring: Built-in Rails instrumentation

Testing Architecture

Test Strategy

spec/
├── models/ # Unit tests for models
├── services/ # Unit tests for services
├── components/ # Component testing
├── requests/ # Integration tests
├── system/ # End-to-end tests
└── factories/ # Test data factories

Testing Pyramid

  • Unit Tests: Models, services, components
  • Integration Tests: Controller/request specs
  • System Tests: Full user workflows
  • Static Analysis: RuboCop, Brakeman

Scalability Considerations

Horizontal Scaling

  • Stateless Application: Session data in cookies/database
  • Database Connection Pooling: Efficient resource usage
  • Background Job Processing: Async task distribution
  • Asset Optimization: CDN-ready static assets

Performance Monitoring

  • Application Metrics: Built-in Rails instrumentation
  • Database Monitoring: Query performance tracking
  • Error Tracking: Exception monitoring
  • User Experience: Real User Monitoring (RUM)

Future Architecture Goals

Planned Improvements

  • API Development: RESTful API for mobile applications
  • Real-time Features: WebSocket integration for collaborative planning
  • Microservices: Extract mapping services for independent scaling
  • Mobile App: Native mobile application with API backend

This architecture provides a solid foundation for current needs while maintaining flexibility for future growth and feature additions.