A car stock management system for dealers, built with C# (FastEndpoints) and Svelte.
cd CarDealerApi
dotnet run
The API will start at http://localhost:5150.
The SQLite database is created and seeded automatically on first run.
cd CarDealerApp
npm install
npm run dev
The frontend will start at http://localhost:5173
Two dealer accounts are seeded automatically:
| DealerName | Username | Password |
|---|---|---|
| Melbourne Auto Group | melbourne | dealer123 |
| Sydney Car World | sydney | dealer123 |
Each account has 5 cars pre-loaded. Log in as both to verify dealer isolation. Each dealer can only see and manage their own inventory.
All car endpoints require a Bearer token obtained from /auth/login.
| Method | Route | Description |
|---|---|---|
| POST | /auth/register |
Register a new dealer account |
| POST | /auth/login |
Login and receive a JWT token |
| Method | Route | Description |
|---|---|---|
| GET | /cars |
List all cars for the authenticated dealer |
| GET | /cars/{id} |
Get a single car by ID |
| POST | /cars |
Add a new car |
| PATCH | /cars/{id}/stock |
Update stock level for a car |
| DELETE | /cars/{id} | Delete a car |
| GET | /cars/search | Search cars by make and/or model |
GET /cars/search?make=toyota&model=corolla
Both parameters are optional. Supports partial matches. For example, searching toy will match Toyota.
Each dealer registers an account and logs in to receive a JWT token. The token contains the dealer's ID as a claim. Every car endpoint reads this claim to scope all database queries so a dealer can only read or modify their own cars. Attempting to access another dealer's car returns a 404.
SQLite is used with a local database file at Data/database.db. The database is initialised and seeded automatically on startup via DBInitializer. Dapper is used for all queries with raw SQL.
Request validation is handled by FastEndpoints' built-in FluentValidation integration. Invalid requests return a 400 with a descriptive error message per field.
Passwords are hashed with BCrypt before storage. Plain text passwords are never stored.
GET /cars/{id} is implemented on the backend as good REST practice, though the frontend uses the list endpoint for the dashboard view.GET /cars using LIMIT and OFFSET in the SQL query.http://localhost:5150/swagger for testing the API directly.