Coding Standards#
This document describes the conventions and patterns used in the Helpbuttons codebase. Follow these when contributing so that new code integrates naturally with the existing style.
General principles#
- TypeScript everywhere: both frontend (
web/) and backend (api/) are fully TypeScript. Avoidanytypes where a proper interface or type can be defined. - Open software choices: prefer well-documented, widely adopted open-source libraries. Introduce new dependencies only when necessary.
- Mobile-first: UI components should work on small screens before large ones.
- GIS awareness: location and map functionality are core — keep geographic data consistent (lat/lng, GeoJSON, H3 cells).
Naming conventions#
General rule#
File and folder names follow FUNCTION-TYPE order:
BtnCircle → Btn (function: button element) + Circle (type)
CardNotification → Card (function: card display) + Notification (type)
FormLogin → Form (function) + Login (type)
Exception — domain classes: when a domain model has many associated elements, the class name comes first:
ButtonNew → Button (class) + New (function)
ButtonCard → Button (class) + Card (type)
NetworkNew → Network (class) + New (function)
NetworkCard → Network (class) + Card (type)
The goal is that similar things group together naturally in a file browser: all Card* components together, all Button* domain elements together.
Frontend components#
- PascalCase for component files and their folders:
ButtonCard/,NetworkNew/ - Each component lives in its own folder with an
index.tsxas the entry point - CSS files are lowercase, including file names:
button-card.css, notButtonCard.css
Backend modules#
- Module folders are lowercase with hyphens:
group-message/,user-credential/ - Entity files:
<name>.entity.ts - DTO files:
<name>.dto.ts - Service files:
<name>.service.ts - Controller files:
<name>.controller.ts
Important naming distinction#
Btn= a native HTML button element (UI atom)Button= a Helpbutton post (the domain object)
Never use these interchangeably.
Frontend conventions#
Component structure#
Each component lives in its own folder:
components/
└── ButtonCard/
├── index.tsx # main component export
├── data.tsx # store events and state selectors (if needed)
└── button-card.css
State management#
State is managed through the custom Store — an RxJS event stream. Do not use component-level state (useState) for data that needs to be shared across unrelated components. See Store for full documentation.
- Read state with the
useRefhook:const user = useRef(store, (state) => state.currentUser) - Write state by emitting events:
store.emit(new SetLoadingEvent(true)) - Async operations use
WatchEventto chain further events
Services#
All API calls go through the services/ layer. Never call fetch or axios directly from a component. Create a typed service function in web/src/services/<domain>/ and call that.
CSS#
- Class names are lowercase with hyphens:
.button-card,.nav-item - File names are lowercase:
button-card.css - Avoid inline styles except for dynamic values (colors, coordinates from data)
- Icons come from react-icons (Bootstrap set)
i18n#
All user-visible strings must use the i18n system. Never hardcode display text. String keys live in web/public/locales/<lang>/.
Backend conventions#
Module structure#
Every feature module follows NestJS conventions:
modules/
└── button/
├── button.entity.ts # TypeORM entity (DB schema)
├── button.dto.ts # Request validation (class-validator)
├── button.service.ts # Business logic
├── button.controller.ts # HTTP endpoints
└── button.module.ts # NestJS module definition
Adding a new attribute to a model#
- Add the column to
<name>.entity.ts - Add the field with validation to
<name>.dto.ts - Generate a migration:
yarn migration:generate src/data/migrations/<description> - Run migrations:
yarn migration:run - Update the corresponding frontend form/DTO in
web/src/shared/and the relevant page
TypeORM migrations#
- Always generate a named migration, never edit existing ones
- Migration names should be descriptive:
add-expiration-to-button,add-invite-role - Run
yarn migration:runafter pulling changes that include new migrations
API conventions#
- REST endpoints follow NestJS controller conventions
- DTOs use
class-validatordecorators for input validation - Guards handle JWT authentication — apply the
@UseGuards(JwtAuthGuard)decorator on protected routes - The geocoding provider is pluggable — use the
GeoServiceabstraction, never call a geocoding API directly
Email#
Email templates use Handlebars (.hbs files in api/src/modules/mail/templates/). Use the MailService to send emails — never send directly via nodemailer from a controller or service outside this module.
Commit conventions#
Follow Angular-style commit messages. See Commit conventions for the full guide.
Short version:
<type>(<scope>): <short description>
feat(button): add expiration date field
fix(network): correct federation URL resolution
docs(readme): update installation steps
Types: feat, fix, docs, style, refactor, test, chore
Git workflow#
- Branch from
dev, not frommain - Open PRs back to
dev maintracks production releases- The live dev instance at dev.helpbuttons.org auto-deploys from
dev
See Contributing for the full workflow.
Browsing the component library#
While running locally, visit http://localhost:3000/RepositoryPage to see all styled elements and components rendered with example props. Use this as a reference before creating new UI elements — the component you need may already exist.