Transnode is a web app that manages all aspects of a multinational shipping company. It manages Taxes, Exchange Rates, Countries, States, Cities, Carriers, Customers, Invoices, Credit notes, among others.

Front end

We did not design a specific UI for this project but rathered implemented a basic Bootstrap style and concentrated more on the development.


On the Frontend side Transnode was built using technologies such as Dart and Angular Dart. These are new generation languages created by Google. Transnode is integrated with Amazon AWS and we are currently working on an integration with Google Apps for email client management and user logins. On the backend side we are using Ruby on Rails with automated tests to guarantee the right functioning of the app.

Dart applications can only be accessed by using Google Chromium browser.

class Contact < ActiveRecord::Base
  include Searchable
  include Filterable
  include BranchManager

  belongs_to :location
  has_one :user
  has_many :emails, as: :of
  has_many :phones, as: :of
  accepts_nested_attributes_for :emails, allow_destroy: true
  accepts_nested_attributes_for :phones, allow_destroy: true

  enum type_user: {salesRep: 0, accountant: 1}
  scope :sales_rep, -> {where(:type_user => ContactType::SALESREP)}

  validates_presence_of :name, :type_user, :emails, :phones

  def self.for_select

  def self.sales_rep_for_select

  def email
    ( emails.empty? )? "n/h" :;

  def roles_for_users
    (location)? location.roles : []
require 'spec_helper'

describe Contact, :type => :model do
  let(:email){ build(:email) }
  let(:phone){ build(:phone) }
  let(:contact){ build(:contact, emails: [email], phones: [phone]) }
  subject{ contact }

  it{ respond_to(:name)}
  it{ respond_to(:title)}
  it{ respond_to(:role)}
  it{ respond_to(:type_user)}
  it{ respond_to(:birthday)}
  it{ respond_to(:status)}
  it{ respond_to(:created_at)}
  it{ respond_to(:updated_at)}

  it{ expect(contact.emails).to include(email)}
  it{ expect(contact.phones).to include(phone)}

  describe 'validation' do
    it{ validate_presence_of(:name)  }
    it{ validate_presence_of(:type_user)  }
    it{ validate_presence_of(:emails)  }
    it{ validate_presence_of(:phones)  }

  context 'with optional relation' do
    let(:location){ build(:location) }
    let(:user){ build(:user) }

    describe 'location' do
      before{ contact.location = location }
      it{ expect(contact.location).to be(location)  }

    describe 'user' do
      before{ contact.user = user }
      it{ expect(contact.user).to be(user)  }

  context 'create' do
    describe 'multiple roles' do
      let(:attributes){ attributes_for(:contact) }
      it do
        expect{create(:contact, attributes ) }.to change(Contact, :count).by(1)

    describe 'accepts_nested_attributes' do
      describe 'contacts' do
        let(:attributes){attributes_for(:contact, emails:[],phones:[],emails_attributes: [attributes_for(:email)] ,phones_attributes: [attributes_for(:phone)])}
        it { expect{}.to_not raise_error }

Don't take our word for it. We run Transnode through Code Climate, and this third party app rates our code and gives us recommendations in how to improve it.

The Process

Status updates

Every Monday we send a report on what the team was able to accomplish the prior week and what the plan is for the upcoming week.

trello - project management

We detail in cards all stories that need to happen in the project. When completed, each card shows an Acceptance Criteria, Pull Request to Github, and Test coverage.

Quality Assurance

A Sr Developer will conduct Code Reviews and accept or reject the story. When approved a member of the Q/A team tests the story in the production environment.


We do weekly deploys to the project and push all new features to production.

Weekly Feedback

Every week Transnode's team get together, reviews a module of the app and send feedback to our team with how to improve it according to their use needs.

Client approval

We will still need your feedback in this process to tell us whether it meets the needs or needs further tweaking. Ultimatelly the story must be accepted by you.