diff --git a/README.md b/README.md index 2adb032..abc821b 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,22 @@ -# Product service +## product-service +- **Purpose:** Product catalog (list + detail). +- **Base path:** `/api/products` -## Create product database + user on mysql server +### Create product database ``` kubectl -n cloudshopt exec -it cloudshopt-mysql-0 -- bash -mysql -u root -prootpass -``` +# mysql -u root -prootpass -``` CREATE DATABASE cloudshopt_products CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -CREATE USER 'users'@'%' IDENTIFIED BY 'userspass'; +CREATE USER 'users'@'%' IDENTIFIED BY 'CHANGE_ME_PASSWORD'; GRANT ALL PRIVILEGES ON cloudshopt_products.* TO 'users'@'%'; FLUSH PRIVILEGES; ``` -Ustvari še bazo za *dev* okolje -``` -CREATE DATABASE cloudshopt_products_dev CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -CREATE USER 'users_dev'@'%' IDENTIFIED BY 'userspass'; -GRANT ALL PRIVILEGES ON cloudshopt_products_dev.* TO 'users_dev'@'%'; -FLUSH PRIVILEGES; -``` - -## Crete external secrets for prod and dev -prod: -``` -kubectl -n cloudshopt create secret generic product-service-secrets \ - --from-literal=DB_PASSWORD="userspass" \ - --from-literal=REDIS_PASSWORD="redispass" \ - --dry-run=client -o yaml | kubectl apply -f - -``` - -dev: -``` -kubectl -n cloudshopt-dev create secret generic product-service-secrets \ - --from-literal=DB_PASSWORD="userspass" \ - --from-literal=REDIS_PASSWORD="redispass" \ - --dry-run=client -o yaml | kubectl apply -f - -``` - -check for secrets: -``` -kubectl get secret -n cloudshopt product-service-secrets -kubectl get secret -n cloudshopt-dev product-service-secrets -``` - -## Install product-service for prod and dev -prod: -``` -helm upgrade --install product-service ./helm/product-service \ --n cloudshopt \ --f helm/product-service/values.yaml -``` - -dev: -``` -helm upgrade --install product-service-dev ./helm/product-service \ --n cloudshopt-dev \ --f helm/product-service/values-dev.yaml -``` - +### Migrations - -## Migrations - -run migrations: ``` -kubectl exec -n cloudshopt-dev -it deploy/product-service-dev -c app -- sh - +kubectl exec -n cloudshopt -it deploy/product-service -c app -- sh # php artisan migrate ``` diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 7d00ea5..5c1b0eb 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,102 +1,210 @@ openapi: 3.0.3 info: title: CloudShopt Product Service API - version: 0.1.0 - description: API for product catalog -servers: - - url: /api + version: 1.0.0 tags: - - name: meta - - name: products + - name: Health + - name: Diagnostics + - name: Products paths: - /info: + /healthz: get: - tags: [meta] - summary: Service info (test endpoint) + tags: [Health] + summary: Health check responses: "200": description: OK content: application/json: schema: - type: object - properties: - service: - type: string - example: product-service - status: - type: string - example: ok + $ref: "#/components/schemas/StatusOkBool" - /health: + /info: get: - tags: [meta] - summary: Health check + tags: [Diagnostics] + summary: Service info (sha, time) responses: "200": - description: Healthy + description: Info content: application/json: schema: - type: object - properties: - ok: - type: boolean - example: true + $ref: "#/components/schemas/InfoResponse" - /products: + /database: get: - tags: [products] - summary: List products (test placeholder) + tags: [Diagnostics] + summary: Database connectivity check responses: "200": - description: OK + description: DB OK content: application/json: schema: - type: object - properties: - data: - type: array - items: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/DatabaseOkResponse" "500": - $ref: "#/components/responses/ServerError" + description: DB connection failed + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseFailResponse" + + /items: + get: + tags: [Products] + summary: List products + responses: + "200": + description: Products + content: + application/json: + schema: + $ref: "#/components/schemas/ProductListResponse" + + /items/{id}: + get: + tags: [Products] + summary: Get product detail + parameters: + - name: id + in: path + required: true + schema: + type: integer + minimum: 1 + responses: + "200": + description: Product + content: + application/json: + schema: + $ref: "#/components/schemas/ProductResponse" + "404": + $ref: "#/components/responses/NotFound" components: responses: - ServerError: - description: Server error + NotFound: + description: Not found content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/ErrorMessage" + example: + message: "Not found" schemas: + ErrorMessage: + type: object + required: [message] + properties: + message: + type: string + + StatusOkBool: + type: object + required: [ok] + properties: + ok: + type: boolean + example: true + + InfoResponse: + type: object + required: [ok, service, sha, time] + properties: + ok: + type: boolean + example: true + service: + type: string + example: product-service + sha: + type: string + nullable: true + example: 0.0.1 + time: + type: string + format: date-time + example: "2026-01-29T10:15:30.123Z" + + DatabaseOkResponse: + type: object + required: [ok, db, time] + properties: + ok: + type: boolean + example: true + db: + type: object + required: [connection, database, ping_ms] + properties: + connection: + type: string + example: mysql + database: + type: string + example: cloudshopt_products_dev + ping_ms: + type: number + format: float + example: 1.25 + time: + type: string + format: date-time + example: "2026-01-29T10:15:30.123Z" + + DatabaseFailResponse: + type: object + required: [ok, error, message] + properties: + ok: + type: boolean + example: false + error: + type: string + example: DB connection failed + message: + type: string + nullable: true + example: "SQLSTATE[HY000] ..." + Product: type: object + required: [id, name, price] properties: id: type: integer example: 1 name: type: string - example: "T-Shirt" + example: CloudShopt T-Shirt + description: + type: string + nullable: true + example: Basic tee for everyday wear. price: - type: number - format: float - example: 19.99 + type: integer + description: Price in cents + example: 1990 + image_url: + type: string + nullable: true + example: null - ErrorResponse: + ProductResponse: type: object + required: [data] properties: - message: - type: string - example: "Internal Server Error" - code: - type: string - example: "SERVER_ERROR" - details: - type: object - additionalProperties: true \ No newline at end of file + data: + $ref: "#/components/schemas/Product" + + ProductListResponse: + type: object + required: [data] + properties: + data: + type: array + items: + $ref: "#/components/schemas/Product" \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index 1135c49..f3a5515 100644 --- a/routes/api.php +++ b/routes/api.php @@ -21,7 +21,7 @@ Route::get('/info', function () { return response()->json([ - 'ok11' => true, + 'ok' => true, 'service' => config('app.name'), 'sha' => env('IMAGE_SHA', null), 'time' => now()->toISOString(),