From 45c6d03f8dbd773243432cc24bd7f5a22d2c46b5 Mon Sep 17 00:00:00 2001 From: blaisadmin Date: Thu, 26 Mar 2026 00:28:34 -0400 Subject: [PATCH] Working and documented --- README.md | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 289 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1444cf5..9cd527b 100644 --- a/README.md +++ b/README.md @@ -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 ` +- 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