Developer Guidelines
This document summarises the current project layout, application structure, and styling conventions used in KelpieBooks. It is intended to help contributors make changes that fit naturally with the existing codebase.
Project Overview
KelpieBooks is organised as a Rust workspace with separate backend, frontend, shared domain code, documentation, planning documents, and deployment/configuration assets.
Top-Level Directories
backend/
The backend contains the Rocket-based server application.
Key areas:
backend/src/main.rs: Application entry point and server setup.backend/src/db/: Database access layer. Files are grouped by domain concept, such as accounts, users, organisations, transactions, journal entries, and security.backend/src/routes/: HTTP route handlers grouped by feature area.backend/src/services/: Business logic that sits between routes and database access.backend/src/util/: Shared backend utilities, such as logging and common types.backend/migrations/: SQL database migrations.backend/static/: Static files served by the backend if required.
frontend/
The frontend is a Yew application compiled to WebAssembly and built with Trunk.
Key areas:
frontend/src/main.rs: Frontend application entry point.frontend/src/lib.rs: Main frontend library module.frontend/src/auth.rs: Frontend authentication-related logic.frontend/src/components/: Reusable UI components such as layout, sidebar, header, account rows, journal entry rows, and modal dialogs.frontend/src/pages/: Route-level page components such as dashboard, login, register, profile, ledger, account ledger, and transaction entry pages.frontend/assets/: Static frontend assets, including images and CSS assets.frontend/styles/kelpie.css: Primary shared stylesheet for the frontend.frontend/index.html: HTML entry point used by Trunk.frontend/Trunk.toml: Trunk build configuration.
shared_core/
Shared Rust code used across the backend and frontend.
Typical responsibilities include:
- Shared models
- DTOs
- Request types
- Utility functions
- Common business/domain types
Use this crate for types that must remain consistent between client and server.
.docs/
The home of all our documentation source
This is divided into
general: Overall documentation about all aspects of the projectuser: The end user documentation a.k.a. the user manual
.planning/
Project planning and design documentation.
Current documents include onboarding and ledger planning notes. New design, architecture, feature, and implementation planning documents should be added here.
templates/
Configuration or deployment templates.
logs/
Runtime logs. These should generally be treated as generated output, not source material.
Architectural Conventions
Keep Domain Types Shared
If a type is exchanged between frontend and backend, place it in shared_core rather than duplicating it.
Good candidates for shared_core include:
- Request payloads
- Response DTOs
- Domain models
- Enum values used by both frontend and backend
- Shared formatting or validation helpers
Handling Currency values
- All monetary values must be represented as
i64whole cents (e.g.,$10.50is stored and calculated as1050). - Never use
f32orf64for tracking financial values. - All mathematical modifications must happen via safe integer calculations to completely eliminate rounding errors.
i18n - Internationalization
The back end and front end use similar techniques for internationalization.
Translations and language files are all in the shared_core.
Frontend
- Use the LocalContext in each component that renders content
- At the start of the component get the locale context
let i18n = use_locale();
- In the html retrieve the text by key
i18n.t("common-expand")
or if it has arguments
i18n.t_args("vendor-invoice-drawer-inv-number", &fluent_args!["number" => props.invoice.invoice_number.clone()])
- Format dates and currencies
i18n.format_date(primary_entry.date)
i18n.format_currency(total_amount)Backend
- Use the LocalContext where appropriate, e.g. pdf exports
- At the start of the route create a Context using the data from the AuthenticatedUser
let i18n = LocaleContext::new(&user.locale);
- Use the same techniques as above for translation and formatting.
Keep Backend Layers Separate
Backend changes should generally follow this flow:
[HTTP Request] -> [Routes] -> [Services] -> [DB Modules] -> [Database]
Use each layer for its intended purpose:
-
Routes should handle HTTP concerns:
- Request parsing
- Authentication/authorisation checks
- Response construction
- Status codes
-
Services should handle business logic:
- Validation
- Multi-step operations
- Coordination between database functions
- Domain rules
-
DB modules should handle database access:
- SQL queries
- Mapping database rows to Rust types
- Insert/update/delete/select operations
Avoid placing complex business logic directly inside route handlers or database functions.
Use transactions where appropriate. Any route that makes multiple transaction entries, that must remain in balance in the accounts, must be placed in a transaction. Most of the database updates are write only so there is generally little need to consider deadlocks in this situation.
Keep Frontend Components Focused
Frontend code is split into:
- Pages for route-level screens
- Components for reusable UI pieces
- Auth logic for authentication helpers
- Shared styles in
kelpie.css
A page should compose components rather than becoming one large component itself.
Reusable UI patterns, such as modals, rows, layout wrappers, and navigation elements, should live in
frontend/src/components/.
Frontend Layout Guidelines
The application uses a dashboard-style layout with:
- A sidebar for primary navigation
- A header for top-level page/application controls
- A main content area for page content
The general structure is:
+--------------------------------------------------+
| Header |
+----------+---------------------------------------+
| | |
| Sidebar | Main Content Area |
| | |
| | |
+----------+---------------------------------------+
When adding authenticated/dashboard pages, they should fit inside the existing layout rather than creating independent page chrome.
Authentication pages may use centred form layouts instead of the dashboard layout where appropriate.
Styling Guidelines
The frontend uses a central stylesheet. Key colour variables are defined in frontend/assets/scss/base/_variables.scss
and should be used to maintain consistency.
// Example from _variables.scss
:root {
--brand-color: #8B0000; /* Dark Red */
--text-color: #333;
--background-color: #f4f4f4;
--border-color: #ddd;
--success-color: #28a745;
--error-color: #dc3545;
}
Use these variables for consistent colour usage.
Typography
Headings use the custom dark red brand colour and modest sizing.
General conventions:
h1is used for primary page titles.h2is used for section headings and includes a subtle bottom border.h3is used for smaller section or panel headings.
Layout Containers
Common layout classes include:
.page-container: Used for full-height centred page layouts, especially auth-style screens..content: Flexible vertical content container with scroll support..scrollable-table: Scrollable area for table-heavy views..scrollable-list: Fixed-height scrollable list region.
When building new screens, prefer these existing layout classes before introducing new layout rules.
Buttons
Base button styles are defined globally.
Default buttons use:
- Light grey background
- Dark red text
- Rounded corners
- Subtle border
- Hover state
- Disabled state
Additional button patterns:
.button-secondaryfor secondary actions.button-groupfor radio-style grouped choices.icon-buttonfor compact icon actions.key-buttonfor minimal key-style buttons.button-rowfor horizontally spaced button groups
Guidelines:
- Use normal buttons for primary page actions.
- Use
.button-secondaryfor cancel/back/less important actions. - Use
.icon-buttonfor row-level table actions. - Keep destructive actions behind confirmation modals where appropriate.
Forms
Inputs, selects, and textareas share consistent styling:
- Rounded border
- Compact padding
- Focus ring
- Max width control
- Validation classes
Validation classes:
.input-success.input-error.error.success-message
Form layout patterns:
.auth-formuses a two-column grid with labels on the left and inputs on the right..modal-formuses a similar two-column grid inside modals..transaction-formis used for larger accounting/transaction entry screens.
Guidelines:
- Align labels consistently.
- Use existing error and success message styles.
- Avoid inline styles for validation states.
- Prefer semantic form elements.
Tables
Tables use the shared .table class.
Common behaviour:
- Full-width layout
- Collapsed borders
- White background
- Subtle shadow
- Compact cell padding
- Header background
- Alternating row colour
Special table conventions:
.coa-tableis used for chart of accounts tables..actions-cellis used for action columns..amountis used for right-aligned numeric values..transaction-detail-rowand.transaction-detail-contentare used for expandable transaction details.
Guidelines:
- Use
.tablefor tabular data. - Right-align monetary and amount fields.
- Use action columns for edit/delete/view controls.
- Keep row-level action buttons compact.
Modals
Modal styling uses:
.modal-overlay.modal-content.modal-form
Modal conventions:
- Overlay covers the full viewport.
- Content is centred.
- Forms use grid alignment.
- Actions are placed at the bottom right.
Use modals for focused interactions such as:
- Adding records
- Editing records
- Confirming destructive actions
- Confirming journal entry reversals
Cards and Alerts
Use .card for boxed content panels.
Use .alert for prominent warning/error notices.
Use .success-message for successful operation feedback.
Use .error for form or request errors.
Links
Links use the shared link colour and underline on hover.
Avoid styling links as buttons unless they perform navigation. Use buttons for actions.
Accounting UI Conventions
KelpieBooks contains accounting-focused screens, so consistency is especially important for financial data.
Amounts
Use .amount for numeric money values.
Amounts should be:
- Right-aligned
- Consistently formatted
- Clearly separated into debit/credit/balance columns where relevant
Journal Entries
Journal entry forms use grid-based rows with consistent columns.
Existing classes include:
.journal-entry-header.journal-entry-row.journal-entry-line.totals.balanced.unbalanced
Guidelines:
- Keep debit and credit columns aligned.
- Clearly indicate whether an entry is balanced.
- Use success/error colour states for balanced/unbalanced indicators.
- Avoid hiding imbalance states from the user.
Chart of Accounts
Chart of accounts tables use .coa-table with specific column classes:
.code-col.name-col.category-col.balance-col.actions-col
Parent accounts are visually emphasised with .parent-account.
Use .collapse-toggle for expanding/collapsing account groups.
Naming Guidelines
Rust Modules
Use snake_case for Rust files and modules.
Examples:
backend/src/db/chart_of_accounts.rsshared_core/src/models/transaction_dto.rs
Frontend Components
Frontend component files should be named after the component or UI element they contain, using PascalCase. The files
themselves should be snake_case.
Examples:
- Component:
AccountRow-> File:frontend/src/components/account_row.rs - Page:
DashboardPage-> File:frontend/src/pages/dashboard_page.rs
CSS Classes
Prefer descriptive class names over abbreviated names unless the abbreviation is already established, such as
coa-table. Use BEM (Block, Element, Modifier) naming conventions for clarity where appropriate.
Examples:
.table(Block).table__row--highlighted(Block with Modifier).modal-form__input(Element within a Block)
Adding New Features
When adding a new feature:
- Define shared request/response/domain types in
shared_coreif needed. - Add database logic under
backend/src/db/. - Add business rules under
backend/src/services/. - Add HTTP routes under
backend/src/routes/. - Add frontend API calls/auth handling where needed.
- Add reusable frontend components under
frontend/src/components/. - Add route-level screens under
frontend/src/pages/. - Reuse styles from
frontend/styles/kelpie.css. - Add or update planning documentation in
planning/for significant features.
Style Maintenance Guidelines
When modifying styles:
- Use SCSS variables for colours, fonts, and spacing from
frontend/assets/scss/base/_variables.scss. - Reuse existing utility and component classes before creating new ones.
- Avoid creating new classes for one-off situations. Consider utility classes or inline styles if the style is not reusable.
- Use the BEM (Block, Element, Modifier) naming convention for new CSS classes to keep styles scoped and understandable.
For example:
.card__header--large.
Consistency Checklist
Before submitting frontend changes, check:
- Does the page fit into the established layout?
- Are buttons using existing button styles?
- Are forms using existing form patterns?
- Are errors and success messages styled consistently?
- Are tables using
.table? - Are amounts right-aligned?
- Are modals using the standard modal classes?
- Are colours coming from CSS variables where appropriate?
Before submitting backend changes, check:
- Are route handlers thin?
- Is business logic in services?
- Is SQL/database logic isolated in
dbmodules? - Are shared types placed in
shared_core? - Are errors handled clearly?
- Are new routes grouped in the correct route module?
General Development Principles
- Keep code organised by responsibility.
- Prefer small, focused components and functions.
- Avoid duplicating shared types between frontend and backend.
- Keep user-facing interactions predictable and consistent.
- Preserve the accounting-specific clarity of the interface.
- Update this document when layout or styling conventions change.