Working and documented
This commit is contained in:
@@ -84,10 +84,298 @@ To disable self-service account creation and allow only existing users or SSO si
|
||||
ALLOW_REGISTRATION=false
|
||||
```
|
||||
|
||||
## API routes
|
||||
## API
|
||||
|
||||
The app includes an Express API in [backend/src/app.ts](/home/corey/github/Arsenal_IQ/backend/src/app.ts). In local development, the frontend calls:
|
||||
|
||||
- Base URL: `http://localhost:5000/api`
|
||||
- Health check: `http://localhost:5000/health`
|
||||
|
||||
### Authentication model
|
||||
|
||||
- Authenticated requests use `Authorization: Bearer <token>`
|
||||
- The token is returned by local login/register or after a successful SSO callback
|
||||
- The app is currently single-profile per user, even though profile endpoints still exist for compatibility
|
||||
- Most inventory routes also accept `x-profile-id`, but in the current app this resolves to the user’s single arsenal/profile
|
||||
|
||||
### Environment flags
|
||||
|
||||
- `ALLOW_REGISTRATION=true|false`
|
||||
- Controls whether `POST /api/auth/register` is available
|
||||
- When `false`, the login UI hides self-service account creation
|
||||
|
||||
### Response shape notes
|
||||
|
||||
- Validation and business-rule errors generally return:
|
||||
|
||||
```json
|
||||
{ "error": "Human readable message" }
|
||||
```
|
||||
|
||||
- Successful login/register responses return:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "session-token",
|
||||
"user": {
|
||||
"id": "uuid",
|
||||
"email": "owner@example.com",
|
||||
"name": "Owner Name"
|
||||
},
|
||||
"profiles": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"name": "Owner"
|
||||
}
|
||||
],
|
||||
"activeProfileId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
### Core routes
|
||||
|
||||
#### Service and discovery
|
||||
|
||||
- `GET /health`
|
||||
- Returns service/database health
|
||||
- `GET /api`
|
||||
- Returns API metadata and `allowRegistration`
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Arsenal IQ API",
|
||||
"version": "3.0.0",
|
||||
"allowRegistration": true,
|
||||
"resources": [
|
||||
"/api/auth/login",
|
||||
"/api/auth/register",
|
||||
"/api/dashboard",
|
||||
"/api/firearms",
|
||||
"/api/calibers",
|
||||
"/api/ammo"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Authentication
|
||||
|
||||
- `GET /api/auth/providers`
|
||||
- Public list of enabled SSO providers for the login page
|
||||
- `POST /api/auth/register`
|
||||
- Creates a local account when registration is enabled
|
||||
- `POST /api/auth/login`
|
||||
- Signs in with local email/password
|
||||
- `POST /api/auth/logout`
|
||||
- Invalidates the current session token
|
||||
- `GET /api/auth/me`
|
||||
- Returns the current authenticated user and active profile
|
||||
- `GET /api/auth/sso/:providerKey/start`
|
||||
- Starts the OIDC login flow and returns an authorization URL
|
||||
- `GET /api/auth/sso/:providerKey/callback`
|
||||
- Handles the provider callback, creates or links a user, then redirects back to the frontend with a token
|
||||
|
||||
Register request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Owner Name",
|
||||
"email": "owner@example.com",
|
||||
"password": "change-me"
|
||||
}
|
||||
```
|
||||
|
||||
Login request:
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "owner@example.com",
|
||||
"password": "change-me"
|
||||
}
|
||||
```
|
||||
|
||||
SSO behavior:
|
||||
|
||||
- If the SSO provider returns an email that matches an existing user, the SSO identity is linked to that user
|
||||
- If the email does not exist yet, a new user is created automatically
|
||||
- If the account was created via SSO only, local password login is rejected for that user
|
||||
|
||||
#### Profiles
|
||||
|
||||
- `GET /api/profiles`
|
||||
- Returns the user’s profile list and active profile ID
|
||||
- `POST /api/profiles`
|
||||
- Currently disabled and returns `403`
|
||||
- `POST /api/profiles/select`
|
||||
- Returns the active profile ID
|
||||
|
||||
Note:
|
||||
|
||||
- The backend still exposes these endpoints, but the product now behaves as one user per arsenal/profile
|
||||
|
||||
#### Dashboard
|
||||
|
||||
- `GET /api/dashboard`
|
||||
- Returns the current user, active profile, firearms, calibers, ammo inventory, defaults, and summary metrics used by the React UI
|
||||
|
||||
Summary fields:
|
||||
|
||||
- `totalFirearms`
|
||||
- `totalAmmoRounds`
|
||||
- `firearmsInvestment`
|
||||
- `ammoInvestment`
|
||||
- `configuredCalibers`
|
||||
|
||||
#### Firearms
|
||||
|
||||
- `GET /api/firearms`
|
||||
- Lists firearms for the current profile
|
||||
- `POST /api/firearms`
|
||||
- Creates a firearm
|
||||
- `PUT /api/firearms/:id`
|
||||
- Updates a firearm
|
||||
- `DELETE /api/firearms/:id`
|
||||
- Deletes a firearm
|
||||
|
||||
Firearm body:
|
||||
|
||||
```json
|
||||
{
|
||||
"manufacturer": "Glock",
|
||||
"model": "19",
|
||||
"category": "Handgun",
|
||||
"caliber": "9mm",
|
||||
"serialNumber": "ABC123",
|
||||
"purchasePrice": 550,
|
||||
"acquiredOn": "2025-06-01",
|
||||
"imageUrl": "",
|
||||
"notes": "Carry pistol"
|
||||
}
|
||||
```
|
||||
|
||||
Valid firearm categories:
|
||||
|
||||
- `Handgun`
|
||||
- `Rifle`
|
||||
- `Shotgun`
|
||||
- `PCC`
|
||||
- `Other`
|
||||
|
||||
Firearm response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"manufacturer": "Glock",
|
||||
"model": "19",
|
||||
"category": "Handgun",
|
||||
"caliber": "9mm",
|
||||
"serialNumber": "ABC123",
|
||||
"purchasePrice": 550,
|
||||
"acquiredOn": "2025-06-01",
|
||||
"imageUrl": null,
|
||||
"notes": "Carry pistol"
|
||||
}
|
||||
```
|
||||
|
||||
#### Calibers
|
||||
|
||||
- `GET /api/calibers`
|
||||
- Returns configured active calibers plus unused default caliber names
|
||||
- `POST /api/calibers`
|
||||
- Adds or re-enables a caliber for the current profile
|
||||
- `PATCH /api/calibers/:id`
|
||||
- Enables or disables a caliber
|
||||
|
||||
Create caliber request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "300 BLK"
|
||||
}
|
||||
```
|
||||
|
||||
Toggle caliber request:
|
||||
|
||||
```json
|
||||
{
|
||||
"isActive": false
|
||||
}
|
||||
```
|
||||
|
||||
Caliber response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"name": "9mm",
|
||||
"isDefault": true,
|
||||
"isActive": true
|
||||
}
|
||||
```
|
||||
|
||||
#### Ammo
|
||||
|
||||
- `GET /api/ammo`
|
||||
- Returns active caliber inventory rows for the current profile
|
||||
- `PATCH /api/ammo/:caliberId`
|
||||
- Adjusts rounds on hand and optionally updates cost per round
|
||||
|
||||
Ammo patch request:
|
||||
|
||||
```json
|
||||
{
|
||||
"rounds": 250,
|
||||
"costPerRound": 0.24
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Positive `rounds` adds to the current count
|
||||
- Negative `rounds` removes from the current count
|
||||
- The backend clamps the final total to `0`
|
||||
- If `costPerRound` is omitted or `null`, the existing value is preserved
|
||||
|
||||
Ammo response:
|
||||
|
||||
```json
|
||||
{
|
||||
"caliberId": "uuid",
|
||||
"caliber": "9mm",
|
||||
"roundsOnHand": 750,
|
||||
"costPerRound": 0.24,
|
||||
"totalValue": 180
|
||||
}
|
||||
```
|
||||
|
||||
#### Auth provider settings
|
||||
|
||||
- `GET /api/settings/auth-providers`
|
||||
- Returns the full editable provider configuration for the authenticated settings page
|
||||
- `PUT /api/settings/auth-providers/:providerKey`
|
||||
- Updates an auth provider config such as Google, Entra, or another OIDC-compatible provider
|
||||
|
||||
Provider update request:
|
||||
|
||||
```json
|
||||
{
|
||||
"displayName": "Google",
|
||||
"protocol": "oidc",
|
||||
"clientId": "your-client-id",
|
||||
"clientSecret": "your-client-secret",
|
||||
"authorizationEndpoint": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"tokenEndpoint": "https://oauth2.googleapis.com/token",
|
||||
"userinfoEndpoint": "https://openidconnect.googleapis.com/v1/userinfo",
|
||||
"issuer": "https://accounts.google.com",
|
||||
"scopes": "openid profile email",
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
### Current limitations
|
||||
|
||||
- There is no password reset or account recovery flow yet
|
||||
- There is no API versioning beyond the current route structure
|
||||
- Profile endpoints remain present, but multiple profiles are intentionally disabled in the product
|
||||
|
||||
Reference in New Issue
Block a user