1385 lines
35 KiB
JSON
1385 lines
35 KiB
JSON
{
|
|
"openapi": "3.0.3",
|
|
"info": {
|
|
"title": "Dash API",
|
|
"version": "1.0.0",
|
|
"description": "Backend API for Dash — Google SSO auth, MSSQL, session cookies.\n\nBrowser clients must send cookies (`credentials: 'include'`). Sessions use an HTTP-only `token` cookie (`Secure`, `SameSite=Strict`, 24h); HTTPS is required for login."
|
|
},
|
|
"servers": [
|
|
{
|
|
"url": "http://localhost:4208/api",
|
|
"description": "Local default (PORT / .env)"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"name": "Auth",
|
|
"description": "Google SSO and session"
|
|
},
|
|
{
|
|
"name": "Health",
|
|
"description": "Connectivity checks"
|
|
},
|
|
{
|
|
"name": "Article",
|
|
"description": "Articles under categories"
|
|
},
|
|
{
|
|
"name": "Category",
|
|
"description": "Category tree and membership"
|
|
},
|
|
{
|
|
"name": "Company",
|
|
"description": "Company CRUD"
|
|
}
|
|
],
|
|
"paths": {
|
|
"/health": {
|
|
"get": {
|
|
"tags": [
|
|
"Health"
|
|
],
|
|
"summary": "Database health check",
|
|
"description": "Verifies the database client can establish a connection.",
|
|
"security": [],
|
|
"x-markdown": "health.md",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Database reachable",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"ok": {
|
|
"type": "boolean",
|
|
"example": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"description": "Database unreachable",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"ok": {
|
|
"type": "boolean",
|
|
"example": false
|
|
},
|
|
"error": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/company": {
|
|
"get": {
|
|
"tags": [
|
|
"Company"
|
|
],
|
|
"summary": "List companies",
|
|
"description": "Lists companies for the authenticated user.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "company/list.md",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Company list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companies": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Company"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Server error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Company"
|
|
],
|
|
"summary": "Create company",
|
|
"description": "Creates a company and selects it for the current user.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "company/create.md",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"iso639",
|
|
"name",
|
|
"taxrate",
|
|
"reducedtaxrate"
|
|
],
|
|
"properties": {
|
|
"iso639": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"taxrate": {
|
|
"type": "number"
|
|
},
|
|
"reducedtaxrate": {
|
|
"type": "number"
|
|
}
|
|
},
|
|
"example": {
|
|
"iso639": "de",
|
|
"name": "Acme GmbH",
|
|
"taxrate": 19,
|
|
"reducedtaxrate": 7
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created; selected company updated",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"company": {
|
|
"$ref": "#/components/schemas/Company"
|
|
},
|
|
"user": {
|
|
"$ref": "#/components/schemas/User"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"409": {
|
|
"description": "Company name not available",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/company/{id}": {
|
|
"put": {
|
|
"tags": [
|
|
"Company"
|
|
],
|
|
"summary": "Update company",
|
|
"description": "Updates a company.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "company/update.md",
|
|
"parameters": [
|
|
{
|
|
"in": "path",
|
|
"name": "id",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"iso639",
|
|
"name",
|
|
"taxrate",
|
|
"reducedtaxrate"
|
|
],
|
|
"properties": {
|
|
"iso639": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"taxrate": {
|
|
"type": "number"
|
|
},
|
|
"reducedtaxrate": {
|
|
"type": "number"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"company": {
|
|
"$ref": "#/components/schemas/Company"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Company not found",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"409": {
|
|
"description": "Company name not available",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Company"
|
|
],
|
|
"summary": "Delete company",
|
|
"description": "Deletes a company.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "company/delete.md",
|
|
"parameters": [
|
|
{
|
|
"in": "path",
|
|
"name": "id",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Deleted"
|
|
},
|
|
"400": {
|
|
"description": "Invalid id",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Server error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/category/tree": {
|
|
"get": {
|
|
"tags": [
|
|
"Category"
|
|
],
|
|
"summary": "Category tree",
|
|
"description": "Returns the category tree for the authenticated user's selected company.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "category/tree.md",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Tree and articles for the selected company",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"languageId": {
|
|
"type": "integer"
|
|
},
|
|
"tree": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"articles": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "No company selected",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Company not found",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/category": {
|
|
"post": {
|
|
"tags": [
|
|
"Category"
|
|
],
|
|
"summary": "Create category",
|
|
"description": "Creates a category under an authorized parent.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "category/create.md",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"parentId",
|
|
"name"
|
|
],
|
|
"properties": {
|
|
"parentId": {
|
|
"type": "integer"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"example": {
|
|
"parentId": 1,
|
|
"name": "New category"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"category": {
|
|
"$ref": "#/components/schemas/Category"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Parent not found",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/category/{id}/articles": {
|
|
"get": {
|
|
"tags": [
|
|
"Category"
|
|
],
|
|
"summary": "Articles in category",
|
|
"description": "Returns articles in a category the user is authorized for.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "category/articles.md",
|
|
"parameters": [
|
|
{
|
|
"in": "path",
|
|
"name": "id",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer"
|
|
},
|
|
"description": "Category id"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Articles list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"articles": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid id",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/category/{id}": {
|
|
"delete": {
|
|
"tags": [
|
|
"Category"
|
|
],
|
|
"summary": "Delete category",
|
|
"description": "Deletes a category the user is authorized for (not the company root).",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "category/delete.md",
|
|
"parameters": [
|
|
{
|
|
"in": "path",
|
|
"name": "id",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer"
|
|
},
|
|
"description": "Category id"
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Deleted"
|
|
},
|
|
"400": {
|
|
"description": "Invalid id or cannot delete root",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/article": {
|
|
"post": {
|
|
"tags": [
|
|
"Article"
|
|
],
|
|
"summary": "Create article",
|
|
"description": "Creates an article under an authorized category (`parentId`).",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "article/create.md",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"parentId",
|
|
"name"
|
|
],
|
|
"properties": {
|
|
"parentId": {
|
|
"type": "integer",
|
|
"description": "Category id"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"example": {
|
|
"parentId": 10,
|
|
"name": "New article"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"article": {
|
|
"$ref": "#/components/schemas/ArticleSummary"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized for parent category",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Parent not found",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/article/{sku}": {
|
|
"get": {
|
|
"tags": [
|
|
"Article"
|
|
],
|
|
"summary": "Get article by SKU",
|
|
"description": "Returns article detail by SKU if the user may access its category.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "article/get.md",
|
|
"parameters": [
|
|
{
|
|
"in": "path",
|
|
"name": "sku",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"description": "Article SKU"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Article detail",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"article": {
|
|
"$ref": "#/components/schemas/ArticleDetail"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Missing sku",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Article not found",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"patch": {
|
|
"tags": [
|
|
"Article"
|
|
],
|
|
"summary": "Update article by SKU",
|
|
"description": "Updates an article name by SKU; returns the same detail shape as GET.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "article/update.md",
|
|
"parameters": [
|
|
{
|
|
"in": "path",
|
|
"name": "sku",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"description": "Article SKU"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"name"
|
|
],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"example": {
|
|
"name": "Updated name"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated article detail",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"article": {
|
|
"$ref": "#/components/schemas/ArticleDetail"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Not authorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Article not found",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/selected-company": {
|
|
"put": {
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Set selected company",
|
|
"description": "Sets the authenticated user's selected company.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "auth/selected-company.md",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"companyId"
|
|
],
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"example": {
|
|
"companyId": 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated user",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"user": {
|
|
"$ref": "#/components/schemas/User"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid companyId",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Server error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/me": {
|
|
"get": {
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Current user",
|
|
"description": "Returns the authenticated user from the session cookie and the Google client ID. Unauthenticated calls still receive `googleClientId` with 401.",
|
|
"security": [
|
|
{
|
|
"cookieAuth": []
|
|
}
|
|
],
|
|
"x-markdown": "auth/me.md",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Authenticated",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"user": {
|
|
"$ref": "#/components/schemas/User"
|
|
},
|
|
"googleClientId": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized — still includes `googleClientId` for the frontend",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"error": {
|
|
"type": "string"
|
|
},
|
|
"googleClientId": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/logout": {
|
|
"post": {
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Logout",
|
|
"description": "Clears the HTTP-only `token` cookie set at login.",
|
|
"security": [],
|
|
"x-markdown": "auth/logout.md",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Logged out",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string",
|
|
"example": "Logged out successfully"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/login": {
|
|
"post": {
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Login with Google ID token",
|
|
"description": "Verifies a Google ID token, checks allowlist (or creates entry when `IMPLICIT_CREATE=true`), and sets an HTTP-only `token` cookie.",
|
|
"security": [],
|
|
"x-markdown": "auth/login.md",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": [
|
|
"idToken"
|
|
],
|
|
"properties": {
|
|
"idToken": {
|
|
"type": "string",
|
|
"description": "Google ID token from Google Identity Services"
|
|
}
|
|
},
|
|
"example": {
|
|
"idToken": "<google-id-token>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Login successful; `token` cookie set",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string",
|
|
"example": "Login successful"
|
|
},
|
|
"user": {
|
|
"$ref": "#/components/schemas/User"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Missing token or Google client not configured",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Invalid Google token or account",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"403": {
|
|
"description": "Email not on allowlist",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Server error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"components": {
|
|
"securitySchemes": {
|
|
"cookieAuth": {
|
|
"type": "apiKey",
|
|
"in": "cookie",
|
|
"name": "token",
|
|
"description": "HTTP-only session cookie set by POST /auth/login"
|
|
}
|
|
},
|
|
"schemas": {
|
|
"Error": {
|
|
"type": "object",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"User": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"email",
|
|
"selectedCompanyId"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer"
|
|
},
|
|
"email": {
|
|
"type": "string",
|
|
"format": "email"
|
|
},
|
|
"selectedCompanyId": {
|
|
"type": "integer",
|
|
"nullable": true
|
|
},
|
|
"picture": {
|
|
"type": "string",
|
|
"format": "uri"
|
|
}
|
|
}
|
|
},
|
|
"Company": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer"
|
|
},
|
|
"iso639": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"taxrate": {
|
|
"type": "number"
|
|
},
|
|
"reducedtaxrate": {
|
|
"type": "number"
|
|
}
|
|
}
|
|
},
|
|
"Category": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer"
|
|
},
|
|
"parentId": {
|
|
"type": "integer",
|
|
"nullable": true
|
|
},
|
|
"sort": {
|
|
"type": "integer"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"ArticleSummary": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer"
|
|
},
|
|
"parentId": {
|
|
"type": "integer"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"sku": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"ArticleDetail": {
|
|
"type": "object",
|
|
"description": "Full article payload (unit, brand, categoryIds, photos, eans, prices, …)",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|