There's One Weird Trick™ in managing joins in this case -- create views that implement the joins and then just treat it as yet another table. Bonus feature is creating a consistent way of working with that relation using native DB tools. ;-)
that works great till your database gets big. Then you will watch your memory use skyrocket to perform joins into that view and it will F@#$@# your shit up. eventually it will take so much time to construct your view table that you'll tiemout your connection pool.
to be clear, dont' use views in production queries. you WILL regret it.