Frontend Architecture: ISS
Rails view layer with Hotwire (Turbo + Stimulus) and Propshaft asset pipeline. Answers: how does the UI render and what conventions govern it?
Diagram
Components
| Component |
Purpose |
Notes |
| <code>application.html.erb</code> |
Root layout — nav, tab bar, flash messages, content yield |
Wraps all authenticated views. Includes <code>_tab_bar.html.erb</code> partial for bottom navigation. |
| <code>_tab_bar.html.erb</code> |
Bottom tab bar navigation shared across all authenticated views |
Role-aware: shows different tabs for admin vs lead/client. Tabs: Catalog, Projects, Communications, Account (+ CRM for admin). |
| <code>pages/landing.html.erb</code> |
Public landing page — the sales pitch and App Store CTA |
Root route (<code>root "pages#landing"</code>). No auth required. Marketing-only — no login form. |
| Propshaft |
Asset fingerprinting and serving |
No Node.js build step. CSS files served directly with fingerprinted URLs. |
| importmap-rails |
ES module management without bundler |
Pins Turbo, Stimulus, and application JS via importmap. No webpack/esbuild. |
| Turbo Drive |
SPA-like page transitions without full reloads |
Default Hotwire behavior — intercepts link clicks and form submissions. |
| Turbo Frames |
Partial page updates scoped to a frame |
Used for inline editing, modal-like flows, tab content switching. |
| Turbo Streams |
Real-time DOM updates via WebSocket (Solid Cable) |
Used for live messaging updates. Backed by Solid Cable (PostgreSQL, no Redis). |
| Stimulus |
Modest JS framework for DOM behavior |
Controllers for interactive UI elements. No heavy client-side state. |
CSS Conventions
| Convention |
Detail |
| Design tokens |
CSS custom properties on <code>:root</code> in <code>application.css</code>. Brand colors: <code>--color-accent: #1b2a4a</code> (navy), <code>--color-gold: #996d13</code>. |
| Per-view stylesheets |
One CSS file per view area: <code>dashboard.css</code>, <code>catalog.css</code>, <code>messages.css</code>, <code>profile.css</code>, <code>tab_bar.css</code>, <code>forms.css</code>, <code>pages.css</code>, <code>admin_catalog.css</code>. |
| No utility-first |
Semantic class names, not Tailwind. Styles reference design tokens via <code>var(--color-*)</code>. |
| Mobile-first |
Base styles target mobile (Turbo Native shell). Desktop breakpoints added as needed. |
Key Decisions
- Propshaft + importmap over esbuild/webpack — No Node.js build step. Propshaft handles asset fingerprinting; importmap-rails pins ES modules directly. Simpler deploy, fewer moving parts.
- Hotwire over React/Vue SPA — Server-rendered HTML with Turbo Drive for navigation, Turbo Frames for partial updates, Turbo Streams for real-time. One codebase serves both web and Turbo Native iOS.
- Semantic CSS with design tokens — All colors, spacing, and typography flow from CSS custom properties defined once in
application.css. No Tailwind. ISS brand palette (navy + gold) enforced via tokens.
- Per-view CSS files — Each view area gets its own stylesheet. Avoids monolithic CSS. Propshaft serves them individually with fingerprinting.
- Tab bar as shared partial —
_tab_bar.html.erb renders role-aware navigation. Admin sees CRM tab; leads/clients do not. Consistent bottom nav across the iOS shell.
- Landing page outside auth —
pages#landing is the root route, served without authentication. All other views require login via the authenticate_user! filter.
- Solid Cable for WebSocket — Turbo Streams use Solid Cable backed by PostgreSQL. No Redis dependency for real-time features.
Key Directories
| Path |
Contents |
| <code>app/views/layouts/</code> |
<code>application.html.erb</code> — root layout with tab bar |
| <code>app/views/shared/</code> |
<code>_tab_bar.html.erb</code> — role-aware bottom navigation |
| <code>app/views/pages/</code> |
<code>landing.html.erb</code> — public landing page |
| <code>app/views/dashboard/</code> |
Authenticated dashboard views |
| <code>app/views/catalog/</code> |
Public catalog browsing |
| <code>app/views/admin/catalog/</code> |
Admin CRUD for catalog entries |
| <code>app/views/messages/</code> |
Messaging thread views |
| <code>app/views/profile/</code> |
User profile display and edit |
| <code>app/assets/stylesheets/</code> |
Per-view CSS files with shared design tokens |