Tuesday, June 10, 2025

Building a Modern Lettings Platform: Why We Chose Rails 8 and TailAdmin

Paul (Founder)
Platform Development
Clean code on a computer screen showing web development

When you're managing dozens—or hundreds—of rental properties, your software needs to do three things brilliantly: load quickly, work reliably, and stay out of your way. For the week of 9–15 June 2025, we focused on building exactly that kind of foundation for a new lettings management platform.

The challenge wasn't just technical. It was about creating a system that letting agents would actually want to use—one that feels modern, responds instantly, and doesn't require a manual to navigate. This article explores the decisions we made during the initial build and what they mean for agencies considering purpose-built software.

What Your Team Will Notice

From the moment staff log in, the interface feels purposeful. The dashboard uses TailAdmin, a professionally designed template built on Tailwind CSS, which means every button, form, and navigation element follows consistent design patterns. There are no jarring layout shifts, no clunky dropdowns, and no hidden features buried in obscure menus.

Everything is responsive by default. Whether your lettings negotiator is checking property details on a desktop in the office or approving maintenance requests on a mobile phone during a viewing, the interface adapts seamlessly. The sidebar navigation collapses intelligently on smaller screens, and forms remain perfectly usable without zooming or horizontal scrolling.

The authentication system uses Devise, a battle-tested Rails library that's been securing user accounts for over a decade. Staff members have individual logins with secure password requirements, and sessions are managed automatically. If someone steps away from their desk, the session times out safely. If they forget their password, the recovery flow is straightforward and secure.

Behind the scenes, the system runs on Rails 8, the latest major release of Ruby on Rails. This isn't just about having the newest version—it's about benefiting from years of refinement in areas like database query performance, background job processing, and security patches. Rails has powered platforms like Shopify, GitHub, and Basecamp for years because it's designed to scale gracefully as requirements grow.

Under the Bonnet: Technical Decisions That Matter

The initial commit established the Rails application with carefully chosen defaults. We configured Tailwind CSS for styling, which generates only the CSS classes actually used in the application, resulting in remarkably small stylesheet files (typically under 50KB compressed). This translates directly to faster page loads, especially for field staff on mobile networks.

The TailAdmin template provided pre-built components for common dashboard patterns:

# app/helpers/application_helper.rb
module ApplicationHelper
  def breadcrumb(*crumbs)
    # Generates consistent breadcrumb navigation
    content_tag :nav, class: "flex mb-6" do
      # ...
    end
  end
end

This helper method, introduced, ensures breadcrumbs appear consistently across all pages, helping users understand where they are in the application hierarchy. It's a small detail, but one that significantly improves usability when navigating between properties, tenants, and compliance records.

The User model integrated Devise modules selectively:

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :recoverable,
         :rememberable, :validatable
end

We explicitly chose not to enable features like :confirmable (email verification) or :lockable (account locking after failed attempts) initially. For internal staff accounts, these add friction without meaningful security benefit—though they remain easy to enable later if needed for tenant portals or third-party access.

The database migration added first and last names to users:

class AddFirstAndLastNameToUsers < ActiveRecord::Migration[8.0]
  def change
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string
  end
end

This seems obvious, but many authentication systems default to just email addresses. Having proper names means audit logs show "Sarah updated Property #142" rather than "sarah@agency.co.uk updated Property #142"—a subtle but important improvement for compliance and team communication.

The Tailwind Advantage for Property Interfaces

Tailwind CSS deserves special mention because it fundamentally changes how quickly you can build and modify interfaces. Rather than writing custom CSS for every component, you compose interfaces using utility classes:

<div class="bg-white dark:bg-boxdark rounded-lg shadow-default p-6">
  <h3 class="text-xl font-semibold text-black dark:text-white mb-4">
    Property Details
  </h3>
  <!-- Property form fields here -->
</div>

This approach means we can implement dark mode support (which we added in a later week) without rewriting stylesheets. The dark: prefix variants are already available, just waiting to be activated. For agencies working late preparing listings or responding to maintenance emergencies, this isn't a frivolous feature—it's about reducing eye strain and improving comfort.

The TailAdmin template includes pre-built components for forms, tables, cards, modals, and charts. This meant we could focus engineering time on lettings-specific features (like compliance tracking and portal integrations) rather than debating button styles or dropdown animations.

Deployment Strategy: Heroku from Day One

Many projects defer deployment decisions until "later." We took the opposite approach, configuring Heroku deployment on 11 June just two days into development. This established a forcing function: if the application can't deploy cleanly to production, something is wrong with the architecture.

The config/database.yml configuration was adjusted to work with Heroku's DATABASE_URL environment variable:

production:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

This is simpler than it looks. Heroku provides a PostgreSQL database automatically and sets DATABASE_URL with the connection string. Rails reads that variable and configures the database connection without any manual setup. When the database credentials rotate (which Heroku does periodically for security), the application adapts automatically.

We also configured Action Cable (Rails' WebSocket framework) to use the primary database rather than Redis initially. This simplified the production stack—fewer moving parts means fewer things that can fail during initial deployments. As traffic grows and real-time features expand, migrating to Redis is straightforward.

Why Testing Matters from Day One

By 11 June, we'd integrated RSpec, Ruby's most popular testing framework. The initial test suite was modest—primarily model validations and controller smoke tests—but the infrastructure was in place.

Here's what a typical early spec looked like:

# spec/models/user_spec.rb
RSpec.describe User, type: :model do
  describe "validations" do
    it "requires an email address" do
      user = User.new(password: "password123")
      expect(user).not_to be_valid
      expect(user.errors[:email]).to include("can't be blank")
    end
  end
end

This might seem like overkill for a validation that Devise handles automatically, but it serves two purposes. First, it confirms that our Devise configuration is correct. Second, it establishes a pattern: every model has a spec file, every controller action has coverage, and every bug fix includes a regression test. By the end of August (Week 35), this discipline would drive test coverage to 100%.

For agencies evaluating software, this is a critical indicator of quality. Untested code breaks unpredictably. Tested code breaks rarely, and when it does, the test suite catches the problem before users notice.

Performance Considerations in the Foundation

Even in this foundational week, we made choices that would pay performance dividends later:

  1. Asset Pipeline Configuration: Rails 8's asset pipeline compiles and fingerprints assets (JavaScript, CSS, images) automatically. This means browsers cache assets aggressively, only redownloading when files actually change. For agencies with field staff on mobile networks, this translates to faster page loads after the first visit.

  2. Lazy Loading Images: While not implemented until Week 35, the foundation supported it. Rails' view helpers make adding loading="lazy" attributes trivial, deferring image loads until they're needed.

  3. Database Indexing: The Property model (added 12 June) would eventually have dozens of fields, but we established the discipline early: every foreign key gets an index, every frequently queried column gets consideration for indexing.

What This Means for Agencies

The technology choices in this first week weren't about chasing trends. They were about building a platform that:

  • Deploys reliably: Heroku handles SSL, scaling, and infrastructure so agencies don't need dedicated IT staff.
  • Looks professional: TailAdmin provides a polished interface that rivals expensive SaaS platforms.
  • Performs consistently: Tailwind CSS and Rails 8 optimisations mean pages load quickly even on mobile networks.
  • Scales gracefully: Rails has proven itself in production at companies managing millions of users.
  • Maintains quality: RSpec ensures features work as intended and regressions are caught early.

For a letting agency considering custom software, these aren't flashy features. They're the unglamorous fundamentals that determine whether a system becomes indispensable or an expensive liability.

What's Next

With the foundation in place, the following weeks would build on these basics: secure photo storage (AWS S3), robust property data models, search and filtering, multi-tenancy for managing multiple agency branches, and API integrations with property portals. Each feature would benefit from this careful groundwork.

The initial commit happened on 10 June. By 12 June, we had a deployable application with authentication, a responsive UI, and the beginnings of a property management system. For a foundation built in less than a week, that's a solid start.


Related articles: