Project · Water

Yachty

Maritime crew management — one source of truth across the fleet.

Essence

For the people who use it

Yacht operations run on a patchwork of spreadsheets, shared inboxes and cloud-drive folders. Certifications expire silently. Onboarding stalls because somebody never received a document. Payroll across multiple currencies and time zones turns into a monthly fire drill. Yachty replaces the patchwork with one place to keep crew data, run the operation and prove compliance.

Built for captains, crew managers, HR, fleet operators and the crew themselves, the platform covers the full lifecycle: recruitment, onboarding, compliance, leave, payroll, travel documents, budgets, reporting. Each role has the view it needs. Captains see crew availability and expiries; HR runs payroll; crew members upload their own documents and request their own leave.

The vessel is the unit. A fleet operator with twelve yachts gets twelve isolated tenants without twelve databases. A new crew member joining a new vessel is a workflow, not a project plan.

Visit Yachty

Construction

For the engineers

Stack

API
ASP.NET Core 10 Web API on .NET 10 · 60+ RESTful endpoints with OpenAPI
Frontend
Two Blazor WebAssembly 10 SPAs — Admin (operators) and Site (crew)
Data access
Dapper 2.1.66 — no EF Core, database-first
Database
SQL Server, idempotent schema scripts
Auth
JWT Bearer (24h + refresh) · BCrypt · Blazored.LocalStorage
UI
BootstrapBlazor 10.2.1 · Syncfusion Blazor 32.1.22 — grids, charts, rich text
Document parsing
TesseractOCR 5.5.1 · MRZ 1.2.0 for passport / visa parsing
Testing
Microsoft.Playwright 1.57 · NUnit · Bogus for test-data generation

Architecture

Layered monolith with clear seams. The API hosts controllers → services → Dapper repositories → SQL Server. Yachty.Shared holds DTOs, domain models, lookup entities and authentication contracts and is referenced by both Blazor SPAs as well as the API, so any change to a shape ripples to both ends at compile time.

Central Package Management. Every dependency version lives in Directory.Packages.Props. Five projects, one place to update — no drift between the Admin SPA, Crew SPA, API, Shared and Tests projects.

Multi-vessel isolation by foreign key. Every core table — CrewMembers, Employments, PayrollRuns, Expenses — carries a VesselId. A twelve-yacht fleet operator gets twelve isolated tenants in one database without per-tenant schema sprawl.

Strict soft delete and audit trail. Every entity carries IsDeleted plus a four-column audit (CreatedAt, CreatedBy, UpdatedAt, UpdatedBy). Nothing is destroyed; everything is attributed.

Database-first, idempotent SQL. Schema lives in a two-part DBSchema-Update.sql — table definitions in part one, idempotent alters in part two. The same script can run against an empty database or production without modification.

Notable details