From 482178096879d0357433a8c6a77098bef941d3bf Mon Sep 17 00:00:00 2001 From: Zikil Date: Thu, 27 Mar 2025 18:15:50 +0700 Subject: [PATCH] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B4=D0=BE=D0=BB=D0=B6?= =?UTF-8?q?=D0=B0=D1=8E=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D1=82=D1=8C?= =?UTF-8?q?=20=D1=81=20=D0=BE=D0=BD=D0=BE=D0=B2=D1=8B=D0=BC=20=D1=81=D0=B0?= =?UTF-8?q?=D0=B9=D1=82=D0=BE=D0=BC.=20=D0=B2=20=D0=B7=D0=B0=D0=B3=D0=BB?= =?UTF-8?q?=D1=83=D1=88=D0=BA=D1=83=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=B8=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BE=D0=B1=20=D0=98=D0=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 12292 bytes .cursor/rules/.cursorrules | 107 + .cursor/rules/fastapinextjs.mdc | 131 + .../alembic/__pycache__/env.cpython-310.pyc | Bin 2007 -> 2007 bytes ...6faa_add_size_table_and_update_product_.py | 57 + .../2325dd0f1bd5_init.cpython-310.pyc | Bin 832 -> 832 bytes ..._table_and_update_product_.cpython-310.pyc | Bin 0 -> 3424 bytes ...40913679bd_update_products.cpython-310.pyc | Bin 1950 -> 1950 bytes .../app/__pycache__/__init__.cpython-310.pyc | Bin 171 -> 173 bytes .../app/__pycache__/config.cpython-310.pyc | Bin 1820 -> 1822 bytes backend/app/__pycache__/core.cpython-310.pyc | Bin 3426 -> 3428 bytes backend/app/__pycache__/main.cpython-310.pyc | Bin 1710 -> 1710 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 178 -> 180 bytes .../catalog_models.cpython-310.pyc | Bin 3296 -> 3791 bytes .../content_models.cpython-310.pyc | Bin 1708 -> 1710 bytes .../__pycache__/order_models.cpython-310.pyc | Bin 2885 -> 2887 bytes .../__pycache__/review_models.cpython-310.pyc | Bin 1184 -> 1186 bytes .../__pycache__/user_models.cpython-310.pyc | Bin 1829 -> 1831 bytes backend/app/models/catalog_models.py | 28 +- .../__pycache__/__init__.cpython-310.pyc | Bin 184 -> 184 bytes .../__pycache__/catalog_repo.cpython-310.pyc | Bin 13585 -> 17307 bytes .../__pycache__/content_repo.cpython-310.pyc | Bin 6106 -> 6106 bytes .../__pycache__/order_repo.cpython-310.pyc | Bin 10469 -> 10611 bytes .../__pycache__/review_repo.cpython-310.pyc | Bin 5585 -> 5585 bytes .../__pycache__/user_repo.cpython-310.pyc | Bin 6442 -> 6442 bytes backend/app/repositories/catalog_repo.py | 310 +- backend/app/repositories/order_repo.py | 110 +- .../__pycache__/__init__.cpython-310.pyc | Bin 848 -> 848 bytes .../analytics_router.cpython-310.pyc | Bin 1780 -> 1780 bytes .../__pycache__/auth_router.cpython-310.pyc | Bin 2230 -> 2230 bytes .../__pycache__/cart_router.cpython-310.pyc | Bin 1919 -> 1919 bytes .../catalog_router.cpython-310.pyc | Bin 6526 -> 7913 bytes .../content_router.cpython-310.pyc | Bin 2116 -> 2116 bytes .../__pycache__/order_router.cpython-310.pyc | Bin 2133 -> 2133 bytes .../__pycache__/review_router.cpython-310.pyc | Bin 2052 -> 2052 bytes .../__pycache__/user_router.cpython-310.pyc | Bin 2204 -> 2204 bytes backend/app/routers/catalog_router.py | 84 +- .../__pycache__/__init__.cpython-310.pyc | Bin 179 -> 179 bytes .../catalog_schemas.cpython-310.pyc | Bin 6537 -> 7568 bytes .../content_schemas.cpython-310.pyc | Bin 2970 -> 2970 bytes .../__pycache__/order_schemas.cpython-310.pyc | Bin 4924 -> 4924 bytes .../review_schemas.cpython-310.pyc | Bin 1766 -> 1766 bytes .../__pycache__/user_schemas.cpython-310.pyc | Bin 4311 -> 4311 bytes backend/app/schemas/catalog_schemas.py | 47 +- backend/app/services/__init__.py | 3 +- .../__pycache__/__init__.cpython-310.pyc | Bin 1643 -> 1775 bytes .../catalog_service.cpython-310.pyc | Bin 8047 -> 11839 bytes .../content_service.cpython-310.pyc | Bin 1870 -> 1870 bytes .../__pycache__/order_service.cpython-310.pyc | Bin 4278 -> 4278 bytes .../review_service.cpython-310.pyc | Bin 2051 -> 2051 bytes .../__pycache__/user_service.cpython-310.pyc | Bin 5705 -> 5705 bytes backend/app/services/catalog_service.py | 339 +- backend/docs/README.md | 117 + backend/docs/api_documentation.md | 191 + backend/docs/database_structure.md | 210 + .../ea1e8526-b67b-40ba-b971-b87694223a4a.png | Bin 0 -> 677827 bytes .../eb3edbd1-b0ec-4a3a-9458-93e867ac2bd4.png | Bin 0 -> 677827 bytes .../035b2663-53a2-4581-9d7d-eb9282ba359b.png | Bin 0 -> 677827 bytes .../4ac4d7ff-4d44-4ac8-950b-5d9b1802e88a.png | Bin 0 -> 677827 bytes .../e15e0382-c28f-4858-a6e8-b0db39e8ea35.png | Bin 0 -> 677827 bytes frontend/.DS_Store | Bin 8196 -> 8196 bytes frontend/app/{ => (main)}/about/page.tsx | 0 frontend/app/{ => (main)}/blog/loading.tsx | 0 frontend/app/{ => (main)}/blog/page.tsx | 0 frontend/app/{ => (main)}/cart/page.tsx | 0 frontend/app/(main)/catalog/[slug]/page.tsx | 142 + frontend/app/{ => (main)}/catalog/loading.tsx | 0 frontend/app/(main)/catalog/page.tsx | 627 ++ frontend/app/{ => (main)}/checkout/page.tsx | 0 .../app/{ => (main)}/collections/page.tsx | 0 frontend/app/{ => (main)}/contact/page.tsx | 0 frontend/app/{ => (main)}/faq/loading.tsx | 0 frontend/app/{ => (main)}/faq/page.tsx | 0 frontend/app/(main)/layout.tsx | 16 + .../{ => (main)}/order-tracking/loading.tsx | 0 .../app/{ => (main)}/order-tracking/page.tsx | 0 frontend/app/{ => (main)}/page.tsx | 0 .../app/{ => (main)}/product/[id]/page.tsx | 81 - frontend/app/(main)/product/layout.tsx | 16 + frontend/app/{ => (main)}/size-guide/page.tsx | 0 frontend/app/{ => (main)}/wishlist/page.tsx | 0 frontend/app/admin/categories/page.tsx | 235 + frontend/app/admin/collections/page.tsx | 235 + frontend/app/admin/customers/page.tsx | 243 + frontend/app/admin/dashboard/page.tsx | 522 + frontend/app/admin/layout.tsx | 99 + frontend/app/admin/login/page.tsx | 159 + frontend/app/admin/orders/[id]/page.tsx | 186 + frontend/app/admin/orders/page.tsx | 452 + frontend/app/admin/page.tsx | 5 + frontend/app/admin/products/[id]/page.tsx | 163 + .../products/components/EditProductDialog.tsx | 965 ++ frontend/app/admin/products/create/page.tsx | 102 + frontend/app/admin/products/page.tsx | 466 + frontend/app/catalog/page.tsx | 700 -- frontend/app/layout.tsx | 55 +- frontend/components/admin/AdminLayout.tsx | 298 + frontend/components/admin/AdminSidebar.tsx | 106 + frontend/components/admin/CategoryForm.tsx | 242 + .../components/admin/ProductForm copy.tsx | 391 + frontend/components/admin/ProductForm.tsx | 296 + .../components/admin/ProductImageUploader.tsx | 230 + frontend/components/admin/ProductImages.tsx | 375 + .../admin/ProductVariantManager.tsx | 336 + frontend/components/admin/ProductVariants.tsx | 440 + frontend/components/admin/Sidebar.tsx | 107 + .../components/admin/orders/CustomerInfo.tsx | 30 + .../components/admin/orders/OrderActions.tsx | 99 + .../components/admin/orders/OrderHeader.tsx | 32 + .../components/admin/orders/OrderItems.tsx | 141 + .../components/admin/orders/OrderNotes.tsx | 18 + .../components/admin/orders/OrderStatus.tsx | 103 + .../admin/orders/PaymentShipping.tsx | 103 + .../admin/orders/ShippingAddress.tsx | 53 + frontend/components/footer.tsx | 27 +- frontend/components/layout/site-footer.tsx | 139 + frontend/components/layout/site-header.tsx | 275 + frontend/components/product/ImageSlider.tsx | 179 + .../components/product/ProductDetails.tsx | 252 + frontend/components/product/product-card.tsx | 165 + .../components/providers/theme-provider.tsx | 9 + frontend/components/ui/product-card.tsx | 28 +- frontend/components/ui/sheet.tsx | 15 +- frontend/hooks/use-cart.tsx | 144 + frontend/hooks/use-media-query.ts | 31 + frontend/hooks/use-wishlist.tsx | 140 + frontend/lib/analytics.ts | 100 + frontend/lib/api.ts | 443 + frontend/lib/auth.ts | 94 + frontend/lib/auth.tsx | 349 + frontend/lib/cart.ts | 68 + frontend/lib/catalog-admin.ts | 96 + frontend/lib/catalog.ts | 651 ++ frontend/lib/orders.ts | 341 + frontend/lib/users.ts | 115 + frontend/lib/utils.ts | 39 +- frontend/package-lock.json | 436 +- frontend/package.json | 25 +- frontend/public/logo copy.svg | 50 + frontend/public/logo-white.svg | 56 +- frontend/public/logo.svg | 58 +- frontend/tsconfig.json | 7 +- land_comingsoon/app/about/page.tsx | 155 + land_comingsoon/app/layout.tsx | 22 + land_comingsoon/app/page.tsx | 19 +- node_modules/.package-lock.json | 285 + node_modules/asynckit/LICENSE | 21 + node_modules/asynckit/README.md | 233 + node_modules/asynckit/bench.js | 76 + node_modules/asynckit/index.js | 6 + node_modules/asynckit/lib/abort.js | 29 + node_modules/asynckit/lib/async.js | 34 + node_modules/asynckit/lib/defer.js | 26 + node_modules/asynckit/lib/iterate.js | 75 + .../asynckit/lib/readable_asynckit.js | 91 + .../asynckit/lib/readable_parallel.js | 25 + node_modules/asynckit/lib/readable_serial.js | 25 + .../asynckit/lib/readable_serial_ordered.js | 29 + node_modules/asynckit/lib/state.js | 37 + node_modules/asynckit/lib/streamify.js | 141 + node_modules/asynckit/lib/terminator.js | 29 + node_modules/asynckit/package.json | 63 + node_modules/asynckit/parallel.js | 43 + node_modules/asynckit/serial.js | 17 + node_modules/asynckit/serialOrdered.js | 75 + node_modules/asynckit/stream.js | 21 + node_modules/axios/CHANGELOG.md | 1158 +++ node_modules/axios/LICENSE | 7 + node_modules/axios/MIGRATION_GUIDE.md | 3 + node_modules/axios/README.md | 1679 ++++ node_modules/axios/dist/axios.js | 4277 +++++++++ node_modules/axios/dist/axios.js.map | 1 + node_modules/axios/dist/axios.min.js | 3 + node_modules/axios/dist/axios.min.js.map | 1 + node_modules/axios/dist/browser/axios.cjs | 3708 +++++++ node_modules/axios/dist/browser/axios.cjs.map | 1 + node_modules/axios/dist/esm/axios.js | 3731 ++++++++ node_modules/axios/dist/esm/axios.js.map | 1 + node_modules/axios/dist/esm/axios.min.js | 3 + node_modules/axios/dist/esm/axios.min.js.map | 1 + node_modules/axios/dist/node/axios.cjs | 4765 +++++++++ node_modules/axios/dist/node/axios.cjs.map | 1 + node_modules/axios/index.d.cts | 550 ++ node_modules/axios/index.d.ts | 570 ++ node_modules/axios/index.js | 43 + node_modules/axios/lib/adapters/README.md | 37 + node_modules/axios/lib/adapters/adapters.js | 79 + node_modules/axios/lib/adapters/fetch.js | 229 + node_modules/axios/lib/adapters/http.js | 695 ++ node_modules/axios/lib/adapters/xhr.js | 197 + node_modules/axios/lib/axios.js | 89 + node_modules/axios/lib/cancel/CancelToken.js | 135 + .../axios/lib/cancel/CanceledError.js | 25 + node_modules/axios/lib/cancel/isCancel.js | 5 + node_modules/axios/lib/core/Axios.js | 242 + node_modules/axios/lib/core/AxiosError.js | 103 + node_modules/axios/lib/core/AxiosHeaders.js | 302 + .../axios/lib/core/InterceptorManager.js | 71 + node_modules/axios/lib/core/README.md | 8 + node_modules/axios/lib/core/buildFullPath.js | 22 + .../axios/lib/core/dispatchRequest.js | 81 + node_modules/axios/lib/core/mergeConfig.js | 106 + node_modules/axios/lib/core/settle.js | 27 + node_modules/axios/lib/core/transformData.js | 28 + node_modules/axios/lib/defaults/index.js | 161 + .../axios/lib/defaults/transitional.js | 7 + node_modules/axios/lib/env/README.md | 3 + .../axios/lib/env/classes/FormData.js | 2 + node_modules/axios/lib/env/data.js | 1 + .../axios/lib/helpers/AxiosTransformStream.js | 143 + .../axios/lib/helpers/AxiosURLSearchParams.js | 58 + .../axios/lib/helpers/HttpStatusCode.js | 71 + node_modules/axios/lib/helpers/README.md | 7 + .../lib/helpers/ZlibHeaderTransformStream.js | 28 + node_modules/axios/lib/helpers/bind.js | 7 + node_modules/axios/lib/helpers/buildURL.js | 69 + node_modules/axios/lib/helpers/callbackify.js | 16 + node_modules/axios/lib/helpers/combineURLs.js | 15 + .../axios/lib/helpers/composeSignals.js | 48 + node_modules/axios/lib/helpers/cookies.js | 42 + .../axios/lib/helpers/deprecatedMethod.js | 26 + .../axios/lib/helpers/formDataToJSON.js | 95 + .../axios/lib/helpers/formDataToStream.js | 112 + node_modules/axios/lib/helpers/fromDataURI.js | 53 + .../axios/lib/helpers/isAbsoluteURL.js | 15 + .../axios/lib/helpers/isAxiosError.js | 14 + .../axios/lib/helpers/isURLSameOrigin.js | 14 + node_modules/axios/lib/helpers/null.js | 2 + .../axios/lib/helpers/parseHeaders.js | 55 + .../axios/lib/helpers/parseProtocol.js | 6 + .../axios/lib/helpers/progressEventReducer.js | 44 + node_modules/axios/lib/helpers/readBlob.js | 15 + .../axios/lib/helpers/resolveConfig.js | 57 + node_modules/axios/lib/helpers/speedometer.js | 55 + node_modules/axios/lib/helpers/spread.js | 28 + node_modules/axios/lib/helpers/throttle.js | 44 + node_modules/axios/lib/helpers/toFormData.js | 219 + .../axios/lib/helpers/toURLEncodedForm.js | 18 + node_modules/axios/lib/helpers/trackStream.js | 87 + node_modules/axios/lib/helpers/validator.js | 99 + .../lib/platform/browser/classes/Blob.js | 3 + .../lib/platform/browser/classes/FormData.js | 3 + .../browser/classes/URLSearchParams.js | 4 + .../axios/lib/platform/browser/index.js | 13 + .../axios/lib/platform/common/utils.js | 51 + node_modules/axios/lib/platform/index.js | 7 + .../lib/platform/node/classes/FormData.js | 3 + .../platform/node/classes/URLSearchParams.js | 4 + node_modules/axios/lib/platform/node/index.js | 38 + node_modules/axios/lib/utils.js | 738 ++ node_modules/axios/package.json | 219 + .../call-bind-apply-helpers/.eslintrc | 17 + .../.github/FUNDING.yml | 12 + node_modules/call-bind-apply-helpers/.nycrc | 9 + .../call-bind-apply-helpers/CHANGELOG.md | 30 + node_modules/call-bind-apply-helpers/LICENSE | 21 + .../call-bind-apply-helpers/README.md | 62 + .../call-bind-apply-helpers/actualApply.d.ts | 1 + .../call-bind-apply-helpers/actualApply.js | 10 + .../call-bind-apply-helpers/applyBind.d.ts | 19 + .../call-bind-apply-helpers/applyBind.js | 10 + .../functionApply.d.ts | 1 + .../call-bind-apply-helpers/functionApply.js | 4 + .../call-bind-apply-helpers/functionCall.d.ts | 1 + .../call-bind-apply-helpers/functionCall.js | 4 + .../call-bind-apply-helpers/index.d.ts | 64 + node_modules/call-bind-apply-helpers/index.js | 15 + .../call-bind-apply-helpers/package.json | 85 + .../call-bind-apply-helpers/reflectApply.d.ts | 3 + .../call-bind-apply-helpers/reflectApply.js | 4 + .../call-bind-apply-helpers/test/index.js | 63 + .../call-bind-apply-helpers/tsconfig.json | 9 + node_modules/combined-stream/License | 19 + node_modules/combined-stream/Readme.md | 138 + .../combined-stream/lib/combined_stream.js | 208 + node_modules/combined-stream/package.json | 25 + node_modules/combined-stream/yarn.lock | 17 + node_modules/delayed-stream/.npmignore | 1 + node_modules/delayed-stream/License | 19 + node_modules/delayed-stream/Makefile | 7 + node_modules/delayed-stream/Readme.md | 141 + .../delayed-stream/lib/delayed_stream.js | 107 + node_modules/delayed-stream/package.json | 27 + node_modules/dunder-proto/.eslintrc | 5 + node_modules/dunder-proto/.github/FUNDING.yml | 12 + node_modules/dunder-proto/.nycrc | 13 + node_modules/dunder-proto/CHANGELOG.md | 24 + node_modules/dunder-proto/LICENSE | 21 + node_modules/dunder-proto/README.md | 54 + node_modules/dunder-proto/get.d.ts | 5 + node_modules/dunder-proto/get.js | 30 + node_modules/dunder-proto/package.json | 76 + node_modules/dunder-proto/set.d.ts | 5 + node_modules/dunder-proto/set.js | 35 + node_modules/dunder-proto/test/get.js | 34 + node_modules/dunder-proto/test/index.js | 4 + node_modules/dunder-proto/test/set.js | 50 + node_modules/dunder-proto/tsconfig.json | 9 + node_modules/es-define-property/.eslintrc | 13 + .../es-define-property/.github/FUNDING.yml | 12 + node_modules/es-define-property/.nycrc | 9 + node_modules/es-define-property/CHANGELOG.md | 29 + node_modules/es-define-property/LICENSE | 21 + node_modules/es-define-property/README.md | 49 + node_modules/es-define-property/index.d.ts | 3 + node_modules/es-define-property/index.js | 14 + node_modules/es-define-property/package.json | 81 + node_modules/es-define-property/test/index.js | 56 + node_modules/es-define-property/tsconfig.json | 10 + node_modules/es-errors/.eslintrc | 5 + node_modules/es-errors/.github/FUNDING.yml | 12 + node_modules/es-errors/CHANGELOG.md | 40 + node_modules/es-errors/LICENSE | 21 + node_modules/es-errors/README.md | 55 + node_modules/es-errors/eval.d.ts | 3 + node_modules/es-errors/eval.js | 4 + node_modules/es-errors/index.d.ts | 3 + node_modules/es-errors/index.js | 4 + node_modules/es-errors/package.json | 80 + node_modules/es-errors/range.d.ts | 3 + node_modules/es-errors/range.js | 4 + node_modules/es-errors/ref.d.ts | 3 + node_modules/es-errors/ref.js | 4 + node_modules/es-errors/syntax.d.ts | 3 + node_modules/es-errors/syntax.js | 4 + node_modules/es-errors/test/index.js | 19 + node_modules/es-errors/tsconfig.json | 49 + node_modules/es-errors/type.d.ts | 3 + node_modules/es-errors/type.js | 4 + node_modules/es-errors/uri.d.ts | 3 + node_modules/es-errors/uri.js | 4 + node_modules/es-object-atoms/.eslintrc | 16 + .../es-object-atoms/.github/FUNDING.yml | 12 + node_modules/es-object-atoms/CHANGELOG.md | 37 + node_modules/es-object-atoms/LICENSE | 21 + node_modules/es-object-atoms/README.md | 63 + .../RequireObjectCoercible.d.ts | 3 + .../es-object-atoms/RequireObjectCoercible.js | 11 + node_modules/es-object-atoms/ToObject.d.ts | 7 + node_modules/es-object-atoms/ToObject.js | 10 + node_modules/es-object-atoms/index.d.ts | 3 + node_modules/es-object-atoms/index.js | 4 + node_modules/es-object-atoms/isObject.d.ts | 3 + node_modules/es-object-atoms/isObject.js | 6 + node_modules/es-object-atoms/package.json | 80 + node_modules/es-object-atoms/test/index.js | 38 + node_modules/es-object-atoms/tsconfig.json | 6 + node_modules/es-set-tostringtag/.eslintrc | 13 + node_modules/es-set-tostringtag/.nycrc | 9 + node_modules/es-set-tostringtag/CHANGELOG.md | 67 + node_modules/es-set-tostringtag/LICENSE | 21 + node_modules/es-set-tostringtag/README.md | 53 + node_modules/es-set-tostringtag/index.d.ts | 10 + node_modules/es-set-tostringtag/index.js | 35 + node_modules/es-set-tostringtag/package.json | 78 + node_modules/es-set-tostringtag/test/index.js | 85 + node_modules/es-set-tostringtag/tsconfig.json | 9 + node_modules/follow-redirects/LICENSE | 18 + node_modules/follow-redirects/README.md | 155 + node_modules/follow-redirects/debug.js | 15 + node_modules/follow-redirects/http.js | 1 + node_modules/follow-redirects/https.js | 1 + node_modules/follow-redirects/index.js | 686 ++ node_modules/follow-redirects/package.json | 58 + node_modules/form-data/License | 19 + node_modules/form-data/Readme.md | 358 + node_modules/form-data/index.d.ts | 62 + node_modules/form-data/lib/browser.js | 2 + node_modules/form-data/lib/form_data.js | 503 + node_modules/form-data/lib/populate.js | 10 + node_modules/form-data/package.json | 74 + node_modules/function-bind/.eslintrc | 21 + .../function-bind/.github/FUNDING.yml | 12 + .../function-bind/.github/SECURITY.md | 3 + node_modules/function-bind/.nycrc | 13 + node_modules/function-bind/CHANGELOG.md | 136 + node_modules/function-bind/LICENSE | 20 + node_modules/function-bind/README.md | 46 + node_modules/function-bind/implementation.js | 84 + node_modules/function-bind/index.js | 5 + node_modules/function-bind/package.json | 87 + node_modules/function-bind/test/.eslintrc | 9 + node_modules/function-bind/test/index.js | 252 + node_modules/get-intrinsic/.eslintrc | 42 + .../get-intrinsic/.github/FUNDING.yml | 12 + node_modules/get-intrinsic/.nycrc | 9 + node_modules/get-intrinsic/CHANGELOG.md | 186 + node_modules/get-intrinsic/LICENSE | 21 + node_modules/get-intrinsic/README.md | 71 + node_modules/get-intrinsic/index.js | 378 + node_modules/get-intrinsic/package.json | 97 + .../get-intrinsic/test/GetIntrinsic.js | 274 + node_modules/get-proto/.eslintrc | 10 + node_modules/get-proto/.github/FUNDING.yml | 12 + node_modules/get-proto/.nycrc | 9 + node_modules/get-proto/CHANGELOG.md | 21 + node_modules/get-proto/LICENSE | 21 + .../get-proto/Object.getPrototypeOf.d.ts | 5 + .../get-proto/Object.getPrototypeOf.js | 6 + node_modules/get-proto/README.md | 50 + .../get-proto/Reflect.getPrototypeOf.d.ts | 3 + .../get-proto/Reflect.getPrototypeOf.js | 4 + node_modules/get-proto/index.d.ts | 5 + node_modules/get-proto/index.js | 27 + node_modules/get-proto/package.json | 81 + node_modules/get-proto/test/index.js | 68 + node_modules/get-proto/tsconfig.json | 9 + node_modules/gopd/.eslintrc | 16 + node_modules/gopd/.github/FUNDING.yml | 12 + node_modules/gopd/CHANGELOG.md | 45 + node_modules/gopd/LICENSE | 21 + node_modules/gopd/README.md | 40 + node_modules/gopd/gOPD.d.ts | 1 + node_modules/gopd/gOPD.js | 4 + node_modules/gopd/index.d.ts | 5 + node_modules/gopd/index.js | 15 + node_modules/gopd/package.json | 77 + node_modules/gopd/test/index.js | 36 + node_modules/gopd/tsconfig.json | 9 + node_modules/has-symbols/.eslintrc | 11 + node_modules/has-symbols/.github/FUNDING.yml | 12 + node_modules/has-symbols/.nycrc | 9 + node_modules/has-symbols/CHANGELOG.md | 91 + node_modules/has-symbols/LICENSE | 21 + node_modules/has-symbols/README.md | 46 + node_modules/has-symbols/index.d.ts | 3 + node_modules/has-symbols/index.js | 14 + node_modules/has-symbols/package.json | 111 + node_modules/has-symbols/shams.d.ts | 3 + node_modules/has-symbols/shams.js | 45 + node_modules/has-symbols/test/index.js | 22 + .../has-symbols/test/shams/core-js.js | 29 + .../test/shams/get-own-property-symbols.js | 29 + node_modules/has-symbols/test/tests.js | 58 + node_modules/has-symbols/tsconfig.json | 10 + node_modules/has-tostringtag/.eslintrc | 5 + .../has-tostringtag/.github/FUNDING.yml | 12 + node_modules/has-tostringtag/.nycrc | 13 + node_modules/has-tostringtag/CHANGELOG.md | 42 + node_modules/has-tostringtag/LICENSE | 21 + node_modules/has-tostringtag/README.md | 46 + node_modules/has-tostringtag/index.d.ts | 3 + node_modules/has-tostringtag/index.js | 8 + node_modules/has-tostringtag/package.json | 108 + node_modules/has-tostringtag/shams.d.ts | 3 + node_modules/has-tostringtag/shams.js | 8 + node_modules/has-tostringtag/test/index.js | 21 + .../has-tostringtag/test/shams/core-js.js | 31 + .../test/shams/get-own-property-symbols.js | 30 + node_modules/has-tostringtag/test/tests.js | 15 + node_modules/has-tostringtag/tsconfig.json | 49 + node_modules/hasown/.eslintrc | 5 + node_modules/hasown/.github/FUNDING.yml | 12 + node_modules/hasown/.nycrc | 13 + node_modules/hasown/CHANGELOG.md | 40 + node_modules/hasown/LICENSE | 21 + node_modules/hasown/README.md | 40 + node_modules/hasown/index.d.ts | 3 + node_modules/hasown/index.js | 8 + node_modules/hasown/package.json | 92 + node_modules/hasown/tsconfig.json | 6 + node_modules/math-intrinsics/.eslintrc | 16 + .../math-intrinsics/.github/FUNDING.yml | 12 + node_modules/math-intrinsics/CHANGELOG.md | 24 + node_modules/math-intrinsics/LICENSE | 21 + node_modules/math-intrinsics/README.md | 50 + node_modules/math-intrinsics/abs.d.ts | 1 + node_modules/math-intrinsics/abs.js | 4 + .../constants/maxArrayLength.d.ts | 3 + .../constants/maxArrayLength.js | 4 + .../constants/maxSafeInteger.d.ts | 3 + .../constants/maxSafeInteger.js | 5 + .../math-intrinsics/constants/maxValue.d.ts | 3 + .../math-intrinsics/constants/maxValue.js | 5 + node_modules/math-intrinsics/floor.d.ts | 1 + node_modules/math-intrinsics/floor.js | 4 + node_modules/math-intrinsics/isFinite.d.ts | 3 + node_modules/math-intrinsics/isFinite.js | 12 + node_modules/math-intrinsics/isInteger.d.ts | 3 + node_modules/math-intrinsics/isInteger.js | 16 + node_modules/math-intrinsics/isNaN.d.ts | 1 + node_modules/math-intrinsics/isNaN.js | 6 + .../math-intrinsics/isNegativeZero.d.ts | 3 + .../math-intrinsics/isNegativeZero.js | 6 + node_modules/math-intrinsics/max.d.ts | 1 + node_modules/math-intrinsics/max.js | 4 + node_modules/math-intrinsics/min.d.ts | 1 + node_modules/math-intrinsics/min.js | 4 + node_modules/math-intrinsics/mod.d.ts | 3 + node_modules/math-intrinsics/mod.js | 9 + node_modules/math-intrinsics/package.json | 86 + node_modules/math-intrinsics/pow.d.ts | 1 + node_modules/math-intrinsics/pow.js | 4 + node_modules/math-intrinsics/round.d.ts | 1 + node_modules/math-intrinsics/round.js | 4 + node_modules/math-intrinsics/sign.d.ts | 3 + node_modules/math-intrinsics/sign.js | 11 + node_modules/math-intrinsics/test/index.js | 192 + node_modules/math-intrinsics/tsconfig.json | 3 + node_modules/mime-db/HISTORY.md | 507 + node_modules/mime-db/LICENSE | 23 + node_modules/mime-db/README.md | 100 + node_modules/mime-db/db.json | 8519 +++++++++++++++++ node_modules/mime-db/index.js | 12 + node_modules/mime-db/package.json | 60 + node_modules/mime-types/HISTORY.md | 397 + node_modules/mime-types/LICENSE | 23 + node_modules/mime-types/README.md | 113 + node_modules/mime-types/index.js | 188 + node_modules/mime-types/package.json | 44 + node_modules/proxy-from-env/.eslintrc | 29 + node_modules/proxy-from-env/.travis.yml | 10 + node_modules/proxy-from-env/LICENSE | 20 + node_modules/proxy-from-env/README.md | 131 + node_modules/proxy-from-env/index.js | 108 + node_modules/proxy-from-env/package.json | 34 + node_modules/proxy-from-env/test.js | 483 + package-lock.json | 290 + package.json | 5 + test.txt | 1 + 520 files changed, 61203 insertions(+), 1120 deletions(-) create mode 100644 .cursor/rules/.cursorrules create mode 100644 .cursor/rules/fastapinextjs.mdc create mode 100644 backend/alembic/versions/9773b0186faa_add_size_table_and_update_product_.py create mode 100644 backend/alembic/versions/__pycache__/9773b0186faa_add_size_table_and_update_product_.cpython-310.pyc create mode 100644 backend/docs/README.md create mode 100644 backend/docs/api_documentation.md create mode 100644 backend/docs/database_structure.md create mode 100644 backend/uploads/products/2/ea1e8526-b67b-40ba-b971-b87694223a4a.png create mode 100644 backend/uploads/products/2/eb3edbd1-b0ec-4a3a-9458-93e867ac2bd4.png create mode 100644 backend/uploads/products/9/035b2663-53a2-4581-9d7d-eb9282ba359b.png create mode 100644 backend/uploads/products/9/4ac4d7ff-4d44-4ac8-950b-5d9b1802e88a.png create mode 100644 backend/uploads/products/9/e15e0382-c28f-4858-a6e8-b0db39e8ea35.png rename frontend/app/{ => (main)}/about/page.tsx (100%) rename frontend/app/{ => (main)}/blog/loading.tsx (100%) rename frontend/app/{ => (main)}/blog/page.tsx (100%) rename frontend/app/{ => (main)}/cart/page.tsx (100%) create mode 100644 frontend/app/(main)/catalog/[slug]/page.tsx rename frontend/app/{ => (main)}/catalog/loading.tsx (100%) create mode 100644 frontend/app/(main)/catalog/page.tsx rename frontend/app/{ => (main)}/checkout/page.tsx (100%) rename frontend/app/{ => (main)}/collections/page.tsx (100%) rename frontend/app/{ => (main)}/contact/page.tsx (100%) rename frontend/app/{ => (main)}/faq/loading.tsx (100%) rename frontend/app/{ => (main)}/faq/page.tsx (100%) create mode 100644 frontend/app/(main)/layout.tsx rename frontend/app/{ => (main)}/order-tracking/loading.tsx (100%) rename frontend/app/{ => (main)}/order-tracking/page.tsx (100%) rename frontend/app/{ => (main)}/page.tsx (100%) rename frontend/app/{ => (main)}/product/[id]/page.tsx (86%) create mode 100644 frontend/app/(main)/product/layout.tsx rename frontend/app/{ => (main)}/size-guide/page.tsx (100%) rename frontend/app/{ => (main)}/wishlist/page.tsx (100%) create mode 100644 frontend/app/admin/categories/page.tsx create mode 100644 frontend/app/admin/collections/page.tsx create mode 100644 frontend/app/admin/customers/page.tsx create mode 100644 frontend/app/admin/dashboard/page.tsx create mode 100644 frontend/app/admin/layout.tsx create mode 100644 frontend/app/admin/login/page.tsx create mode 100644 frontend/app/admin/orders/[id]/page.tsx create mode 100644 frontend/app/admin/orders/page.tsx create mode 100644 frontend/app/admin/page.tsx create mode 100644 frontend/app/admin/products/[id]/page.tsx create mode 100644 frontend/app/admin/products/components/EditProductDialog.tsx create mode 100644 frontend/app/admin/products/create/page.tsx create mode 100644 frontend/app/admin/products/page.tsx delete mode 100644 frontend/app/catalog/page.tsx create mode 100644 frontend/components/admin/AdminLayout.tsx create mode 100644 frontend/components/admin/AdminSidebar.tsx create mode 100644 frontend/components/admin/CategoryForm.tsx create mode 100644 frontend/components/admin/ProductForm copy.tsx create mode 100644 frontend/components/admin/ProductForm.tsx create mode 100644 frontend/components/admin/ProductImageUploader.tsx create mode 100644 frontend/components/admin/ProductImages.tsx create mode 100644 frontend/components/admin/ProductVariantManager.tsx create mode 100644 frontend/components/admin/ProductVariants.tsx create mode 100644 frontend/components/admin/Sidebar.tsx create mode 100644 frontend/components/admin/orders/CustomerInfo.tsx create mode 100644 frontend/components/admin/orders/OrderActions.tsx create mode 100644 frontend/components/admin/orders/OrderHeader.tsx create mode 100644 frontend/components/admin/orders/OrderItems.tsx create mode 100644 frontend/components/admin/orders/OrderNotes.tsx create mode 100644 frontend/components/admin/orders/OrderStatus.tsx create mode 100644 frontend/components/admin/orders/PaymentShipping.tsx create mode 100644 frontend/components/admin/orders/ShippingAddress.tsx create mode 100644 frontend/components/layout/site-footer.tsx create mode 100644 frontend/components/layout/site-header.tsx create mode 100644 frontend/components/product/ImageSlider.tsx create mode 100644 frontend/components/product/ProductDetails.tsx create mode 100644 frontend/components/product/product-card.tsx create mode 100644 frontend/components/providers/theme-provider.tsx create mode 100644 frontend/hooks/use-cart.tsx create mode 100644 frontend/hooks/use-media-query.ts create mode 100644 frontend/hooks/use-wishlist.tsx create mode 100644 frontend/lib/analytics.ts create mode 100644 frontend/lib/api.ts create mode 100644 frontend/lib/auth.ts create mode 100644 frontend/lib/auth.tsx create mode 100644 frontend/lib/cart.ts create mode 100644 frontend/lib/catalog-admin.ts create mode 100644 frontend/lib/catalog.ts create mode 100644 frontend/lib/orders.ts create mode 100644 frontend/lib/users.ts create mode 100644 frontend/public/logo copy.svg create mode 100644 land_comingsoon/app/about/page.tsx create mode 100644 node_modules/.package-lock.json create mode 100644 node_modules/asynckit/LICENSE create mode 100644 node_modules/asynckit/README.md create mode 100644 node_modules/asynckit/bench.js create mode 100644 node_modules/asynckit/index.js create mode 100644 node_modules/asynckit/lib/abort.js create mode 100644 node_modules/asynckit/lib/async.js create mode 100644 node_modules/asynckit/lib/defer.js create mode 100644 node_modules/asynckit/lib/iterate.js create mode 100644 node_modules/asynckit/lib/readable_asynckit.js create mode 100644 node_modules/asynckit/lib/readable_parallel.js create mode 100644 node_modules/asynckit/lib/readable_serial.js create mode 100644 node_modules/asynckit/lib/readable_serial_ordered.js create mode 100644 node_modules/asynckit/lib/state.js create mode 100644 node_modules/asynckit/lib/streamify.js create mode 100644 node_modules/asynckit/lib/terminator.js create mode 100644 node_modules/asynckit/package.json create mode 100644 node_modules/asynckit/parallel.js create mode 100644 node_modules/asynckit/serial.js create mode 100644 node_modules/asynckit/serialOrdered.js create mode 100644 node_modules/asynckit/stream.js create mode 100644 node_modules/axios/CHANGELOG.md create mode 100644 node_modules/axios/LICENSE create mode 100644 node_modules/axios/MIGRATION_GUIDE.md create mode 100644 node_modules/axios/README.md create mode 100644 node_modules/axios/dist/axios.js create mode 100644 node_modules/axios/dist/axios.js.map create mode 100644 node_modules/axios/dist/axios.min.js create mode 100644 node_modules/axios/dist/axios.min.js.map create mode 100644 node_modules/axios/dist/browser/axios.cjs create mode 100644 node_modules/axios/dist/browser/axios.cjs.map create mode 100644 node_modules/axios/dist/esm/axios.js create mode 100644 node_modules/axios/dist/esm/axios.js.map create mode 100644 node_modules/axios/dist/esm/axios.min.js create mode 100644 node_modules/axios/dist/esm/axios.min.js.map create mode 100644 node_modules/axios/dist/node/axios.cjs create mode 100644 node_modules/axios/dist/node/axios.cjs.map create mode 100644 node_modules/axios/index.d.cts create mode 100644 node_modules/axios/index.d.ts create mode 100644 node_modules/axios/index.js create mode 100644 node_modules/axios/lib/adapters/README.md create mode 100644 node_modules/axios/lib/adapters/adapters.js create mode 100644 node_modules/axios/lib/adapters/fetch.js create mode 100755 node_modules/axios/lib/adapters/http.js create mode 100644 node_modules/axios/lib/adapters/xhr.js create mode 100644 node_modules/axios/lib/axios.js create mode 100644 node_modules/axios/lib/cancel/CancelToken.js create mode 100644 node_modules/axios/lib/cancel/CanceledError.js create mode 100644 node_modules/axios/lib/cancel/isCancel.js create mode 100644 node_modules/axios/lib/core/Axios.js create mode 100644 node_modules/axios/lib/core/AxiosError.js create mode 100644 node_modules/axios/lib/core/AxiosHeaders.js create mode 100644 node_modules/axios/lib/core/InterceptorManager.js create mode 100644 node_modules/axios/lib/core/README.md create mode 100644 node_modules/axios/lib/core/buildFullPath.js create mode 100644 node_modules/axios/lib/core/dispatchRequest.js create mode 100644 node_modules/axios/lib/core/mergeConfig.js create mode 100644 node_modules/axios/lib/core/settle.js create mode 100644 node_modules/axios/lib/core/transformData.js create mode 100644 node_modules/axios/lib/defaults/index.js create mode 100644 node_modules/axios/lib/defaults/transitional.js create mode 100644 node_modules/axios/lib/env/README.md create mode 100644 node_modules/axios/lib/env/classes/FormData.js create mode 100644 node_modules/axios/lib/env/data.js create mode 100644 node_modules/axios/lib/helpers/AxiosTransformStream.js create mode 100644 node_modules/axios/lib/helpers/AxiosURLSearchParams.js create mode 100644 node_modules/axios/lib/helpers/HttpStatusCode.js create mode 100644 node_modules/axios/lib/helpers/README.md create mode 100644 node_modules/axios/lib/helpers/ZlibHeaderTransformStream.js create mode 100644 node_modules/axios/lib/helpers/bind.js create mode 100644 node_modules/axios/lib/helpers/buildURL.js create mode 100644 node_modules/axios/lib/helpers/callbackify.js create mode 100644 node_modules/axios/lib/helpers/combineURLs.js create mode 100644 node_modules/axios/lib/helpers/composeSignals.js create mode 100644 node_modules/axios/lib/helpers/cookies.js create mode 100644 node_modules/axios/lib/helpers/deprecatedMethod.js create mode 100644 node_modules/axios/lib/helpers/formDataToJSON.js create mode 100644 node_modules/axios/lib/helpers/formDataToStream.js create mode 100644 node_modules/axios/lib/helpers/fromDataURI.js create mode 100644 node_modules/axios/lib/helpers/isAbsoluteURL.js create mode 100644 node_modules/axios/lib/helpers/isAxiosError.js create mode 100644 node_modules/axios/lib/helpers/isURLSameOrigin.js create mode 100644 node_modules/axios/lib/helpers/null.js create mode 100644 node_modules/axios/lib/helpers/parseHeaders.js create mode 100644 node_modules/axios/lib/helpers/parseProtocol.js create mode 100644 node_modules/axios/lib/helpers/progressEventReducer.js create mode 100644 node_modules/axios/lib/helpers/readBlob.js create mode 100644 node_modules/axios/lib/helpers/resolveConfig.js create mode 100644 node_modules/axios/lib/helpers/speedometer.js create mode 100644 node_modules/axios/lib/helpers/spread.js create mode 100644 node_modules/axios/lib/helpers/throttle.js create mode 100644 node_modules/axios/lib/helpers/toFormData.js create mode 100644 node_modules/axios/lib/helpers/toURLEncodedForm.js create mode 100644 node_modules/axios/lib/helpers/trackStream.js create mode 100644 node_modules/axios/lib/helpers/validator.js create mode 100644 node_modules/axios/lib/platform/browser/classes/Blob.js create mode 100644 node_modules/axios/lib/platform/browser/classes/FormData.js create mode 100644 node_modules/axios/lib/platform/browser/classes/URLSearchParams.js create mode 100644 node_modules/axios/lib/platform/browser/index.js create mode 100644 node_modules/axios/lib/platform/common/utils.js create mode 100644 node_modules/axios/lib/platform/index.js create mode 100644 node_modules/axios/lib/platform/node/classes/FormData.js create mode 100644 node_modules/axios/lib/platform/node/classes/URLSearchParams.js create mode 100644 node_modules/axios/lib/platform/node/index.js create mode 100644 node_modules/axios/lib/utils.js create mode 100644 node_modules/axios/package.json create mode 100644 node_modules/call-bind-apply-helpers/.eslintrc create mode 100644 node_modules/call-bind-apply-helpers/.github/FUNDING.yml create mode 100644 node_modules/call-bind-apply-helpers/.nycrc create mode 100644 node_modules/call-bind-apply-helpers/CHANGELOG.md create mode 100644 node_modules/call-bind-apply-helpers/LICENSE create mode 100644 node_modules/call-bind-apply-helpers/README.md create mode 100644 node_modules/call-bind-apply-helpers/actualApply.d.ts create mode 100644 node_modules/call-bind-apply-helpers/actualApply.js create mode 100644 node_modules/call-bind-apply-helpers/applyBind.d.ts create mode 100644 node_modules/call-bind-apply-helpers/applyBind.js create mode 100644 node_modules/call-bind-apply-helpers/functionApply.d.ts create mode 100644 node_modules/call-bind-apply-helpers/functionApply.js create mode 100644 node_modules/call-bind-apply-helpers/functionCall.d.ts create mode 100644 node_modules/call-bind-apply-helpers/functionCall.js create mode 100644 node_modules/call-bind-apply-helpers/index.d.ts create mode 100644 node_modules/call-bind-apply-helpers/index.js create mode 100644 node_modules/call-bind-apply-helpers/package.json create mode 100644 node_modules/call-bind-apply-helpers/reflectApply.d.ts create mode 100644 node_modules/call-bind-apply-helpers/reflectApply.js create mode 100644 node_modules/call-bind-apply-helpers/test/index.js create mode 100644 node_modules/call-bind-apply-helpers/tsconfig.json create mode 100644 node_modules/combined-stream/License create mode 100644 node_modules/combined-stream/Readme.md create mode 100644 node_modules/combined-stream/lib/combined_stream.js create mode 100644 node_modules/combined-stream/package.json create mode 100644 node_modules/combined-stream/yarn.lock create mode 100644 node_modules/delayed-stream/.npmignore create mode 100644 node_modules/delayed-stream/License create mode 100644 node_modules/delayed-stream/Makefile create mode 100644 node_modules/delayed-stream/Readme.md create mode 100644 node_modules/delayed-stream/lib/delayed_stream.js create mode 100644 node_modules/delayed-stream/package.json create mode 100644 node_modules/dunder-proto/.eslintrc create mode 100644 node_modules/dunder-proto/.github/FUNDING.yml create mode 100644 node_modules/dunder-proto/.nycrc create mode 100644 node_modules/dunder-proto/CHANGELOG.md create mode 100644 node_modules/dunder-proto/LICENSE create mode 100644 node_modules/dunder-proto/README.md create mode 100644 node_modules/dunder-proto/get.d.ts create mode 100644 node_modules/dunder-proto/get.js create mode 100644 node_modules/dunder-proto/package.json create mode 100644 node_modules/dunder-proto/set.d.ts create mode 100644 node_modules/dunder-proto/set.js create mode 100644 node_modules/dunder-proto/test/get.js create mode 100644 node_modules/dunder-proto/test/index.js create mode 100644 node_modules/dunder-proto/test/set.js create mode 100644 node_modules/dunder-proto/tsconfig.json create mode 100644 node_modules/es-define-property/.eslintrc create mode 100644 node_modules/es-define-property/.github/FUNDING.yml create mode 100644 node_modules/es-define-property/.nycrc create mode 100644 node_modules/es-define-property/CHANGELOG.md create mode 100644 node_modules/es-define-property/LICENSE create mode 100644 node_modules/es-define-property/README.md create mode 100644 node_modules/es-define-property/index.d.ts create mode 100644 node_modules/es-define-property/index.js create mode 100644 node_modules/es-define-property/package.json create mode 100644 node_modules/es-define-property/test/index.js create mode 100644 node_modules/es-define-property/tsconfig.json create mode 100644 node_modules/es-errors/.eslintrc create mode 100644 node_modules/es-errors/.github/FUNDING.yml create mode 100644 node_modules/es-errors/CHANGELOG.md create mode 100644 node_modules/es-errors/LICENSE create mode 100644 node_modules/es-errors/README.md create mode 100644 node_modules/es-errors/eval.d.ts create mode 100644 node_modules/es-errors/eval.js create mode 100644 node_modules/es-errors/index.d.ts create mode 100644 node_modules/es-errors/index.js create mode 100644 node_modules/es-errors/package.json create mode 100644 node_modules/es-errors/range.d.ts create mode 100644 node_modules/es-errors/range.js create mode 100644 node_modules/es-errors/ref.d.ts create mode 100644 node_modules/es-errors/ref.js create mode 100644 node_modules/es-errors/syntax.d.ts create mode 100644 node_modules/es-errors/syntax.js create mode 100644 node_modules/es-errors/test/index.js create mode 100644 node_modules/es-errors/tsconfig.json create mode 100644 node_modules/es-errors/type.d.ts create mode 100644 node_modules/es-errors/type.js create mode 100644 node_modules/es-errors/uri.d.ts create mode 100644 node_modules/es-errors/uri.js create mode 100644 node_modules/es-object-atoms/.eslintrc create mode 100644 node_modules/es-object-atoms/.github/FUNDING.yml create mode 100644 node_modules/es-object-atoms/CHANGELOG.md create mode 100644 node_modules/es-object-atoms/LICENSE create mode 100644 node_modules/es-object-atoms/README.md create mode 100644 node_modules/es-object-atoms/RequireObjectCoercible.d.ts create mode 100644 node_modules/es-object-atoms/RequireObjectCoercible.js create mode 100644 node_modules/es-object-atoms/ToObject.d.ts create mode 100644 node_modules/es-object-atoms/ToObject.js create mode 100644 node_modules/es-object-atoms/index.d.ts create mode 100644 node_modules/es-object-atoms/index.js create mode 100644 node_modules/es-object-atoms/isObject.d.ts create mode 100644 node_modules/es-object-atoms/isObject.js create mode 100644 node_modules/es-object-atoms/package.json create mode 100644 node_modules/es-object-atoms/test/index.js create mode 100644 node_modules/es-object-atoms/tsconfig.json create mode 100644 node_modules/es-set-tostringtag/.eslintrc create mode 100644 node_modules/es-set-tostringtag/.nycrc create mode 100644 node_modules/es-set-tostringtag/CHANGELOG.md create mode 100644 node_modules/es-set-tostringtag/LICENSE create mode 100644 node_modules/es-set-tostringtag/README.md create mode 100644 node_modules/es-set-tostringtag/index.d.ts create mode 100644 node_modules/es-set-tostringtag/index.js create mode 100644 node_modules/es-set-tostringtag/package.json create mode 100644 node_modules/es-set-tostringtag/test/index.js create mode 100644 node_modules/es-set-tostringtag/tsconfig.json create mode 100644 node_modules/follow-redirects/LICENSE create mode 100644 node_modules/follow-redirects/README.md create mode 100644 node_modules/follow-redirects/debug.js create mode 100644 node_modules/follow-redirects/http.js create mode 100644 node_modules/follow-redirects/https.js create mode 100644 node_modules/follow-redirects/index.js create mode 100644 node_modules/follow-redirects/package.json create mode 100644 node_modules/form-data/License create mode 100644 node_modules/form-data/Readme.md create mode 100644 node_modules/form-data/index.d.ts create mode 100644 node_modules/form-data/lib/browser.js create mode 100644 node_modules/form-data/lib/form_data.js create mode 100644 node_modules/form-data/lib/populate.js create mode 100644 node_modules/form-data/package.json create mode 100644 node_modules/function-bind/.eslintrc create mode 100644 node_modules/function-bind/.github/FUNDING.yml create mode 100644 node_modules/function-bind/.github/SECURITY.md create mode 100644 node_modules/function-bind/.nycrc create mode 100644 node_modules/function-bind/CHANGELOG.md create mode 100644 node_modules/function-bind/LICENSE create mode 100644 node_modules/function-bind/README.md create mode 100644 node_modules/function-bind/implementation.js create mode 100644 node_modules/function-bind/index.js create mode 100644 node_modules/function-bind/package.json create mode 100644 node_modules/function-bind/test/.eslintrc create mode 100644 node_modules/function-bind/test/index.js create mode 100644 node_modules/get-intrinsic/.eslintrc create mode 100644 node_modules/get-intrinsic/.github/FUNDING.yml create mode 100644 node_modules/get-intrinsic/.nycrc create mode 100644 node_modules/get-intrinsic/CHANGELOG.md create mode 100644 node_modules/get-intrinsic/LICENSE create mode 100644 node_modules/get-intrinsic/README.md create mode 100644 node_modules/get-intrinsic/index.js create mode 100644 node_modules/get-intrinsic/package.json create mode 100644 node_modules/get-intrinsic/test/GetIntrinsic.js create mode 100644 node_modules/get-proto/.eslintrc create mode 100644 node_modules/get-proto/.github/FUNDING.yml create mode 100644 node_modules/get-proto/.nycrc create mode 100644 node_modules/get-proto/CHANGELOG.md create mode 100644 node_modules/get-proto/LICENSE create mode 100644 node_modules/get-proto/Object.getPrototypeOf.d.ts create mode 100644 node_modules/get-proto/Object.getPrototypeOf.js create mode 100644 node_modules/get-proto/README.md create mode 100644 node_modules/get-proto/Reflect.getPrototypeOf.d.ts create mode 100644 node_modules/get-proto/Reflect.getPrototypeOf.js create mode 100644 node_modules/get-proto/index.d.ts create mode 100644 node_modules/get-proto/index.js create mode 100644 node_modules/get-proto/package.json create mode 100644 node_modules/get-proto/test/index.js create mode 100644 node_modules/get-proto/tsconfig.json create mode 100644 node_modules/gopd/.eslintrc create mode 100644 node_modules/gopd/.github/FUNDING.yml create mode 100644 node_modules/gopd/CHANGELOG.md create mode 100644 node_modules/gopd/LICENSE create mode 100644 node_modules/gopd/README.md create mode 100644 node_modules/gopd/gOPD.d.ts create mode 100644 node_modules/gopd/gOPD.js create mode 100644 node_modules/gopd/index.d.ts create mode 100644 node_modules/gopd/index.js create mode 100644 node_modules/gopd/package.json create mode 100644 node_modules/gopd/test/index.js create mode 100644 node_modules/gopd/tsconfig.json create mode 100644 node_modules/has-symbols/.eslintrc create mode 100644 node_modules/has-symbols/.github/FUNDING.yml create mode 100644 node_modules/has-symbols/.nycrc create mode 100644 node_modules/has-symbols/CHANGELOG.md create mode 100644 node_modules/has-symbols/LICENSE create mode 100644 node_modules/has-symbols/README.md create mode 100644 node_modules/has-symbols/index.d.ts create mode 100644 node_modules/has-symbols/index.js create mode 100644 node_modules/has-symbols/package.json create mode 100644 node_modules/has-symbols/shams.d.ts create mode 100644 node_modules/has-symbols/shams.js create mode 100644 node_modules/has-symbols/test/index.js create mode 100644 node_modules/has-symbols/test/shams/core-js.js create mode 100644 node_modules/has-symbols/test/shams/get-own-property-symbols.js create mode 100644 node_modules/has-symbols/test/tests.js create mode 100644 node_modules/has-symbols/tsconfig.json create mode 100644 node_modules/has-tostringtag/.eslintrc create mode 100644 node_modules/has-tostringtag/.github/FUNDING.yml create mode 100644 node_modules/has-tostringtag/.nycrc create mode 100644 node_modules/has-tostringtag/CHANGELOG.md create mode 100644 node_modules/has-tostringtag/LICENSE create mode 100644 node_modules/has-tostringtag/README.md create mode 100644 node_modules/has-tostringtag/index.d.ts create mode 100644 node_modules/has-tostringtag/index.js create mode 100644 node_modules/has-tostringtag/package.json create mode 100644 node_modules/has-tostringtag/shams.d.ts create mode 100644 node_modules/has-tostringtag/shams.js create mode 100644 node_modules/has-tostringtag/test/index.js create mode 100644 node_modules/has-tostringtag/test/shams/core-js.js create mode 100644 node_modules/has-tostringtag/test/shams/get-own-property-symbols.js create mode 100644 node_modules/has-tostringtag/test/tests.js create mode 100644 node_modules/has-tostringtag/tsconfig.json create mode 100644 node_modules/hasown/.eslintrc create mode 100644 node_modules/hasown/.github/FUNDING.yml create mode 100644 node_modules/hasown/.nycrc create mode 100644 node_modules/hasown/CHANGELOG.md create mode 100644 node_modules/hasown/LICENSE create mode 100644 node_modules/hasown/README.md create mode 100644 node_modules/hasown/index.d.ts create mode 100644 node_modules/hasown/index.js create mode 100644 node_modules/hasown/package.json create mode 100644 node_modules/hasown/tsconfig.json create mode 100644 node_modules/math-intrinsics/.eslintrc create mode 100644 node_modules/math-intrinsics/.github/FUNDING.yml create mode 100644 node_modules/math-intrinsics/CHANGELOG.md create mode 100644 node_modules/math-intrinsics/LICENSE create mode 100644 node_modules/math-intrinsics/README.md create mode 100644 node_modules/math-intrinsics/abs.d.ts create mode 100644 node_modules/math-intrinsics/abs.js create mode 100644 node_modules/math-intrinsics/constants/maxArrayLength.d.ts create mode 100644 node_modules/math-intrinsics/constants/maxArrayLength.js create mode 100644 node_modules/math-intrinsics/constants/maxSafeInteger.d.ts create mode 100644 node_modules/math-intrinsics/constants/maxSafeInteger.js create mode 100644 node_modules/math-intrinsics/constants/maxValue.d.ts create mode 100644 node_modules/math-intrinsics/constants/maxValue.js create mode 100644 node_modules/math-intrinsics/floor.d.ts create mode 100644 node_modules/math-intrinsics/floor.js create mode 100644 node_modules/math-intrinsics/isFinite.d.ts create mode 100644 node_modules/math-intrinsics/isFinite.js create mode 100644 node_modules/math-intrinsics/isInteger.d.ts create mode 100644 node_modules/math-intrinsics/isInteger.js create mode 100644 node_modules/math-intrinsics/isNaN.d.ts create mode 100644 node_modules/math-intrinsics/isNaN.js create mode 100644 node_modules/math-intrinsics/isNegativeZero.d.ts create mode 100644 node_modules/math-intrinsics/isNegativeZero.js create mode 100644 node_modules/math-intrinsics/max.d.ts create mode 100644 node_modules/math-intrinsics/max.js create mode 100644 node_modules/math-intrinsics/min.d.ts create mode 100644 node_modules/math-intrinsics/min.js create mode 100644 node_modules/math-intrinsics/mod.d.ts create mode 100644 node_modules/math-intrinsics/mod.js create mode 100644 node_modules/math-intrinsics/package.json create mode 100644 node_modules/math-intrinsics/pow.d.ts create mode 100644 node_modules/math-intrinsics/pow.js create mode 100644 node_modules/math-intrinsics/round.d.ts create mode 100644 node_modules/math-intrinsics/round.js create mode 100644 node_modules/math-intrinsics/sign.d.ts create mode 100644 node_modules/math-intrinsics/sign.js create mode 100644 node_modules/math-intrinsics/test/index.js create mode 100644 node_modules/math-intrinsics/tsconfig.json create mode 100644 node_modules/mime-db/HISTORY.md create mode 100644 node_modules/mime-db/LICENSE create mode 100644 node_modules/mime-db/README.md create mode 100644 node_modules/mime-db/db.json create mode 100644 node_modules/mime-db/index.js create mode 100644 node_modules/mime-db/package.json create mode 100644 node_modules/mime-types/HISTORY.md create mode 100644 node_modules/mime-types/LICENSE create mode 100644 node_modules/mime-types/README.md create mode 100644 node_modules/mime-types/index.js create mode 100644 node_modules/mime-types/package.json create mode 100644 node_modules/proxy-from-env/.eslintrc create mode 100644 node_modules/proxy-from-env/.travis.yml create mode 100644 node_modules/proxy-from-env/LICENSE create mode 100644 node_modules/proxy-from-env/README.md create mode 100644 node_modules/proxy-from-env/index.js create mode 100644 node_modules/proxy-from-env/package.json create mode 100644 node_modules/proxy-from-env/test.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 test.txt diff --git a/.DS_Store b/.DS_Store index 4c3be68a825a8de5664e6b14ae1e8ac3fe9fb47f..69c814346902536c25947a853d6ebad41d57b3d9 100644 GIT binary patch delta 1285 zcmZn(Xi1P~U|?W$DortDV9)?EIe-{M3-B;7uy8RjC`^<$V6@yAAjdxWo|HI863eUw zD-R!YoV-y=L?kyq#U&{xKMAA_Sz@xKG!L`Z6ottfq(mpjN{a)HVqgSfAmHHMEXX0o zvRRGiDKn$=WJMXJ&3Xd6SeUoeUYfjL)MT=}C=Z)OkiB~0;mL-gP6(#iFgQHIRDta146gK&Mu?-)%t4L`T&jc^iclQL5Wp~*M?#{WrEMlK?ipBsE=y;~ zWGF$lu~8=o7!}}PLXt-W3pROVOIVfzO$PZoi6If_?`&W+WENY%Fxf^@VzZ9qQbrav*7Av<)HnI16c0+OBQ`mjaEMQL z+z50P&*WTo2?-SMy70DZ+VIYnjW0KL)^!{i~w1E BKZyVU delta 664 zcmZokXbF&KU|?W$DortDU{C-uIe-{M3ve?quy8RjNKBMBU^LtqAjdxWpRzKGgtPFy z$v>54L~`?8T#|C~lR#QDbsCnK96II*lF-l1Pr;A?D&k>CV<=+CXUJnH0rD6aK?G1M z_vSzeahA>MJWrSz#V2o6QQE90u#1Ix&74b<_lufLmKWt=)16xcG<~w6s1t%|HhH}$ zFVjYc$@@fIHt!PSWMY(@JV!yIo*~w)2WTt{gC0XVLncEBvMYP<+wq9*Jm!chk8mtD z`GO3?;N<+=0+3r7(m#Mmc7`N|M22LBY=%^zXHs&~kyJ1X@pMi$QiS>(*mSWR|R7MWbh&cm_gXEP)efdatbMK}yuV)99L z9%f~kg2@ibqLbe$n-Go=6r+%1iXYi?()|}UZ%~n7ocuw=Pyk^yJnYc|oRvwE6%-i2 qv;s^g46aD&g?qCg$9v|<{5rlIOpxTHF*!kJ=Hy;gYa$J2VgdlR+qR1U diff --git a/.cursor/rules/.cursorrules b/.cursor/rules/.cursorrules new file mode 100644 index 0000000..f57ec0c --- /dev/null +++ b/.cursor/rules/.cursorrules @@ -0,0 +1,107 @@ +Вы — эксперт в разработке веб-приложений с использованием **Python, FastAPI, SQLAlchemy, Next.js, React, TypeScript, Tailwind CSS** и **Shadcn UI**. + +### Ключевые принципы + +- Пишите лаконичные технические ответы с точными примерами как на Python, так и на TypeScript. +- Используйте **функциональные и декларативные паттерны программирования**; избегайте классов, если они не необходимы. +- Предпочитайте **итерацию и модуляризацию** вместо дублирования кода. +- Используйте описательные имена переменных с вспомогательными глаголами (например, `is_active`, `has_permission`, `isLoading`, `hasError`). +- Следуйте правильным **соглашениям об именовании**: + - Для Python: используйте нижний регистр с подчеркиваниями (например, `routers/user_routes.py`). + - Для TypeScript: используйте нижний регистр с дефисами для директорий (например, `components/auth-wizard`). + +### Структура проекта + +- **Фронтенд**: + - **Язык**: TypeScript + - **Фреймворк**: Next.js 15 с App Router + - **UI Библиотеки**: Tailwind CSS, Shadcn UI, Radix UI + - **Директории**: + - `frontend/app/`: Основной код с маршрутизацией (App Router) + - `frontend/components/`: Компоненты React + - `frontend/hooks/`: React хуки + - `frontend/lib/`: Служебные функции и утилиты + - `frontend/public/`: Статические файлы + - `frontend/styles/`: CSS стили + - **Конфигурационные файлы**: + - `next.config.mjs` + - `tsconfig.json` + - `tailwind.config.ts` + - `postcss.config.mjs` + +- **Бэкенд**: + - **Язык**: Python + - **Фреймворк**: FastAPI + - **База данных**: PostgreSQL + - **ORM**: SQLAlchemy 2.0 + - **Директории**: + - `backend/app/`: Основной код + - `models/`: Модели базы данных + - `repositories/`: Репозитории для работы с данными + - `schemas/`: Pydantic схемы + - `services/`: Бизнес-логика + - `routers/`: Endpoints API + - `backend/uploads/`: Загруженные файлы + - **Конфигурационные файлы**: + - `alembic.ini`: Конфигурация миграций + - `.env`: Переменные окружения + +### Стиль кода и структура + +**Бэкенд (Python/FastAPI)**: + +- Используйте `def` для чистых функций и `async def` для асинхронных операций. +- **Типизация**: Используйте аннотации типов для всех функций. Предпочитайте Pydantic-модели для валидации данных. +- **Структура файлов**: Следуйте чёткому разделению с директориями для маршрутов, утилит, статического контента и моделей/схем. +- **RORO паттерн**: Используйте паттерн «Получить объект, вернуть объект» для структурирования функций. +- **Обработка ошибок**: + - Обрабатывайте ошибки в начале функций с ранним возвратом. + - Используйте защитные условия и избегайте глубоко вложенных условий. + - Реализуйте правильное логирование и пользовательские типы ошибок. + +**Фронтенд (TypeScript/React/Next.js)**: + +- **TypeScript**: Используйте TypeScript для всего кода. Предпочитайте интерфейсы типам. Избегайте перечислений; используйте объекты вместо них. +- **Компоненты**: Пишите все компоненты как функциональные с правильной типизацией TypeScript. +- **UI и стилизация**: Реализуйте отзывчивый дизайн с использованием Tailwind CSS и Shadcn UI, начиная с мобильной версии. +- **Рендеринг**: Используйте серверные и клиентские компоненты Next.js правильно: + - Предпочитайте серверные компоненты, где это возможно + - Используйте директиву `"use client"` только для компонентов, требующих клиентских возможностей + - Оборачивайте клиентские компоненты в `Suspense` для улучшения производительности + +### Оптимизация производительности + +**Бэкенд**: + +- **Асинхронные операции**: Минимизируйте блокирующие операции ввода-вывода, используя асинхронные функции. +- **Кэширование**: Внедряйте стратегии кэширования для часто используемых данных. +- **Ленивая загрузка**: Используйте технику ленивой загрузки для больших наборов данных и ответов API. + +**Фронтенд**: + +- **Компоненты React**: Предпочитайте серверный рендеринг и оптимизируйте клиентский рендеринг. +- **Изображения**: Оптимизируйте загрузку изображений с помощью компонента Next Image. +- **Метрики**: Оптимизируйте Core Web Vitals (LCP, CLS, FID). + +### Проектные соглашения + +**Бэкенд**: + +1. Следуйте **принципам проектирования RESTful API**. +2. Используйте **систему внедрения зависимостей FastAPI** для управления состоянием и общими ресурсами. +3. Используйте **SQLAlchemy 2.0** для функций ORM. +4. Обеспечьте правильную настройку **CORS** для локальной разработки. +5. Реализуйте надлежащую аутентификацию и авторизацию для защиты API. + +**Фронтенд**: + +1. Следуйте рекомендациям Next.js по использованию серверных и клиентских компонентов. +2. Ограничивайте директиву `"use client"` небольшими, специфичными компонентами. +3. Используйте хуки React эффективно, избегая ненужных рендеров. +4. Реализуйте интернационализацию для поддержки русского языка. + +### Тестирование и развертывание + +- Реализуйте **юнит-тесты** как для фронтенда, так и для бэкенда. +- Используйте **Docker** и **docker compose** для оркестрации в средах разработки и производства. +- Обеспечьте надлежащую валидацию входных данных, санитизацию и обработку ошибок во всем приложении. diff --git a/.cursor/rules/fastapinextjs.mdc b/.cursor/rules/fastapinextjs.mdc new file mode 100644 index 0000000..9645761 --- /dev/null +++ b/.cursor/rules/fastapinextjs.mdc @@ -0,0 +1,131 @@ +--- +description: +globs: +alwaysApply: true +--- +Вы — эксперт в разработке веб-приложений с использованием **Python, FastAPI, SQLAlchemy, Next.js, React, TypeScript, Tailwind CSS** и **Shadcn UI**. + +### Ключевые принципы + +- Пишите лаконичные технические ответы с точными примерами как на Python, так и на TypeScript. +- Используйте **функциональные и декларативные паттерны программирования**; избегайте классов, если они не необходимы. +- Предпочитайте **итерацию и модуляризацию** вместо дублирования кода. +- Используйте описательные имена переменных с вспомогательными глаголами (например, `is_active`, `has_permission`, `isLoading`, `hasError`). +- Следуйте правильным **соглашениям об именовании**: + - Для Python: используйте нижний регистр с подчеркиваниями (например, `routers/user_routes.py`). + - Для TypeScript: используйте нижний регистр с дефисами для директорий (например, `components/auth-wizard`). + +- никогда не запускай сервера бекенд и фронтенд, я сам это делаю! +- комментируй что ты делаешь + +### Структура проекта + +- **Фронтенд**: + - **Язык**: TypeScript + - **Фреймворк**: Next.js 15 с App Router + - **UI Библиотеки**: Tailwind CSS, Shadcn UI, Radix UI + - **Директории**: + - `frontend/app/`: Основной код с маршрутизацией (App Router) + - `frontend/components/`: Компоненты React + - `frontend/hooks/`: React хуки + - `frontend/lib/`: Служебные функции и утилиты, также работа с api бекенда + - `frontend/public/`: Статические файлы + - `frontend/styles/`: CSS стили + - **Конфигурационные файлы**: + - `next.config.mjs` + - `tsconfig.json` + - `tailwind.config.ts` + - `postcss.config.mjs` + + - `frontend/lib/`: Служебные функции и утилиты, также работа с api бекенда + api.ts - Основной файл для работы с API. Содержит базовую функцию fetchApi, которая выполняет HTTP-запросы и обрабатывает ответы сервера. Также определяет основные интерфейсы для работы с API. + auth.ts - Модуль для аутентификации пользователей. Содержит функции для входа, регистрации, выхода из системы, сброса пароля. + users.ts - Модуль для работы с данными пользователей. Содержит функции для получения профиля, обновления данных пользователя, управления адресами. + cart.ts - Модуль для работы с корзиной. Позволяет получать состояние корзины, добавлять, обновлять и удалять товары из корзины. + catalog.ts - Большой модуль для работы с каталогом товаров на стороне пользователя. Содержит функции для получения товаров, категорий, коллекций и работы с ними. + catalog-admin.ts - Модуль для работы с каталогом товаров на стороне администратора. Содержит функции для управления категориями и коллекциями. + orders.ts - Модуль для работы с заказами. Содержит функции для получения списка заказов, создания новых заказов, обновления статуса и т.д. + analytics.ts - Модуль для работы с аналитикой. Содержит функции для логирования событий, получения отчетов и отслеживания пользовательской активности. + utils.ts - Вспомогательные функции для форматирования данных, работы с датами, ценами и другими общими задачами. + auth.tsx - React-компоненты для аутентификации (контекст, провайдеры и т.д.). + + +- **Бэкенд**: + - **Язык**: Python + - **Фреймворк**: FastAPI + - **База данных**: PostgreSQL + - **ORM**: SQLAlchemy 2.0 + - **Директории**: + - `backend/app/`: Основной код + - `models/`: Модели базы данных + - `repositories/`: Репозитории для работы с данными + - `schemas/`: Pydantic схемы + - `services/`: Бизнес-логика + - `routers/`: Endpoints API + - `backend/uploads/`: Загруженные файлы + - `backend/docs/`: документация проекта + + - **Конфигурационные файлы**: + - `alembic.ini`: Конфигурация миграций + - `.env`: Переменные окружения + + +### Стиль кода и структура + +**Бэкенд (Python/FastAPI)**: + +- Используйте `def` для чистых функций и `async def` для асинхронных операций. +- **Типизация**: Используйте аннотации типов для всех функций. Предпочитайте Pydantic-модели для валидации данных. +- **Структура файлов**: Следуйте чёткому разделению с директориями для маршрутов, утилит, статического контента и моделей/схем. +- **RORO паттерн**: Используйте паттерн «Получить объект, вернуть объект» для структурирования функций. +- **Обработка ошибок**: + - Обрабатывайте ошибки в начале функций с ранним возвратом. + - Используйте защитные условия и избегайте глубоко вложенных условий. + - Реализуйте правильное логирование и пользовательские типы ошибок. + +**Фронтенд (TypeScript/React/Next.js)**: + +- **TypeScript**: Используйте TypeScript для всего кода. Предпочитайте интерфейсы типам. Избегайте перечислений; используйте объекты вместо них. +- **Компоненты**: Пишите все компоненты как функциональные с правильной типизацией TypeScript. Создавай компоненты где они нужны +- **UI и стилизация**: Реализуйте отзывчивый дизайн с использованием Tailwind CSS и Shadcn UI, начиная с мобильной версии. +- **Рендеринг**: Используйте серверные и клиентские компоненты Next.js правильно: + - Предпочитайте серверные компоненты, где это возможно + - Используйте директиву `"use client"` только для компонентов, требующих клиентских возможностей + - Оборачивайте клиентские компоненты в `Suspense` для улучшения производительности + +### Оптимизация производительности + +**Бэкенд**: + +- **Асинхронные операции**: Минимизируйте блокирующие операции ввода-вывода, используя асинхронные функции. +- **Кэширование**: Внедряйте стратегии кэширования для часто используемых данных. +- **Ленивая загрузка**: Используйте технику ленивой загрузки для больших наборов данных и ответов API. + +**Фронтенд**: + +- **Компоненты React**: Предпочитайте серверный рендеринг и оптимизируйте клиентский рендеринг. +- **Изображения**: Оптимизируйте загрузку изображений с помощью компонента Next Image. +- **Метрики**: Оптимизируйте Core Web Vitals (LCP, CLS, FID). + +### Проектные соглашения + +**Бэкенд**: + +1. Следуйте **принципам проектирования RESTful API**. +2. Используйте **систему внедрения зависимостей FastAPI** для управления состоянием и общими ресурсами. +3. Используйте **SQLAlchemy 2.0** для функций ORM. +4. Обеспечьте правильную настройку **CORS** для локальной разработки. +5. Реализуйте надлежащую аутентификацию и авторизацию для защиты API. + +**Фронтенд**: + +1. Следуйте рекомендациям Next.js по использованию серверных и клиентских компонентов. +2. Ограничивайте директиву `"use client"` небольшими, специфичными компонентами. +3. Используйте хуки React эффективно, избегая ненужных рендеров. +4. Реализуйте интернационализацию для поддержки русского языка. + +### Тестирование и развертывание + +- Реализуйте **юнит-тесты** как для фронтенда, так и для бэкенда. +- Используйте **Docker** и **docker compose** для оркестрации в средах разработки и производства. +- Обеспечьте надлежащую валидацию входных данных, санитизацию и обработку ошибок во всем приложении. diff --git a/backend/alembic/__pycache__/env.cpython-310.pyc b/backend/alembic/__pycache__/env.cpython-310.pyc index d2c8974714eb7b51b439ce43cb48329fcc0474f5..0fa48a2e4a495224077b324b0aea4561d297048b 100644 GIT binary patch delta 20 acmcc4f1RH@pO=@50SL~my0($~3_Aclat25M delta 20 acmcc4f1RH@pO=@50SJoak8I>V!wvv9Sp`r4 diff --git a/backend/alembic/versions/9773b0186faa_add_size_table_and_update_product_.py b/backend/alembic/versions/9773b0186faa_add_size_table_and_update_product_.py new file mode 100644 index 0000000..b86b6d0 --- /dev/null +++ b/backend/alembic/versions/9773b0186faa_add_size_table_and_update_product_.py @@ -0,0 +1,57 @@ +"""Add size table and update product structure + +Revision ID: 9773b0186faa +Revises: ef40913679bd +Create Date: 2025-03-16 20:30:39.057254 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '9773b0186faa' +down_revision: Union[str, None] = 'ef40913679bd' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('sizes', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('code', sa.String(), nullable=False), + sa.Column('description', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('code') + ) + op.create_index(op.f('ix_sizes_id'), 'sizes', ['id'], unique=False) + op.add_column('product_variants', sa.Column('size_id', sa.Integer(), nullable=False)) + op.create_foreign_key(None, 'product_variants', 'sizes', ['size_id'], ['id']) + op.drop_column('product_variants', 'discount_price') + op.drop_column('product_variants', 'name') + op.drop_column('product_variants', 'price') + op.add_column('products', sa.Column('price', sa.Float(), nullable=False)) + op.add_column('products', sa.Column('discount_price', sa.Float(), nullable=True)) + op.add_column('products', sa.Column('care_instructions', sa.JSON(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('products', 'care_instructions') + op.drop_column('products', 'discount_price') + op.drop_column('products', 'price') + op.add_column('product_variants', sa.Column('price', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=False)) + op.add_column('product_variants', sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=False)) + op.add_column('product_variants', sa.Column('discount_price', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True)) + op.drop_constraint(None, 'product_variants', type_='foreignkey') + op.drop_column('product_variants', 'size_id') + op.drop_index(op.f('ix_sizes_id'), table_name='sizes') + op.drop_table('sizes') + # ### end Alembic commands ### diff --git a/backend/alembic/versions/__pycache__/2325dd0f1bd5_init.cpython-310.pyc b/backend/alembic/versions/__pycache__/2325dd0f1bd5_init.cpython-310.pyc index db598a6a026c0f1ff20d1bf2fa0065ffe7bf8f09..d1865ac172592bc884224803dd18de92df0ec223 100644 GIT binary patch delta 20 acmX@Wc7TmLpO=@50SL~my0($qloMNfFjXi+q+EcP#cF4yth^u0 z>{77^8%RIUORK-2C?KMzT#BMW(H2eqgB~ap=wYtCG(i7=qKBeyW>+iHO`1!&;^WMl z_c=4a_f}!KY)J5t|MJ(P)p<$!8=p*mRG7R2-{{vs_9ZO!B#f}^Az$vvzS2_=pDUi~ z=XyCYRz0nk2VTz8{X(xGc$%mAM$dq8zE>nAQpWn*5-#*AL?I=t9?FXn@C@Loy(;Gs znUoe`cBqJzqFAYY$w~=UW^n~qf1>tgU{u31Fq*|`N2<>af4YgW8M#AZ#`b|nOgq5l zppWgCn0*@JffJiiOyOrhiDB%K6E||hz-(O1=i&vD<4oha6Yg+ z`+#^6Gcf6s07q6BFpUyOGH`e#mmhw%W%zEvH~Kr0q*yvf7{&6jg5_8~S4R?7uzIEl zP7XM^DUSAEoP5gBGpz#XYFNj{8Q49~F&ZHxrLzS-dnLb=&u2keNx9cDnYoda#&BK4w+MdterEBd8aG}l zzmV{ozf@k=Jf6qb@nW+7!qOX90uI89kU#9f2+#&QGtY1Qgwz7a%%=JCac*Kf!^c95ivWuU-j#^Z6GAOa4()*#(+b=xW+ZsyTCC{4u!LL7#b81k1TNr#=_wW?mg`d& z&{4r|dck%JX568b5|LNlAum1u$ybY-7axP>@5i5UDAb;o0c}*{n)6So>)Z77`{Z;BkPuVb4PsV< zh5}fc;9PnDl#mw;9Wukl*m4plxhGx-fK=b>?6#SHL}H7hiRQS2Jb6K!K}?tyIksm* zAWrD}Zp=!y7X!Rg6SHXshan~IQD8kMr%*6x*iQxOD*c8q7bUHYx1b2hLT?6O4`m{< zJy8r`Q$LaDLlFJfj~e?>LZZgdecsp(oq|tRy1%N5?N6U z-WvzD^Bfvo!}f@O;5rR%omYv*WD~V``r7`J)|3TQQ%Xt+)ewCP zj7;@i85jllioW{~7)dT)^QQ~48kQ`K7)5V(P0sE-ph_!#kGmCJ~5V)@o^b+DtHEZ^(>w{ zOZ2MHlTg}w=G*ip;k5=XpyJ%K(_wg++O25`Ul1rTk7R=LUzAYHly zbol2CW?uor$2#G7UR3BB5LQjmds$TII_DaKE2;>sUok`kby;AX z-sd(rgcGvC#R~l0R6vPe{)nI2E%_$8m4F86dQC2&=ogsU7url%fg{! zSxkf7fHFuqYN!H)k=u~Ps5 literal 0 HcmV?d00001 diff --git a/backend/alembic/versions/__pycache__/ef40913679bd_update_products.cpython-310.pyc b/backend/alembic/versions/__pycache__/ef40913679bd_update_products.cpython-310.pyc index 16b070d1f12708017ffbd589eb404fa3441e77eb..1365adf2daeaa98b4dab09a5e3621b8493a74f91 100644 GIT binary patch delta 20 acmbQoKaZa~pO=@50SL~my0(#fGCKe?iUpkj delta 20 acmbQoKaZa~pO=@50SG!Zj%?(f%nkrAK?KAA diff --git a/backend/app/__pycache__/__init__.cpython-310.pyc b/backend/app/__pycache__/__init__.cpython-310.pyc index 355953ad89a7e456a1307e3989eb6f919e52900a..56882f0ae5b0414545e37ed2e1d97d745e770637 100644 GIT binary patch delta 29 jcmZ3@xR#MSpO=@50SL~mx;By9hB08Ghdra-#5Pp`Z~F)H delta 27 hcmZ3>xSEkWpO=@50SE$C9-PQ+!{|5B!+v6?3IJL>2QUBt diff --git a/backend/app/__pycache__/config.cpython-310.pyc b/backend/app/__pycache__/config.cpython-310.pyc index f44934074393781c16f692aa2c1c90512ed620d1..6d7f6cc1b5460e62fb58c7be1a6c2cb4d85d6170 100644 GIT binary patch delta 264 zcmbQkH;<1ypO=@50SL~my0(#9oSE^~WM$@Aj8T*KF&hcqV$Lc^zr~VOkeYsrxgan7 z)@DW)T}Gg!KC3*p0#H*Ci1_6z>% delta 247 zcmbQoH;0cqpO=@50SL~CAKAz)&deA!S($kj?H9ftrdy#4n%8k*xNUXR)dZ%LBQ7nleR_AUP=zAwBsLtGxioh9Yht zaf>-KucU})vLc&^tpG?+5JU)r2oVq=3L?ZnggA(h01+TV!4@GAa+8bL9A%Y&GEssB ol_`mNC7H?b#i=DFnR)5OMNB~PTaz!a$q2w53DGMz`45{C00`$Z%m4rY diff --git a/backend/app/__pycache__/core.cpython-310.pyc b/backend/app/__pycache__/core.cpython-310.pyc index 97aa23b7c85c7e5acacb42ddb5c324121f6f03fc..31943ba4fcc1d0bfab0ee915ba4167a5bd429c3c 100644 GIT binary patch delta 606 zcmaDP^+bw0pO=@50SL~my0(#fAroWNCS#E* zTqRhK^yI57N{s50f3Tba8hx16+f)OjKodwrahBxAr{*Q+r=&))rB)PV7NtgUL-;B2 zS>+`tmO8T;FdANF4@VCI3w9CKzc1FJ94RUBL`FwmmZ@hP|+lNSD*q-mMD(Q;`qdr z+|0Zpevl3UAQ2_x5fTy*Z(?8^@8%!mR03rl0`9z+nCJ@Bq%m{HMco1ARlul zNJg=zB^H+?0>h0DB!w_?atx2OP!v~UL4jU!eqLH;dXX^5rpcW=`hwy>)-4vNM4*Rc mK)RGBpX8AP=^-) delta 611 zcmaDN^+<|4pO=@50SHdNI=GR0Ars@R$!nP^*`$FYzq}^vFxyYgWmadDojjG<3@CMm zIhIj;vKEW1s3K57krIdiDTNR+lVeyE7}X}%vY4re14T8Nid2BqEtZVL;tWm3B6YY* zupXJo*IASpH7EaKIR!NOD66-r7D$0Mkci?e$&XLXOU_S8y~UPVQIJ`b8pRFar^IKK zm!Mec%4Wc5zPXHzlab8?WPs`9R(2gp3n23rdqHAlPJUtviuzOR`fN@hg;JCMv!CI% z1Tn2Zg!SZW9QteyAg0q~ZcZ&P7a&uUy$EDfkra@K5=|~jO-aow$xO^Cj!&&fPAw?O z%+D)w1j^lFP0dZr%qartxy4dioLYopX+5VqqsQdqoMmh_Ak%CoJ9DXVBL`gxmmZ@p zP=V~^16-xjoH|Py)naaY_XG oKo+D+W%6krIb$^tQxim(g9vc=d4O2HAOdVN!a30BmErXO0Iwa96aWAK diff --git a/backend/app/__pycache__/main.cpython-310.pyc b/backend/app/__pycache__/main.cpython-310.pyc index 2973c1c0b39264742255dbf214de07053770034b..b84afa7d7dd8dd4eb41133ef0c1807ca3d109e75 100644 GIT binary patch delta 20 acmZ3-yN;JTpO=@50SL~my0(#fF&h9j!3D?w delta 20 acmZ3-yN;JTpO=@50SGpqJGha1F&h9ja|OHr diff --git a/backend/app/models/__pycache__/__init__.cpython-310.pyc b/backend/app/models/__pycache__/__init__.cpython-310.pyc index a091f91d9dac519cd54a35171fbb208c81629382..12caadf855dab3b9509228ca9d3dbfb2cf81d49f 100644 GIT binary patch delta 29 jcmdnQxP_5BpO=@50SL~mx;By9hB17ihdra-#5NrOamfe| delta 27 hcmdnOxQUTFpO=@50SE$C9-PQ+!x%cz!+v6?HUL}T2TT9} diff --git a/backend/app/models/__pycache__/catalog_models.cpython-310.pyc b/backend/app/models/__pycache__/catalog_models.cpython-310.pyc index f490f20fef980eaf38b50e83cd24716be35f2034..1b8d227a936b895e981eafec0b3d24ca67451352 100644 GIT binary patch literal 3791 zcmb7HTaVku6(&VWq9}@@v^P6x8oTZ#O6*lz6bVqIi5mx-I0iOFz3l`0z|fponJ_Q% z4C!PSc?jS>1@M2^JR0a@{z_V4Ui;L);HQ3PC}|b%+VM)@*>ld!h%@tj=d$Hs;2QY+ z@SlIr?u-rNzhta`Y#2B3$nPPT!OYCa&CtwSVJo*nE4M>CZ-?!?6L#`$*v*~L$$MeX zq`9rk&HG_r>sIFFgK(gAJM;5lI5dq<4Ay3ye;TaAhmWl=fZb&dY)9K8*gfXLcC|f* z-De(bPum-?2h4}ZMWur3n%`%x@;LT_CEbYR@XBfo{d!@*$Koh@fQx9S1>;}sJvEh6)L9na%lK1Eb?PF0SaSjD7-ACw z<6XuN<2tKoYK5CSE(;Fbms~vJB3c_Qi+av*zpDEeQL;LzlzX}bT5>N=9z^qUUgNI0 z+@EYICyI(V=TW5GD9W)YBi)OlhjpASMg~z-(f%4!v}kV@gleTs5TTV#L!w7&pK+Op zbgpl}mRUU$gqG^1GKz68*s=p#c;vK-@=NSdaBPP~;EdZGfOOHP8P2>piF|5^-_kk~ z&;Bv}8%{5$$LWLV$7NFIyr|?9hn|Tzms2LVl=#8JQbe*&5-uZIfrC>zKQGucp3kQ^ zEYIXLiK{p(XLNR$yYnOA;|;V$N%!vL9AjKBMv%%@$E}-9`fy*RbC-DYEIFR+d(^(Uc zUhurEcqCH>UJ?L;ABs0IS2>G`N8&2X{mCV9jeh5sBz{HW*CbYS6Tcyo_$J;W@iqzK zoS2a4La5$67T`jJ-4W}=J0w}|LBBtb7QLNE^N50=f&{5?jh$SD0 z4dWFf0#naA!-+Ol+@z&nLtKCpHn8m=gApT$ASI;eWXF7azP=z!JNnDV+za0>LI|XL|Ne$JlmM-0^psKO8}U{_wpGpf%+PM9i`f2 zKJ=eKA1?Gapa*Qk#%u$>_;XmBE9*^IDB&2}#@H3M16o|tk*K+UCfs#=AN!{jL{iZI z0T=rmO*Hp4D|BWQ?_-MUE?_(!$60p$3X&_Y_>EG`@5cow_X|BIiDeQaFLeIOAEo?D z~!~P}f8rszQxtRilu7tfop) zPYD`&m^;w)Jq>|As2rS(KxHB=1po!csh2vZ4UXPvQIEEuk3eOrP1|e?f^KLwi4SoB z4MCrwi_*Ofv9T#m$Bs^Fut6D}#;9@&#JF)@jcO>rN264CbgI~&?7RxUbd7PB2?{Le z(wm6^RF*7e|3?(77^s9xtrO0)E60SQj-Zah*I@sL= zEv*>PFH+0eWMQg%4Z(>NdQ0aKOF8d1&He`zCA!nSZs?=50xK8>qreX?Z;t*C2V*$! literal 3296 zcmb`JTW=dh6vw?@U)F1TeM_9QR1oepv@r;Q#H|W#6;vTb6%9Nr53B9Y#9d`C?#yo5 zy@Y-JFa7tzAmvUtNm1BHSQdmZU=UqS+Ff_cVRb}4cpds4|bEaV7Ij0 zhuvllY)9Jz*11<2b^pdHOCw9wZlzHkC#rrY$@qi|RlApoFqx?8W|aDws^3i0i2I4M zH&emGN%9TfSJrJmubd(KuL_DCKsAh1g%k7i0YEDHM`(oeQ zg$t@-!uaFO6GK@^9!38Bh@Y6MmM7uEoQodzB?b`auQR^m=TSyOGx+QvO*nK%axW>t18qb8l*NEmw^bU+5;6ClOkqNyR>bQD`BT+oFS= zY>GalAYVLb&pX!<`XP0!lDJIb3WVF1`ThB*5ug`5PBZSwkbz4IfZ#jgRg6{EY~a3F zgSjs2Iyh-9M5^s|@#ZA0JCh;cTB{3pF%!#Wc>JX|i^#xe)usWhnyhq}cH}O81 z*GOC^p$V%MQ^Y#8oFZ0eA5hze5G!~jZPh9jJP-~2QzE*C9(6Gje`4zY!o*^psv=Wa zhsI&S16d8wLix^gyI`RQLTnJyKOTUPf`w;WTcBW>50T*w<`5CkJ2QP1dYAQBpAGQF zOR$zst;?{MwKYWFD{KWEt?IC9N1kCv!*bxv(~%^CK7w1GAxJw?1EG(Za%QRQdtZcp zf_gGb2nT&Ximt8U(DIC5PsQ|spNz`lb-Yp4178L{c&mNO_d@XAGtdnp0L zIjg8e4^>p6mPR?ytIX0hb)LhD`r4n-IyhdM(YlP$|86B(hkS+ZBdh~`m36^gPkf4n zyWJTX-ctt_5I#ZK)y0sAE3z2~SjG%pV1+^2IjO9G`3Ci_L2QjKy$C5f3)xRsg0P?F zE7z2}xgcMwDlP&6R}Kqhkmg8N+IFibQb><;rk;B22E%7Cm;X0=d)d!&ntk^);tUR3)zpc^WMFS?j z!kdblOhX?vFBg$(`BCO&xSkdl7#kOu*#++6vwU7SXa{%kNGhcBa8M|Q#$`kAaBH-r zZ22(qqu>FL_ZNzu=7*>$xFEiYzt^`dXFg{=6|t^p?qVbQi>sD}JI{K6OOR;ME9jC_ nq*_WK`T*&LoClP$z9?>nH|VVBZCovBlFD7P+v)bY!=?T|RaV<- diff --git a/backend/app/models/__pycache__/content_models.cpython-310.pyc b/backend/app/models/__pycache__/content_models.cpython-310.pyc index a7ec9422394503ce782a9ed15a27ccbf320f6451..af03adc17d40a7e39b35d90aae34a7264ca28f82 100644 GIT binary patch delta 241 zcmZ3(yN;JTpO=@50SL~my0(#f3X@6{S8i%aVth$vNlt2%0GOSUTAW;zSx}OhpI5{I zR2nt;Fq1jADv(tKB7VhAW@WZ#)Z6UL{DP4&YO)Tio^2FYX>n>%d}4ZPUP%;3QEFOh zQ4tVvf^_pIrle$o3`@+3Pf09EEMfzh#0?^pK!oz->8whkaO1&t6sdt^)F+=~)n!zl s{D;*_EQ+tVFefo5IU_ZHV%7>9FClQ?!7C?uv%C8F{nR3PE2EhM0JX)7euN_-6*gJt3qjfms$-eqVP zHYDalV(ZSZ%hv;U z*_!3{gY}KaTWjlU?=y7DETs7LR6ns+S@ZCnm1m7V(?@|>qpoXQmi#n~|?S zTNQmgU)0~TdyF5xo?2!8qyjaw&)4^zisLblm9iy9wejAc_jo>`NRWI)b0$Wo4K}Eb z*Ruw@GeapT2&0IEltMPU5uL~41z-WV1Y9=Y`e9*-HT0W8{q7Y^T0j=K3KW2A02-k( zP%#+gr3%$hQqBx`NhK=m1!0^F`-z9;Z63AH0Py#htQLkV0Ax|qU~8d5GZ^4_=_K$UaXiEA@y8>&j^GUd z#zwgTbvt5Ww`rrdk-P;=YP794oq5*QiL>JIvV7SKd!20&?=%yNQ&A)R!C5?qGa&p( Ol=cA~|CG~n?#17>XP34B delta 762 zcmZ{iO-~a+7{@z>rOR#$0+j#_kw%Cq2Ji(?Y|>tU#F$`0iD$opB*gh|s}e1{*DPSRzGHF%s5i~+*aG!dh2c0VzYmYZTC20CJctnC$N{D>1B9rbzx1Z zA3g7wZoTfUvzy&AOX{0dW~J7pm1oa%UqS&V@q#9?>y*JdmGL`ca5B^soIF1Whzr5R zd>GIjI4i(iU=El!&}u8U#1_<>+^y65FlK=s-~o^W9s;PC27sc0?i13NO+gkGd6`K6 z$n&G58B0AP4#GwwjQ4++;F$u@xgKcvuOc2xFXHkb38){&!H!W??82cQl;rQdL~`7W zb~$M)P9zs(n^4LF%fKVxG2j9#2KvUo=V~jIJQ9D$b7c}$_1>OiRdsHEIISVuO(pfx zjJB>P{cV+vejRmhQ)60va*Aw6ojHrs7zUMqv~cwQU%r}jXMX|n Ccc_g3 diff --git a/backend/app/models/__pycache__/review_models.cpython-310.pyc b/backend/app/models/__pycache__/review_models.cpython-310.pyc index ef987bdf71c72485c373580225caa083ea1fdb8a..58f74532a03895d499799a806cf1fcc4a0daf61f 100644 GIT binary patch delta 118 zcmZ3$xrmcHpO=@50SL~my0($~7n69DNM><-S!z*cT4riWd_ieZazRu@hfI>A+tTB-sJVnO=3}e#f3SEImsERxs`hPMY%;F^KMOcXVDaZYXIvi(wyAD Gq5uF>d?7vn delta 144 zcmZ3)xqy>9pO=@50SJ0m9^A<-S!z*cT4riWd_ieZazaEE#%wF7D zKy^hR;#btg5;Z7J*EQn(WDEVnl(@xV albfGXnv-hB2;>!m)M_yBFajZy2r~d&A|-YJ diff --git a/backend/app/models/__pycache__/user_models.cpython-310.pyc b/backend/app/models/__pycache__/user_models.cpython-310.pyc index 9283a831bfcb21e8c1ca01f41c5c77781a16431e..830bcf9b37cd70daa2db5e7cc771299a24c558eb 100644 GIT binary patch delta 107 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 Jxtm5W`(Gell28Bu literal 13585 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 delta 957 zcmZ9L&rcIU6vt;~f3;KEf`EXOA1#WmMib)6$U((~gT^Qx#Hwj3yJDBJEwfvdWY#JM zZywBENu-I1XT#s%)x_(b^q?1S8cn>Y?~PE6ZN8s<^XB{ByxFE-7d~FeHL_Vw;Pd&_ zo8@m8p63eGd423Mv$%W0&D>!-580=2n#6AL6!1my3@yj+i?hJ7(uejUB_t%0Ncx0D zOtK&s(vW$YLml>vZBR+J_0Z_hZ8J1HOENFD!eEu|kVtb#q(g>_bIO%bu8eZ=uFH@H z>|?Fr^?~>sDVYk&YxBx6 zs2qdfNO}9aj7Iu>(1H{p{c!yE~#S9E^ zTM)bzZw$miGUP{fI@~K0lE=|YS%0*oAtHd@hi5mPg;yA#z#3VeD zY}Iju8w8bl&5zlk;kFTk)zD2c%?1SZ%2LB|6Kko_@m zpb1f#w*psG+|_EWp7aKHYt1HlcP}F5z+xYa*Cqzdajff){juSAXnM+Q<8m&32e%9{ zRM+_L1})rB6XI~<5#ljI&49-zhC12Kh!M=ICf6{p<5*$?lP&@W5%&?N5wnPUh!Tn4 zPTOrCVor6+l+2$6Q`bydfR)Zb-LLsW&v06R9NVR?{oUP*IOX5<{NC!{XAjgdYJSoC a#3meRGXZ}yB6gl0en9DF{OgEdrJ3J43f_PK diff --git a/backend/app/repositories/__pycache__/review_repo.cpython-310.pyc b/backend/app/repositories/__pycache__/review_repo.cpython-310.pyc index 3913f552ec3d36153ebe5dcf4465b0caec7021f6..a483185a7c50f3b049cea97e6226fd4f7353c11d 100644 GIT binary patch delta 20 acmcbpeNme`pO=@50SL~my0($~m?!{1fChX3 delta 20 acmcbpeNme`pO=@50SKy}9^A-%OcVe=GzL!q diff --git a/backend/app/repositories/__pycache__/user_repo.cpython-310.pyc b/backend/app/repositories/__pycache__/user_repo.cpython-310.pyc index 44a00c629a9fa5905da8674b6c1412ccf8ef8f07..1498564b6e6ec1165ff6c6724135fea53e3bfde6 100644 GIT binary patch delta 20 acmZ2ww91G(pO=@50SL~my0(#9UJ?L0Xa$)7 delta 20 acmZ2ww91G(pO=@50SKbz9o@(+F9`rPp9Kg2 diff --git a/backend/app/repositories/catalog_repo.py b/backend/app/repositories/catalog_repo.py index e2c0b6b..f241f74 100644 --- a/backend/app/repositories/catalog_repo.py +++ b/backend/app/repositories/catalog_repo.py @@ -5,13 +5,14 @@ from typing import List, Optional, Dict, Any import re from datetime import datetime -from app.models.catalog_models import Category, Product, ProductVariant, ProductImage, Collection +from app.models.catalog_models import Category, Product, ProductVariant, ProductImage, Collection, Size from app.schemas.catalog_schemas import ( CategoryCreate, CategoryUpdate, ProductCreate, ProductUpdate, ProductVariantCreate, ProductVariantUpdate, ProductImageCreate, ProductImageUpdate, - CollectionCreate, CollectionUpdate + CollectionCreate, CollectionUpdate, + SizeCreate, SizeUpdate ) @@ -380,32 +381,34 @@ def create_product(db: Session, product: ProductCreate) -> Product: if not product.slug: product.slug = generate_slug(product.name) - # Проверяем, что продукт с таким slug не существует - if get_product_by_slug(db, product.slug): + # Проверяем, что slug уникален + if db.query(Product).filter(Product.slug == product.slug).first(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Продукт с таким slug уже существует" + detail=f"Продукт с slug '{product.slug}' уже существует" ) # Проверяем, что категория существует if not get_category(db, product.category_id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Категория не найдена" + detail=f"Категория с ID {product.category_id} не найдена" ) - # Проверяем, что коллекция существует, если указана + # Проверяем, что коллекция существует, если она указана if product.collection_id and not get_collection(db, product.collection_id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Коллекция не найдена" + detail=f"Коллекция с ID {product.collection_id} не найдена" ) - # Создаем новый продукт db_product = Product( name=product.name, slug=product.slug, description=product.description, + price=product.price, + discount_price=product.discount_price, + care_instructions=product.care_instructions, is_active=product.is_active, category_id=product.category_id, collection_id=product.collection_id @@ -416,11 +419,11 @@ def create_product(db: Session, product: ProductCreate) -> Product: db.commit() db.refresh(db_product) return db_product - except IntegrityError: + except IntegrityError as e: db.rollback() raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Ошибка при создании продукта" + detail=f"Ошибка при создании продукта: {str(e)}" ) @@ -429,57 +432,72 @@ def update_product(db: Session, product_id: int, product: ProductUpdate) -> Prod if not db_product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Продукт не найден" + detail=f"Продукт с ID {product_id} не найден" ) - # Обновляем только предоставленные поля - update_data = product.dict(exclude_unset=True) - # Если slug изменяется, проверяем его уникальность - if "slug" in update_data and update_data["slug"] != db_product.slug: - if get_product_by_slug(db, update_data["slug"]): + if product.slug is not None and product.slug != db_product.slug: + if db.query(Product).filter(Product.slug == product.slug).first(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Продукт с таким slug уже существует" + detail=f"Продукт с slug '{product.slug}' уже существует" ) - # Если имя изменяется и slug не предоставлен, генерируем новый slug - if "name" in update_data and "slug" not in update_data: - update_data["slug"] = generate_slug(update_data["name"]) - # Проверяем уникальность сгенерированного slug - if get_product_by_slug(db, update_data["slug"]) and get_product_by_slug(db, update_data["slug"]).id != product_id: + # Если имя изменяется и slug не предоставлен, обновляем slug + if product.name is not None and product.name != db_product.name and product.slug is None: + product.slug = generate_slug(product.name) + # Проверяем, что новый slug уникален + if db.query(Product).filter(Product.slug == product.slug).first(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Продукт с таким slug уже существует" + detail=f"Продукт с slug '{product.slug}' уже существует" ) - # Проверяем, что категория существует, если указана - if "category_id" in update_data and update_data["category_id"] and not get_category(db, update_data["category_id"]): - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Категория не найдена" - ) + # Проверяем, что категория существует, если она изменяется + if product.category_id is not None and product.category_id != db_product.category_id: + if not get_category(db, product.category_id): + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Категория с ID {product.category_id} не найдена" + ) - # Проверяем, что коллекция существует, если указана - if "collection_id" in update_data and update_data["collection_id"] and not get_collection(db, update_data["collection_id"]): - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Коллекция не найдена" - ) + # Проверяем, что коллекция существует, если она изменяется + if product.collection_id is not None and product.collection_id != db_product.collection_id: + if product.collection_id and not get_collection(db, product.collection_id): + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Коллекция с ID {product.collection_id} не найдена" + ) - # Применяем обновления - for key, value in update_data.items(): - setattr(db_product, key, value) + # Обновляем поля + if product.name is not None: + db_product.name = product.name + if product.slug is not None: + db_product.slug = product.slug + if product.description is not None: + db_product.description = product.description + if product.price is not None: + db_product.price = product.price + if product.discount_price is not None: + db_product.discount_price = product.discount_price + if product.care_instructions is not None: + db_product.care_instructions = product.care_instructions + if product.is_active is not None: + db_product.is_active = product.is_active + if product.category_id is not None: + db_product.category_id = product.category_id + if product.collection_id is not None: + db_product.collection_id = product.collection_id try: db.commit() db.refresh(db_product) return db_product - except IntegrityError: + except IntegrityError as e: db.rollback() raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Ошибка при обновлении продукта" + detail=f"Ошибка при обновлении продукта: {str(e)}" ) @@ -514,26 +532,44 @@ def get_product_variants(db: Session, product_id: int) -> List[ProductVariant]: def create_product_variant(db: Session, variant: ProductVariantCreate) -> ProductVariant: # Проверяем, что продукт существует - if not get_product(db, variant.product_id): + db_product = get_product(db, variant.product_id) + if not db_product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Продукт не найден" + detail=f"Продукт с ID {variant.product_id} не найден" + ) + + # Проверяем, что размер существует + db_size = get_size(db, variant.size_id) + if not db_size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {variant.size_id} не найден" ) # Проверяем, что вариант с таким SKU не существует - if db.query(ProductVariant).filter(ProductVariant.sku == variant.sku).first(): + existing_variant = db.query(ProductVariant).filter(ProductVariant.sku == variant.sku).first() + if existing_variant: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Вариант с таким SKU уже существует" + detail=f"Вариант продукта с SKU {variant.sku} уже существует" + ) + + # Проверяем, что вариант с таким размером для этого продукта не существует + existing_size_variant = db.query(ProductVariant).filter( + ProductVariant.product_id == variant.product_id, + ProductVariant.size_id == variant.size_id + ).first() + if existing_size_variant: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Вариант продукта с размером ID {variant.size_id} уже существует для этого продукта" ) - # Создаем новый вариант продукта db_variant = ProductVariant( product_id=variant.product_id, - name=variant.name, + size_id=variant.size_id, sku=variant.sku, - price=variant.price, - discount_price=variant.discount_price, stock=variant.stock, is_active=variant.is_active ) @@ -543,11 +579,11 @@ def create_product_variant(db: Session, variant: ProductVariantCreate) -> Produc db.commit() db.refresh(db_variant) return db_variant - except IntegrityError: + except IntegrityError as e: db.rollback() raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Ошибка при создании варианта продукта" + detail=f"Ошибка при создании варианта продукта: {str(e)}" ) @@ -556,41 +592,73 @@ def update_product_variant(db: Session, variant_id: int, variant: ProductVariant if not db_variant: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Вариант продукта не найден" + detail=f"Вариант продукта с ID {variant_id} не найден" ) - # Обновляем только предоставленные поля - update_data = variant.dict(exclude_unset=True) - - # Если product_id изменяется, проверяем, что продукт существует - if "product_id" in update_data and update_data["product_id"] != db_variant.product_id: - if not get_product(db, update_data["product_id"]): + # Проверяем, что продукт существует, если ID продукта изменяется + if variant.product_id is not None and variant.product_id != db_variant.product_id: + db_product = get_product(db, variant.product_id) + if not db_product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Продукт не найден" + detail=f"Продукт с ID {variant.product_id} не найден" ) - # Если SKU изменяется, проверяем его уникальность - if "sku" in update_data and update_data["sku"] != db_variant.sku: - if db.query(ProductVariant).filter(ProductVariant.sku == update_data["sku"]).first(): + # Проверяем, что размер существует, если ID размера изменяется + if variant.size_id is not None and variant.size_id != db_variant.size_id: + db_size = get_size(db, variant.size_id) + if not db_size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {variant.size_id} не найден" + ) + + # Проверяем, что вариант с таким размером для этого продукта не существует + product_id = variant.product_id if variant.product_id is not None else db_variant.product_id + existing_size_variant = db.query(ProductVariant).filter( + ProductVariant.product_id == product_id, + ProductVariant.size_id == variant.size_id, + ProductVariant.id != variant_id + ).first() + if existing_size_variant: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Вариант с таким SKU уже существует" + detail=f"Вариант продукта с размером ID {variant.size_id} уже существует для этого продукта" ) - # Применяем обновления - for key, value in update_data.items(): - setattr(db_variant, key, value) + # Проверяем, что SKU уникален, если он изменяется + if variant.sku is not None and variant.sku != db_variant.sku: + existing_variant = db.query(ProductVariant).filter( + ProductVariant.sku == variant.sku, + ProductVariant.id != variant_id + ).first() + if existing_variant: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Вариант продукта с SKU {variant.sku} уже существует" + ) + + # Обновляем поля + if variant.product_id is not None: + db_variant.product_id = variant.product_id + if variant.size_id is not None: + db_variant.size_id = variant.size_id + if variant.sku is not None: + db_variant.sku = variant.sku + if variant.stock is not None: + db_variant.stock = variant.stock + if variant.is_active is not None: + db_variant.is_active = variant.is_active try: db.commit() db.refresh(db_variant) return db_variant - except IntegrityError: + except IntegrityError as e: db.rollback() raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Ошибка при обновлении варианта продукта" + detail=f"Ошибка при обновлении варианта продукта: {str(e)}" ) @@ -706,4 +774,110 @@ def delete_product_image(db: Session, image_id: int) -> bool: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Ошибка при удалении изображения продукта" + ) + + +# Функции для работы с размерами +def get_size(db: Session, size_id: int) -> Optional[Size]: + return db.query(Size).filter(Size.id == size_id).first() + + +def get_size_by_code(db: Session, code: str) -> Optional[Size]: + return db.query(Size).filter(Size.code == code).first() + + +def get_sizes(db: Session, skip: int = 0, limit: int = 100) -> List[Size]: + return db.query(Size).offset(skip).limit(limit).all() + + +def create_size(db: Session, size: SizeCreate) -> Size: + # Проверяем, что размер с таким кодом не существует + existing_size = get_size_by_code(db, size.code) + if existing_size: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Размер с кодом {size.code} уже существует" + ) + + db_size = Size( + name=size.name, + code=size.code, + description=size.description + ) + + try: + db.add(db_size) + db.commit() + db.refresh(db_size) + return db_size + except IntegrityError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Ошибка при создании размера: {str(e)}" + ) + + +def update_size(db: Session, size_id: int, size: SizeUpdate) -> Size: + db_size = get_size(db, size_id) + if not db_size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {size_id} не найден" + ) + + # Проверяем, что код размера уникален, если он изменяется + if size.code and size.code != db_size.code: + existing_size = get_size_by_code(db, size.code) + if existing_size: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Размер с кодом {size.code} уже существует" + ) + + # Обновляем поля + if size.name is not None: + db_size.name = size.name + if size.code is not None: + db_size.code = size.code + if size.description is not None: + db_size.description = size.description + + try: + db.commit() + db.refresh(db_size) + return db_size + except IntegrityError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Ошибка при обновлении размера: {str(e)}" + ) + + +def delete_size(db: Session, size_id: int) -> bool: + db_size = get_size(db, size_id) + if not db_size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {size_id} не найден" + ) + + # Проверяем, используется ли размер в вариантах продуктов + variants_with_size = db.query(ProductVariant).filter(ProductVariant.size_id == size_id).count() + if variants_with_size > 0: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Невозможно удалить размер, так как он используется в {variants_with_size} вариантах продуктов" + ) + + try: + db.delete(db_size) + db.commit() + return True + except IntegrityError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Ошибка при удалении размера: {str(e)}" ) \ No newline at end of file diff --git a/backend/app/repositories/order_repo.py b/backend/app/repositories/order_repo.py index 195e0f8..af09846 100644 --- a/backend/app/repositories/order_repo.py +++ b/backend/app/repositories/order_repo.py @@ -419,74 +419,80 @@ def get_cart_with_product_details(db: Session, user_id: int) -> List[Dict[str, A return result -def get_order_with_details(db: Session, order_id: int) -> Dict[str, Any]: - order = get_order(db, order_id) +def get_order_with_details(db: Session, order_id: int) -> Optional[Dict]: + order = db.query(Order).filter(Order.id == order_id).first() if not order: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Заказ не найден" - ) - - # Получаем пользователя - user = db.query(User).filter(User.id == order.user_id).first() - + return None + + # Получаем все товары в заказе с их вариантами + order_items = ( + db.query(OrderItem) + .filter(OrderItem.order_id == order_id) + .all() + ) + + items = [] + for item in order_items: + # Получаем информацию о товаре и его варианте + variant = db.query(ProductVariant).filter(ProductVariant.id == item.variant_id).first() + if not variant: + continue + + product = db.query(Product).filter(Product.id == variant.product_id).first() + if not product: + continue + + # Получаем основное изображение продукта + image = db.query(ProductImage).filter( + ProductImage.product_id == product.id, + ProductImage.is_primary == True + ).first() + + # Если нет основного изображения, берем первое доступное + if not image: + image = db.query(ProductImage).filter( + ProductImage.product_id == product.id + ).first() + + items.append({ + "id": item.id, + "product": { + "id": product.id, + "name": product.name, + "image": image.image_url if image else None, + "slug": product.slug + }, + "variant_name": variant.size.name if variant.size else None, + "quantity": item.quantity, + "price": item.price + }) + # Получаем адрес доставки shipping_address = None if order.shipping_address_id: address = db.query(UserAddress).filter(UserAddress.id == order.shipping_address_id).first() if address: shipping_address = { - "id": address.id, "address_line1": address.address_line1, "address_line2": address.address_line2, "city": address.city, - "state": address.state, "postal_code": address.postal_code, "country": address.country } - - # Получаем элементы заказа с деталями - items = [] - for item in order.items: - # Получаем информацию о варианте и продукте - variant = db.query(ProductVariant).filter(ProductVariant.id == item.variant_id).first() - if not variant: - continue - - product = db.query(Product).filter(Product.id == variant.product_id).first() - if not product: - continue - - # Формируем элемент заказа - items.append({ - "id": item.id, - "order_id": item.order_id, - "variant_id": item.variant_id, - "quantity": item.quantity, - "price": item.price, - "created_at": item.created_at, - "product_id": product.id, - "product_name": product.name, - "variant_name": variant.name, - "total_price": item.price * item.quantity - }) - - # Формируем результат - result = { + + return { "id": order.id, "user_id": order.user_id, + "user_name": f"{order.user.first_name} {order.user.last_name}" if order.user else None, + "user_email": order.user.email if order.user else None, "status": order.status, - "total_amount": order.total_amount, - "shipping_address_id": order.shipping_address_id, - "payment_method": order.payment_method, - "payment_details": order.payment_details, - "tracking_number": order.tracking_number, - "notes": order.notes, + "total": order.total_amount, "created_at": order.created_at, "updated_at": order.updated_at, - "user_email": user.email if user else None, + "items_count": len(items), + "items": items, "shipping_address": shipping_address, - "items": items - } - - return result \ No newline at end of file + "payment_method": order.payment_method, + "tracking_number": order.tracking_number, + "notes": order.notes + } \ No newline at end of file diff --git a/backend/app/routers/__pycache__/__init__.cpython-310.pyc b/backend/app/routers/__pycache__/__init__.cpython-310.pyc index 8edd209286b565f9b1212f833ce22386ac153bb8..617da1e666c70ab281bfe08ca9769c05fc4d54e7 100644 GIT binary patch delta 20 acmcb>c7csMpO=@50SL~my0($ql^Fm!5(S+A delta 20 acmcb>c7csMpO=@50SKbb9o)$6$_xNERRuTz diff --git a/backend/app/routers/__pycache__/analytics_router.cpython-310.pyc b/backend/app/routers/__pycache__/analytics_router.cpython-310.pyc index d0707c9aad0c2e1f040d3f26a0494bcdac5d5f55..f72288355141e50b115e3c445fb671d9f453912d 100644 GIT binary patch delta 20 acmeyu`-PV~pO=@50SL~my0($~B^v-iu?Cs| delta 20 acmeyu`-PV~pO=@50SFeIJGhbiB^v-h>;`=R diff --git a/backend/app/routers/__pycache__/auth_router.cpython-310.pyc b/backend/app/routers/__pycache__/auth_router.cpython-310.pyc index ec953bf88f5648bdcf9d48f7289d5fbf511cc80c..d3b672d13a5433ea31c2b2337997f0dcf696ecea 100644 GIT binary patch delta 20 acmdlcxJ{5dpO=@50SL~my0(#fH3tAVlLhJk delta 20 acmdlcxJ{5dpO=@50SHdNI=GR0H3tAWl?D<3 diff --git a/backend/app/routers/__pycache__/cart_router.cpython-310.pyc b/backend/app/routers/__pycache__/cart_router.cpython-310.pyc index 7635dc93218494387969231de41c6603abdd5b75..f272feca6f65137e6a984cd187037ca83ccc5311 100644 GIT binary patch delta 20 acmey*_n(hDpO=@50SL~my0($KgdG4vjs`ve delta 20 acmey*_n(hDpO=@50SJWqj&9^GVFv&_bOlxb diff --git a/backend/app/routers/__pycache__/catalog_router.cpython-310.pyc b/backend/app/routers/__pycache__/catalog_router.cpython-310.pyc index 1dac9db2b318f1b68f55d645d70ec4c0501cd750..79b249d03e35b548be86cfc28b25e61c78f623d3 100644 GIT binary patch literal 7913 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 literal 6526 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 delta 20 acmX>ia72JRpO=@50SHvi9o)!m$pHX0Xax5F diff --git a/backend/app/routers/__pycache__/order_router.cpython-310.pyc b/backend/app/routers/__pycache__/order_router.cpython-310.pyc index 1e5be832fee5f66a55e057fdd1a50a58e46b2484..591cfb3b8fc1e2053b543113e028a4a5e0414243 100644 GIT binary patch delta 20 acmcaAa8-aipO=@50SL~my0($qivs{WM+LXc6Gf=jG*M0D^O?u5IN0$qoQ9o(0hW delta 20 acmZn>Xc6Gf=jG*M00QxI2RCy6WCs8(3pO=@50SL~my0(#fA_o98g9V%b delta 20 acmbOuI7g5>pO=@50SGpnJ-Cs3A_o988U>61 diff --git a/backend/app/routers/catalog_router.py b/backend/app/routers/catalog_router.py index 8f69936..44af916 100644 --- a/backend/app/routers/catalog_router.py +++ b/backend/app/routers/catalog_router.py @@ -1,15 +1,16 @@ -from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form +from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, Query from sqlalchemy.orm import Session from typing import List, Optional, Dict, Any from app.core import get_db, get_current_admin_user from app import services from app.schemas.catalog_schemas import ( - CategoryCreate, CategoryUpdate, Category, - ProductCreate, ProductUpdate, Product, + CategoryCreate, CategoryUpdate, Category, CategoryWithSubcategories, + ProductCreate, ProductUpdate, Product, ProductWithDetails, ProductVariantCreate, ProductVariantUpdate, ProductVariant, ProductImageCreate, ProductImageUpdate, ProductImage, - CollectionCreate, CollectionUpdate, Collection + CollectionCreate, CollectionUpdate, Collection, + SizeCreate, SizeUpdate, Size ) from app.models.user_models import User as UserModel from app.repositories.catalog_repo import get_products, get_product_by_slug @@ -90,18 +91,34 @@ async def get_product_by_slug_endpoint(slug: str, db: Session = Depends(get_db)) @catalog_router.post("/products/{product_id}/variants", response_model=Dict[str, Any]) -async def add_product_variant_endpoint(product_id: int, variant: ProductVariantCreate, current_user: UserModel = Depends(get_current_admin_user), db: Session = Depends(get_db)): - variant.product_id = product_id +async def add_product_variant_endpoint( + product_id: int, + variant: ProductVariantCreate, + current_user: UserModel = Depends(get_current_admin_user), + db: Session = Depends(get_db) +): + # Убедимся, что product_id в пути совпадает с product_id в данных + if variant.product_id != product_id: + variant.product_id = product_id return services.add_product_variant(db, variant) @catalog_router.put("/variants/{variant_id}", response_model=Dict[str, Any]) -async def update_product_variant_endpoint(variant_id: int, variant: ProductVariantUpdate, current_user: UserModel = Depends(get_current_admin_user), db: Session = Depends(get_db)): +async def update_product_variant_endpoint( + variant_id: int, + variant: ProductVariantUpdate, + current_user: UserModel = Depends(get_current_admin_user), + db: Session = Depends(get_db) +): return services.update_product_variant(db, variant_id, variant) @catalog_router.delete("/variants/{variant_id}", response_model=Dict[str, Any]) -async def delete_product_variant_endpoint(variant_id: int, current_user: UserModel = Depends(get_current_admin_user), db: Session = Depends(get_db)): +async def delete_product_variant_endpoint( + variant_id: int, + current_user: UserModel = Depends(get_current_admin_user), + db: Session = Depends(get_db) +): return services.delete_product_variant(db, variant_id) @@ -141,4 +158,53 @@ async def get_products_endpoint( ): products = get_products(db, skip, limit, category_id, collection_id, search, min_price, max_price, is_active, include_variants) # Преобразуем объекты SQLAlchemy в схемы Pydantic - return [Product.model_validate(product) for product in products] \ No newline at end of file + return [Product.model_validate(product) for product in products] + + +# Маршруты для размеров +@catalog_router.get("/sizes", response_model=List[Size]) +def get_sizes( + skip: int = 0, + limit: int = 100, + db: Session = Depends(get_db) +): + """Получить список всех размеров""" + return services.get_sizes(db, skip, limit) + + +@catalog_router.get("/sizes/{size_id}", response_model=Size) +def get_size( + size_id: int, + db: Session = Depends(get_db) +): + """Получить размер по ID""" + return services.get_size(db, size_id) + + +@catalog_router.post("/sizes", response_model=Size, status_code=status.HTTP_201_CREATED) +def create_size( + size: SizeCreate, + db: Session = Depends(get_db) +): + """Создать новый размер""" + return services.create_size(db, size) + + +@catalog_router.put("/sizes/{size_id}", response_model=Size) +def update_size( + size_id: int, + size: SizeUpdate, + db: Session = Depends(get_db) +): + """Обновить размер""" + return services.update_size(db, size_id, size) + + +@catalog_router.delete("/sizes/{size_id}", response_model=Dict[str, bool]) +def delete_size( + size_id: int, + db: Session = Depends(get_db) +): + """Удалить размер""" + success = services.delete_size(db, size_id) + return {"success": success} \ No newline at end of file diff --git a/backend/app/schemas/__pycache__/__init__.cpython-310.pyc b/backend/app/schemas/__pycache__/__init__.cpython-310.pyc index adb1322c70233b217bf0123e8141cea7dceadd07..494f0af6e596b71b0d93556444046e5ba59cb972 100644 GIT binary patch delta 19 ZcmdnYxS5eVpO=@50SL~mx;Bw}1pqI)1(^T< delta 19 ZcmdnYxS5eVpO=@50SE$C9-PR%0st&+1qA>A diff --git a/backend/app/schemas/__pycache__/catalog_schemas.cpython-310.pyc b/backend/app/schemas/__pycache__/catalog_schemas.cpython-310.pyc index 19365039a2a3742d2a6d58ca9fd227cc7a918f93..89ba868e385fe4f1890f89455fa04d717dd8107f 100644 GIT binary patch literal 7568 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 literal 6537 zcmbVQNpl=Y6|U;)rK%UHWl6T>RYv2b?Xi0Xh9$rZ!ZIEvm}!==hlnDeD0ikb74D6! zYJ+qjh!`#$xN;+6;6Q{q@gw*ZdF8~}Hx2~fd$q|`-Li}nnO$GL%&N@qE%`F1oleuh zUu*xL2mf6)jDHb0{#OOqMG3z!4MP~h92sNNHOCdVGPYdHq_)baIX8zzyjDH-T;806UCZz)jHtZZU2Hw?zlI!{a-^ zD`FLRRdz6b1-L8LfY%tW0-q7UTgtxFR$|S z{>~>x@7;fs?s}GX9{8dBcq-&b*B%9OB((F~9|gjXrV3*FhqEY{PW+LseiVd}u05Fm z_DpS~hm3-;9MX%9|5*ULDB%NC(r`^-xRob{v}9G7_hAHXP1dEgWdK`@8yT(w*IZjV zkkv_ssW$Y=-gGpQLz)Q9R#zwfSPpbG9L*1OOUQ7j0-ok$?F6CcqvvzkYiir`sHf-Y zrss{PVm_khw&(q7?vE0Q6-G+0dY(U-Oe3E@5qh3#Vd|C5YT{x`Iz?&Q&IcU<-fcSX}mwCBokucUM2@b<!M>h+exufGU_?9#MLjvARJO#g^rkcneY@DO9&P5`PJ zUAEcpDd>~mQ_xSSU*h%5Ad%PW6j?vn^-oJZvC&6KsE>m{*F+c~$#Ql+f;4C6bzy+F zyGF7dV)Y0M4PhfJ*a!;_hXqI5DHrN8UarXX2C+Ah!u85bVRIWsp*Nh)C(DC_+D7l5 zb+nqkE(-nNFR$2%Onog~W% z{uI*X1arK__5#o5I17Rs5`NBJPUh9XHbc3Hjb|tE_$HofFuRsMgYBER{M1*0KZ!Ws zXeRu^(K!ZaD||NBwV4WrNJCac5Hjx`Hz-y~4Lkkt*|M;Z6Gj0-*Y-zKKT==Da~vMO zLQf|LhI{C;hZ0i2r@#>Zcg;2erXp#Hz+!ONcy+0-4G~|(OFu@5Lj^VRXE3<$r(;5;Cx>jW3&QRLk}BjHV|2$d$3SlQRGGPH_;>A#6bc6I`-A!Ndb-3 zOH+#-^IP<^G;RC_F9G@_%ZPoFbg8JlwD3$5$yS{P9-jVdeUWm_5lZZfgi0UCn5AHl zGy8g9gzr?dILOmUJ%@=P4tm8@PvsmjWxN}l%ogn`GnBB7s%fyzQ`^#oq&D9^uIM+m z`1RwXPigN*nAU0R{eASCQ(v}sLQ5ADx{&5tN$vejPR9~4GR{?zK-Kx+6z^)3yE?j+ zEOb%o8gERxHB53W>}_}GP zs^}t}WJRy_4!U{x14`^2gi7zW(71~dPEh4~SmGV=PIIb5YcZMSohnXld8dMIY@Mzo zbu8XW_|l<`>BL(<%}x=Sy_Mo_baH~5>w{l$vQqZ&fj^=oO3C*iD1~Ipi4&0K#H9wj z?6`Yi;IM_8JTg;G#jvfTt;KDihuezzZzsur8;RnJ&aUm}ahewDI*0kNG~LXGwlQ67 zcF@^rkr0!t zv@{EiyENd{iwCeu=`Ar@OD^2#;(?N@8eO>Igpu5{@(H63gKX%n^hog2Ao}c+`O_pY z1Txf}@Hpi3R^44RpCZ-UOW%1)^8bdf&=_y(N2VS4EUN(6;oW++qKcFX0is{-W zo*Zj~GQHE7{D6GiJV^$KhGa+ zkc_?1p{H|HU7(65cZ;5GQ$?qDK4J1HNzplmbM4qsDOXeEP>N5z?6R~usRvZ;QAN(E z$Xa-odVS8f delta 20 acmcbvcwLb@pO=@50SJE1JGznki~s;YlLmtT diff --git a/backend/app/schemas/catalog_schemas.py b/backend/app/schemas/catalog_schemas.py index b604302..fa9c90b 100644 --- a/backend/app/schemas/catalog_schemas.py +++ b/backend/app/schemas/catalog_schemas.py @@ -1,5 +1,5 @@ from pydantic import BaseModel, Field, validator -from typing import Optional, List, Union +from typing import Optional, List, Union, Dict, Any from datetime import datetime @@ -62,14 +62,37 @@ class Category(CategoryBase): from_attributes = True +# Схемы для размеров +class SizeBase(BaseModel): + name: str + code: str + description: Optional[str] = None + + +class SizeCreate(SizeBase): + pass + + +class SizeUpdate(SizeBase): + name: Optional[str] = None + code: Optional[str] = None + description: Optional[str] = None + + +class Size(SizeBase): + id: int + created_at: datetime + updated_at: Optional[datetime] = None + + class Config: + from_attributes = True + # Схемы для вариантов продуктов class ProductVariantBase(BaseModel): product_id: int - name: str + size_id: int sku: str - price: float - discount_price: Optional[float] = None stock: int = 0 is_active: bool = True @@ -78,12 +101,10 @@ class ProductVariantCreate(ProductVariantBase): pass -class ProductVariantUpdate(ProductVariantBase): +class ProductVariantUpdate(BaseModel): product_id: Optional[int] = None - name: Optional[str] = None + size_id: Optional[int] = None sku: Optional[str] = None - price: Optional[float] = None - discount_price: Optional[float] = None stock: Optional[int] = None is_active: Optional[bool] = None @@ -92,6 +113,7 @@ class ProductVariant(ProductVariantBase): id: int created_at: datetime updated_at: Optional[datetime] = None + size: Optional[Size] = None class Config: from_attributes = True @@ -123,12 +145,14 @@ class ProductImage(ProductImageBase): from_attributes = True - # Схемы для продуктов class ProductBase(BaseModel): name: str slug: Optional[str] = None description: Optional[str] = None + price: float + discount_price: Optional[float] = None + care_instructions: Optional[Dict[str, Any]] = None is_active: bool = True category_id: int collection_id: Optional[int] = None @@ -138,10 +162,13 @@ class ProductCreate(ProductBase): pass -class ProductUpdate(ProductBase): +class ProductUpdate(BaseModel): name: Optional[str] = None slug: Optional[str] = None description: Optional[str] = None + price: Optional[float] = None + discount_price: Optional[float] = None + care_instructions: Optional[Dict[str, Any]] = None is_active: Optional[bool] = None category_id: Optional[int] = None collection_id: Optional[int] = None diff --git a/backend/app/services/__init__.py b/backend/app/services/__init__.py index 53c9f4b..450e493 100644 --- a/backend/app/services/__init__.py +++ b/backend/app/services/__init__.py @@ -9,7 +9,8 @@ from app.services.catalog_service import ( create_product, update_product, delete_product, get_product_details, add_product_variant, update_product_variant, delete_product_variant, upload_product_image, update_product_image, delete_product_image, - create_collection, update_collection, delete_collection, get_collections + create_collection, update_collection, delete_collection, get_collections, + get_size, get_size_by_code, get_sizes, create_size, update_size, delete_size ) from app.services.order_service import ( diff --git a/backend/app/services/__pycache__/__init__.cpython-310.pyc b/backend/app/services/__pycache__/__init__.cpython-310.pyc index 690a72ed5ef54a2ad26c78b64bcdd1bc8a084a0c..73637b4c0f26ad2ab91ab9a05bbb50f38d485edd 100644 GIT binary patch delta 349 zcmYMvO-{m45CGsl=`$cUap8g(`KJYxKq>SGynzc3Ffk!YpGeXPTIxbqUZHtQPvF88 zXE3hanAn(j02d~nKt?6b;>-Ll=410y(`K5sp)BL<^<{DwYxy;m#jV>87NCGdC}Igp zScWoIpn_GXGR0T?R8T`5bTq)gI@GZN@%xUe25sy>2Td@s3thCp!XET~E_l#K8*FsI zK^I)~z{3Fya0o-W&7N3p@y3qXQIejBXf&VRh-7P(jZUvefZP4RyjG>O_NR5_`lx(UK7_%V(aG54>nt e)ans^!X_NTU2?C49_60=;+N_3^;Tw=*VJ$NR>6BoQb!kq*-(Ha`mJ1a}A;lat)&lbB&^ma*d;mb4{X5ChIUBXB67}g)xS4 z^E_q)Mn==g=UI+U-oz@aDF?K!NFGEefCxnpp#&n7L4*p3Pz4cclYg)(PQJ$~G1-t! qUQGuiqzfYSK!iSsFaQyTKw>3Bkr9Y(G`WnekRyOiheL){g#`dzvolQq diff --git a/backend/app/services/__pycache__/catalog_service.cpython-310.pyc b/backend/app/services/__pycache__/catalog_service.cpython-310.pyc index 891c188f492a36ac7192a44f9255155a169bea6a..7182117fef2d063da4525602f9274ae687d86de3 100644 GIT binary patch literal 11839 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 literal 8047 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 delta 20 acmX@dcaD!cpO=@50SG3ZKDd$FnH>N*m<4(O diff --git a/backend/app/services/__pycache__/order_service.cpython-310.pyc b/backend/app/services/__pycache__/order_service.cpython-310.pyc index f65da0c1702c2f4245e895d8c7853f5b59cc818d..15c0542cafdaf382532d9f6e435fb0796a618c3c 100644 GIT binary patch delta 20 acmdm{xJ{8epO=@50SL~my0(#fwEzG*+XfN< delta 20 acmdm{xJ{8epO=@50SI0%Ke~~7wEzG+KL#5B diff --git a/backend/app/services/__pycache__/review_service.cpython-310.pyc b/backend/app/services/__pycache__/review_service.cpython-310.pyc index 2a5ecb816c85733c5e2f1a2278948bab05c8446d..866b20d7768b34deed802a95ae2b81e1f2862d8f 100644 GIT binary patch delta 27 hcmZn`Xcpkk=jG*M0D^O?u5IN0$i^78`7awABLHKD2i^bx delta 27 hcmZn`Xcpkk=jG*M0D}K74sPWB$i{eU^ItYLMgVJG2)F tuple[List[Dict[str, Any] def create_product(db: Session, product: ProductCreate) -> Dict[str, Any]: - from app.schemas.catalog_schemas import Product as ProductSchema - - new_product = catalog_repo.create_product(db, product) - # Преобразуем объект SQLAlchemy в схему Pydantic - product_schema = ProductSchema.model_validate(new_product) - return {"product": product_schema} + """Создать новый продукт""" + try: + # Проверяем, что категория существует + category = catalog_repo.get_category(db, product.category_id) + if not category: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Категория с ID {product.category_id} не найдена" + ) + + # Проверяем, что коллекция существует, если она указана + if product.collection_id: + collection = catalog_repo.get_collection(db, product.collection_id) + if not collection: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Коллекция с ID {product.collection_id} не найдена" + ) + + # Создаем продукт + db_product = catalog_repo.create_product(db, product) + + return { + "success": True, + "product": Product.from_orm(db_product) + } + except HTTPException as e: + return { + "success": False, + "error": e.detail + } + except Exception as e: + return { + "success": False, + "error": str(e) + } def update_product(db: Session, product_id: int, product: ProductUpdate) -> Dict[str, Any]: - from app.schemas.catalog_schemas import Product as ProductSchema - - updated_product = catalog_repo.update_product(db, product_id, product) - # Преобразуем объект SQLAlchemy в схему Pydantic - product_schema = ProductSchema.model_validate(updated_product) - return {"product": product_schema} + """Обновить продукт""" + try: + # Проверяем, что продукт существует + db_product = catalog_repo.get_product(db, product_id) + if not db_product: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Продукт с ID {product_id} не найден" + ) + + # Если меняется категория, проверяем, что она существует + if product.category_id is not None: + category = catalog_repo.get_category(db, product.category_id) + if not category: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Категория с ID {product.category_id} не найдена" + ) + + # Если меняется коллекция, проверяем, что она существует + if product.collection_id is not None: + if product.collection_id: + collection = catalog_repo.get_collection(db, product.collection_id) + if not collection: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Коллекция с ID {product.collection_id} не найдена" + ) + + # Обновляем продукт + updated_product = catalog_repo.update_product(db, product_id, product) + + return { + "success": True, + "product": Product.from_orm(updated_product) + } + except HTTPException as e: + return { + "success": False, + "error": e.detail + } + except Exception as e: + return { + "success": False, + "error": str(e) + } def delete_product(db: Session, product_id: int) -> Dict[str, Any]: @@ -160,68 +231,150 @@ def delete_product(db: Session, product_id: int) -> Dict[str, Any]: def get_product_details(db: Session, product_id: int) -> Dict[str, Any]: - from app.schemas.catalog_schemas import Product as ProductSchema, Category as CategorySchema - from app.schemas.catalog_schemas import ProductVariant as ProductVariantSchema - from app.schemas.catalog_schemas import ProductImage as ProductImageSchema - from app.schemas.catalog_schemas import Collection as CollectionSchema - - product = catalog_repo.get_product(db, product_id) - if not product: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Продукт не найден" + """Получить детальную информацию о продукте""" + try: + # Получаем продукт + product = catalog_repo.get_product(db, product_id) + if not product: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Продукт с ID {product_id} не найден" + ) + + # Получаем варианты продукта + variants = catalog_repo.get_product_variants(db, product_id) + + # Получаем изображения продукта + images = catalog_repo.get_product_images(db, product_id) + + # Получаем категорию + category = catalog_repo.get_category(db, product.category_id) + + # Получаем коллекцию, если она указана + collection = None + if product.collection_id: + collection = catalog_repo.get_collection(db, product.collection_id) + + # Создаем детальное представление продукта + product_details = ProductWithDetails( + id=product.id, + name=product.name, + slug=product.slug, + description=product.description, + price=product.price, + discount_price=product.discount_price, + care_instructions=product.care_instructions, + is_active=product.is_active, + category_id=product.category_id, + collection_id=product.collection_id, + created_at=product.created_at, + updated_at=product.updated_at, + category=Category.from_orm(category), + collection=Collection.from_orm(collection) if collection else None, + variants=[ProductVariant.from_orm(variant) for variant in variants], + images=[ProductImage.from_orm(image) for image in images] ) - - # Получаем варианты продукта - variants = catalog_repo.get_product_variants(db, product_id) - - # Получаем изображения продукта - images = catalog_repo.get_product_images(db, product_id) - - # Получаем рейтинг продукта - rating = review_repo.get_product_rating(db, product_id) - - # Получаем отзывы продукта - reviews = review_repo.get_product_reviews(db, product_id, limit=5) - - # Преобразуем объекты SQLAlchemy в схемы Pydantic - product_schema = ProductSchema.model_validate(product) - variants_schema = [ProductVariantSchema.model_validate(variant) for variant in variants] - images_schema = [ProductImageSchema.model_validate(image) for image in images] - - # Добавляем информацию о коллекции, если она есть - collection_schema = None - if product.collection_id: - collection = catalog_repo.get_collection(db, product.collection_id) - if collection: - collection_schema = CollectionSchema.model_validate(collection) - - return { - "product": product_schema, - "variants": variants_schema, - "images": images_schema, - "collection": collection_schema, - "rating": rating, - "reviews": reviews - } + + return { + "success": True, + "product": product_details + } + except HTTPException as e: + return { + "success": False, + "error": e.detail + } + except Exception as e: + return { + "success": False, + "error": str(e) + } def add_product_variant(db: Session, variant: ProductVariantCreate) -> Dict[str, Any]: - from app.schemas.catalog_schemas import ProductVariant as ProductVariantSchema - - new_variant = catalog_repo.create_product_variant(db, variant) - # Преобразуем объект SQLAlchemy в схему Pydantic - variant_schema = ProductVariantSchema.model_validate(new_variant) - return {"variant": variant_schema} + """Добавить вариант продукта""" + try: + # Проверяем, что продукт существует + product = catalog_repo.get_product(db, variant.product_id) + if not product: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Продукт с ID {variant.product_id} не найден" + ) + + # Проверяем, что размер существует + size = catalog_repo.get_size(db, variant.size_id) + if not size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {variant.size_id} не найден" + ) + + # Создаем вариант продукта + db_variant = catalog_repo.create_product_variant(db, variant) + + return { + "success": True, + "variant": ProductVariant.from_orm(db_variant) + } + except HTTPException as e: + return { + "success": False, + "error": e.detail + } + except Exception as e: + return { + "success": False, + "error": str(e) + } def update_product_variant(db: Session, variant_id: int, variant: ProductVariantUpdate) -> Dict[str, Any]: - from app.schemas.catalog_schemas import ProductVariant as ProductVariantSchema - - updated_variant = catalog_repo.update_product_variant(db, variant_id, variant) - # Преобразуем объект SQLAlchemy в схему Pydantic - variant_schema = ProductVariantSchema.model_validate(updated_variant) - return {"variant": variant_schema} + """Обновить вариант продукта""" + try: + # Проверяем, что вариант существует + db_variant = catalog_repo.get_product_variant(db, variant_id) + if not db_variant: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Вариант продукта с ID {variant_id} не найден" + ) + + # Если меняется продукт, проверяем, что он существует + if variant.product_id is not None: + product = catalog_repo.get_product(db, variant.product_id) + if not product: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Продукт с ID {variant.product_id} не найден" + ) + + # Если меняется размер, проверяем, что он существует + if variant.size_id is not None: + size = catalog_repo.get_size(db, variant.size_id) + if not size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {variant.size_id} не найден" + ) + + # Обновляем вариант продукта + updated_variant = catalog_repo.update_product_variant(db, variant_id, variant) + + return { + "success": True, + "variant": ProductVariant.from_orm(updated_variant) + } + except HTTPException as e: + return { + "success": False, + "error": e.detail + } + except Exception as e: + return { + "success": False, + "error": str(e) + } def delete_product_variant(db: Session, variant_id: int) -> Dict[str, Any]: @@ -308,4 +461,42 @@ def delete_product_image(db: Session, image_id: int) -> Dict[str, Any]: # В реальном приложении здесь должно быть логирование pass - return {"success": success} \ No newline at end of file + return {"success": success} + + +# Функции для работы с размерами +def get_size(db: Session, size_id: int) -> Size: + db_size = catalog_repo.get_size(db, size_id) + if not db_size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с ID {size_id} не найден" + ) + return Size.from_orm(db_size) + + +def get_size_by_code(db: Session, code: str) -> Size: + db_size = catalog_repo.get_size_by_code(db, code) + if not db_size: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Размер с кодом {code} не найден" + ) + return Size.from_orm(db_size) + + +def get_sizes(db: Session, skip: int = 0, limit: int = 100) -> List[Size]: + db_sizes = catalog_repo.get_sizes(db, skip, limit) + return [Size.from_orm(size) for size in db_sizes] + + +def create_size(db: Session, size: SizeCreate) -> Size: + return Size.from_orm(catalog_repo.create_size(db, size)) + + +def update_size(db: Session, size_id: int, size: SizeUpdate) -> Size: + return Size.from_orm(catalog_repo.update_size(db, size_id, size)) + + +def delete_size(db: Session, size_id: int) -> bool: + return catalog_repo.delete_size(db, size_id) \ No newline at end of file diff --git a/backend/docs/README.md b/backend/docs/README.md new file mode 100644 index 0000000..1374486 --- /dev/null +++ b/backend/docs/README.md @@ -0,0 +1,117 @@ +# Документация бэкенда интернет-магазина одежды + +## Содержание + +1. [API документация](api_documentation.md) - Подробное описание всех API эндпоинтов +2. [Структура базы данных](database_structure.md) - Описание таблиц и связей в базе данных + +## Технологический стек + +- **Язык программирования**: Python 3.10+ +- **Фреймворк**: FastAPI +- **ORM**: SQLAlchemy 2.0 +- **База данных**: PostgreSQL +- **Аутентификация**: JWT (JSON Web Tokens) + +## Архитектура приложения + +Приложение построено по принципу многослойной архитектуры: + +1. **Роутеры (Routers)** - Обрабатывают HTTP-запросы и ответы +2. **Сервисы (Services)** - Содержат бизнес-логику приложения +3. **Репозитории (Repositories)** - Отвечают за взаимодействие с базой данных +4. **Модели (Models)** - Описывают структуру таблиц базы данных +5. **Схемы (Schemas)** - Описывают структуру данных для API (Pydantic модели) + +## Структура проекта + +``` +backend/ +├── app/ +│ ├── __init__.py +│ ├── main.py # Точка входа в приложение +│ ├── config.py # Конфигурация приложения +│ ├── core.py # Основные функции и зависимости +│ ├── models/ # SQLAlchemy модели +│ │ ├── __init__.py +│ │ ├── user_models.py +│ │ ├── catalog_models.py +│ │ ├── order_models.py +│ │ ├── review_models.py +│ │ └── content_models.py +│ ├── schemas/ # Pydantic схемы +│ │ ├── __init__.py +│ │ ├── user_schemas.py +│ │ ├── catalog_schemas.py +│ │ ├── order_schemas.py +│ │ ├── review_schemas.py +│ │ └── content_schemas.py +│ ├── repositories/ # Репозитории для работы с БД +│ │ ├── __init__.py +│ │ ├── user_repo.py +│ │ ├── catalog_repo.py +│ │ ├── order_repo.py +│ │ ├── review_repo.py +│ │ └── content_repo.py +│ ├── services/ # Бизнес-логика +│ │ ├── __init__.py +│ │ ├── user_service.py +│ │ ├── catalog_service.py +│ │ ├── order_service.py +│ │ ├── review_service.py +│ │ └── content_service.py +│ └── routers/ # API эндпоинты +│ ├── __init__.py +│ ├── auth_router.py +│ ├── user_router.py +│ ├── catalog_router.py +│ ├── cart_router.py +│ ├── order_router.py +│ ├── review_router.py +│ ├── content_router.py +│ └── analytics_router.py +├── alembic/ # Миграции базы данных +├── tests/ # Тесты +└── docs/ # Документация + ├── README.md + ├── api_documentation.md + └── database_structure.md +``` + +## Запуск приложения + +### Установка зависимостей + +```bash +pip install -r requirements.txt +``` + +### Настройка переменных окружения + +Создайте файл `.env` в корне проекта со следующими переменными: + +``` +DATABASE_URL=postgresql://user:password@localhost:5432/db_name +SECRET_KEY=your_secret_key +ALGORITHM=HS256 +ACCESS_TOKEN_EXPIRE_MINUTES=30 +``` + +### Запуск сервера разработки + +```bash +uvicorn app.main:app --reload +``` + +### Запуск миграций + +```bash +alembic upgrade head +``` + +## Документация API + +После запуска приложения, документация API доступна по адресу: + +- Swagger UI: http://localhost:8000/docs +- ReDoc: http://localhost:8000/redoc \ No newline at end of file diff --git a/backend/docs/api_documentation.md b/backend/docs/api_documentation.md new file mode 100644 index 0000000..a6fd9bd --- /dev/null +++ b/backend/docs/api_documentation.md @@ -0,0 +1,191 @@ +# Документация API интернет-магазина одежды + +## Содержание +1. [Аутентификация](#аутентификация) +2. [Пользователи](#пользователи) +3. [Каталог](#каталог) +4. [Корзина](#корзина) +5. [Заказы](#заказы) +6. [Отзывы](#отзывы) +7. [Контент](#контент) +8. [Аналитика](#аналитика) + +## Аутентификация + +Базовый URL: `/auth` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| POST | `/register` | Регистрация нового пользователя | `UserCreate` (email, password, first_name, last_name) | Нет | +| POST | `/login` | Вход в систему | `username` (email), `password` | Нет | +| POST | `/reset-password` | Запрос на сброс пароля | `email` | Нет | +| POST | `/set-new-password` | Установка нового пароля по токену | `token`, `password` | Нет | +| POST | `/change-password` | Изменение пароля | `current_password`, `new_password` | Да | + +## Пользователи + +Базовый URL: `/users` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/me` | Получение профиля текущего пользователя | - | Да | +| PUT | `/me` | Обновление профиля текущего пользователя | `UserUpdate` (first_name, last_name, phone) | Да | +| POST | `/me/addresses` | Добавление адреса пользователя | `AddressCreate` (city, street, house, apartment, postal_code, is_default) | Да | +| PUT | `/me/addresses/{address_id}` | Обновление адреса пользователя | `AddressUpdate` (city, street, house, apartment, postal_code, is_default) | Да | +| DELETE | `/me/addresses/{address_id}` | Удаление адреса пользователя | - | Да | +| GET | `/{user_id}` | Получение профиля пользователя по ID (только для админов) | - | Да (админ) | + +## Каталог + +Базовый URL: `/catalog` + +### Коллекции + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/collections` | Получение списка коллекций | `skip`, `limit` | Нет | +| POST | `/collections` | Создание новой коллекции | `CollectionCreate` (name, slug, description, is_active) | Да (админ) | +| PUT | `/collections/{collection_id}` | Обновление коллекции | `CollectionUpdate` (name, slug, description, is_active) | Да (админ) | +| DELETE | `/collections/{collection_id}` | Удаление коллекции | - | Да (админ) | + +### Категории + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/categories` | Получение дерева категорий | - | Нет | +| POST | `/categories` | Создание новой категории | `CategoryCreate` (name, slug, description, parent_id, is_active) | Да (админ) | +| PUT | `/categories/{category_id}` | Обновление категории | `CategoryUpdate` (name, slug, description, parent_id, is_active) | Да (админ) | +| DELETE | `/categories/{category_id}` | Удаление категории | - | Да (админ) | + +### Размеры + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/sizes` | Получение списка размеров | `skip`, `limit` | Нет | +| GET | `/sizes/{size_id}` | Получение размера по ID | - | Нет | +| POST | `/sizes` | Создание нового размера | `SizeCreate` (name, code, description) | Да (админ) | +| PUT | `/sizes/{size_id}` | Обновление размера | `SizeUpdate` (name, code, description) | Да (админ) | +| DELETE | `/sizes/{size_id}` | Удаление размера | - | Да (админ) | + +### Продукты + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/products` | Получение списка продуктов | `skip`, `limit`, `category_id`, `collection_id`, `search`, `min_price`, `max_price`, `is_active`, `include_variants` | Нет | +| GET | `/products/{product_id}` | Получение детальной информации о продукте | - | Нет | +| GET | `/products/slug/{slug}` | Получение продукта по slug | - | Нет | +| POST | `/products` | Создание нового продукта | `ProductCreate` (name, slug, description, price, discount_price, care_instructions, is_active, category_id, collection_id) | Да (админ) | +| PUT | `/products/{product_id}` | Обновление продукта | `ProductUpdate` (name, slug, description, price, discount_price, care_instructions, is_active, category_id, collection_id) | Да (админ) | +| DELETE | `/products/{product_id}` | Удаление продукта | - | Да (админ) | + +### Варианты продуктов + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| POST | `/products/{product_id}/variants` | Добавление варианта продукта | `ProductVariantCreate` (product_id, size_id, sku, stock, is_active) | Да (админ) | +| PUT | `/variants/{variant_id}` | Обновление варианта продукта | `ProductVariantUpdate` (product_id, size_id, sku, stock, is_active) | Да (админ) | +| DELETE | `/variants/{variant_id}` | Удаление варианта продукта | - | Да (админ) | + +### Изображения продуктов + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| POST | `/products/{product_id}/images` | Загрузка изображения продукта | `file`, `is_primary` | Да (админ) | +| PUT | `/images/{image_id}` | Обновление изображения продукта | `ProductImageUpdate` (alt_text, is_primary) | Да (админ) | +| DELETE | `/images/{image_id}` | Удаление изображения продукта | - | Да (админ) | + +## Корзина + +Базовый URL: `/cart` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/` | Получение корзины пользователя | - | Да | +| POST | `/items` | Добавление товара в корзину | `CartItemCreate` (product_variant_id, quantity) | Да | +| PUT | `/items/{cart_item_id}` | Обновление товара в корзине | `CartItemUpdate` (quantity) | Да | +| DELETE | `/items/{cart_item_id}` | Удаление товара из корзины | - | Да | +| DELETE | `/clear` | Очистка корзины | - | Да | + +## Заказы + +Базовый URL: `/orders` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/` | Получение списка заказов | `skip`, `limit`, `status` | Да | +| GET | `/{order_id}` | Получение информации о заказе | - | Да | +| POST | `/` | Создание нового заказа | `OrderCreate` (shipping_address_id, payment_method) | Да | +| PUT | `/{order_id}` | Обновление заказа | `OrderUpdate` (status, tracking_number) | Да (админ) | +| POST | `/{order_id}/cancel` | Отмена заказа | - | Да | + +## Отзывы + +Базовый URL: `/reviews` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/products/{product_id}` | Получение отзывов о продукте | `skip`, `limit` | Нет | +| POST | `/` | Создание нового отзыва | `ReviewCreate` (product_id, rating, text) | Да | +| PUT | `/{review_id}` | Обновление отзыва | `ReviewUpdate` (rating, text) | Да | +| DELETE | `/{review_id}` | Удаление отзыва | - | Да | +| POST | `/{review_id}/approve` | Одобрение отзыва | - | Да (админ) | + +## Контент + +Базовый URL: `/content` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| GET | `/pages` | Получение списка страниц | `skip`, `limit` | Нет | +| GET | `/pages/{page_id}` | Получение страницы по ID | - | Нет | +| GET | `/pages/slug/{slug}` | Получение страницы по slug | - | Нет | +| POST | `/pages` | Создание новой страницы | `PageCreate` (title, slug, content, is_published) | Да (админ) | +| PUT | `/pages/{page_id}` | Обновление страницы | `PageUpdate` (title, slug, content, is_published) | Да (админ) | +| DELETE | `/pages/{page_id}` | Удаление страницы | - | Да (админ) | + +## Аналитика + +Базовый URL: `/analytics` + +| Метод | Эндпоинт | Описание | Параметры запроса | Требуется авторизация | +|-------|----------|----------|-------------------|------------------------| +| POST | `/log` | Логирование события аналитики | `AnalyticsLogCreate` (event_type, event_data, user_id) | Нет | +| GET | `/logs` | Получение логов аналитики | `event_type`, `start_date`, `end_date`, `skip`, `limit` | Да (админ) | +| GET | `/report` | Получение аналитического отчета | `report_type`, `start_date`, `end_date` | Да (админ) | + +## Модели данных + +### Пользователи +- `UserCreate`: email, password, first_name, last_name +- `UserUpdate`: first_name, last_name, phone +- `AddressCreate`: city, street, house, apartment, postal_code, is_default +- `AddressUpdate`: city, street, house, apartment, postal_code, is_default + +### Каталог +- `CollectionCreate`: name, slug, description, is_active +- `CollectionUpdate`: name, slug, description, is_active +- `CategoryCreate`: name, slug, description, parent_id, is_active +- `CategoryUpdate`: name, slug, description, parent_id, is_active +- `SizeCreate`: name, code, description +- `SizeUpdate`: name, code, description +- `ProductCreate`: name, slug, description, price, discount_price, care_instructions, is_active, category_id, collection_id +- `ProductUpdate`: name, slug, description, price, discount_price, care_instructions, is_active, category_id, collection_id +- `ProductVariantCreate`: product_id, size_id, sku, stock, is_active +- `ProductVariantUpdate`: product_id, size_id, sku, stock, is_active +- `ProductImageCreate`: product_id, image_url, alt_text, is_primary +- `ProductImageUpdate`: alt_text, is_primary + +### Корзина и заказы +- `CartItemCreate`: product_variant_id, quantity +- `CartItemUpdate`: quantity +- `OrderCreate`: shipping_address_id, payment_method +- `OrderUpdate`: status, tracking_number + +### Отзывы +- `ReviewCreate`: product_id, rating, text +- `ReviewUpdate`: rating, text + +### Контент +- `PageCreate`: title, slug, content, is_published +- `PageUpdate`: title, slug, content, is_published +- `AnalyticsLogCreate`: event_type, event_data, user_id \ No newline at end of file diff --git a/backend/docs/database_structure.md b/backend/docs/database_structure.md new file mode 100644 index 0000000..d6146a3 --- /dev/null +++ b/backend/docs/database_structure.md @@ -0,0 +1,210 @@ +# Структура базы данных интернет-магазина одежды + +## Содержание +1. [Пользователи](#пользователи) +2. [Каталог](#каталог) +3. [Заказы](#заказы) +4. [Отзывы](#отзывы) +5. [Контент](#контент) + +## Пользователи + +### Таблица `users` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| email | String | Email пользователя (уникальный) | +| hashed_password | String | Хешированный пароль | +| first_name | String | Имя пользователя | +| last_name | String | Фамилия пользователя | +| phone | String | Телефон пользователя (опционально) | +| is_active | Boolean | Активен ли пользователь | +| is_admin | Boolean | Является ли пользователь администратором | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `addresses` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| user_id | Integer | Внешний ключ на таблицу users | +| city | String | Город | +| street | String | Улица | +| house | String | Номер дома | +| apartment | String | Номер квартиры (опционально) | +| postal_code | String | Почтовый индекс | +| is_default | Boolean | Является ли адрес адресом по умолчанию | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +## Каталог + +### Таблица `collections` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| name | String | Название коллекции | +| slug | String | URL-совместимое имя (уникальное) | +| description | Text | Описание коллекции (опционально) | +| is_active | Boolean | Активна ли коллекция | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `categories` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| name | String | Название категории | +| slug | String | URL-совместимое имя (уникальное) | +| description | Text | Описание категории (опционально) | +| parent_id | Integer | Внешний ключ на родительскую категорию (опционально) | +| is_active | Boolean | Активна ли категория | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `sizes` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| name | String | Название размера (S, M, L, XL и т.д.) | +| code | String | Уникальный код размера | +| description | String | Дополнительная информация о размере (опционально) | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `products` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| name | String | Название продукта | +| slug | String | URL-совместимое имя (уникальное) | +| description | Text | Описание продукта (опционально) | +| price | Float | Базовая цена продукта | +| discount_price | Float | Цена со скидкой (опционально) | +| care_instructions | JSON | Инструкции по уходу и другие детали (опционально) | +| is_active | Boolean | Активен ли продукт | +| category_id | Integer | Внешний ключ на таблицу categories | +| collection_id | Integer | Внешний ключ на таблицу collections (опционально) | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `product_variants` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| product_id | Integer | Внешний ключ на таблицу products | +| size_id | Integer | Внешний ключ на таблицу sizes | +| sku | String | Артикул (уникальный) | +| stock | Integer | Количество на складе | +| is_active | Boolean | Активен ли вариант | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `product_images` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| product_id | Integer | Внешний ключ на таблицу products | +| image_url | String | URL изображения | +| alt_text | String | Альтернативный текст (опционально) | +| is_primary | Boolean | Является ли изображение основным | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +## Заказы + +### Таблица `cart_items` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| user_id | Integer | Внешний ключ на таблицу users | +| product_variant_id | Integer | Внешний ключ на таблицу product_variants | +| quantity | Integer | Количество товара | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `orders` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| user_id | Integer | Внешний ключ на таблицу users | +| status | String | Статус заказа (новый, оплачен, отправлен, доставлен, отменен) | +| total_amount | Float | Общая сумма заказа | +| shipping_address_id | Integer | Внешний ключ на таблицу addresses | +| payment_method | String | Способ оплаты | +| tracking_number | String | Номер отслеживания (опционально) | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `order_items` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| order_id | Integer | Внешний ключ на таблицу orders | +| product_variant_id | Integer | Внешний ключ на таблицу product_variants | +| quantity | Integer | Количество товара | +| price | Float | Цена товара на момент заказа | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +## Отзывы + +### Таблица `reviews` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| product_id | Integer | Внешний ключ на таблицу products | +| user_id | Integer | Внешний ключ на таблицу users | +| rating | Integer | Оценка (1-5) | +| text | Text | Текст отзыва (опционально) | +| is_approved | Boolean | Одобрен ли отзыв | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +## Контент + +### Таблица `pages` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| title | String | Заголовок страницы | +| slug | String | URL-совместимое имя (уникальное) | +| content | Text | Содержимое страницы | +| is_published | Boolean | Опубликована ли страница | +| created_at | DateTime | Дата и время создания | +| updated_at | DateTime | Дата и время обновления | + +### Таблица `analytics_logs` +| Поле | Тип | Описание | +|------|-----|----------| +| id | Integer | Первичный ключ | +| event_type | String | Тип события | +| event_data | JSON | Данные события | +| user_id | Integer | Внешний ключ на таблицу users (опционально) | +| ip_address | String | IP-адрес (опционально) | +| user_agent | String | User-Agent (опционально) | +| created_at | DateTime | Дата и время создания | + +## Связи между таблицами + +1. `users` 1:N `addresses` (один пользователь может иметь несколько адресов) +2. `users` 1:N `cart_items` (один пользователь может иметь несколько товаров в корзине) +3. `users` 1:N `orders` (один пользователь может иметь несколько заказов) +4. `users` 1:N `reviews` (один пользователь может оставить несколько отзывов) + +5. `categories` 1:N `categories` (категория может иметь подкатегории) +6. `categories` 1:N `products` (категория может содержать несколько продуктов) + +7. `collections` 1:N `products` (коллекция может содержать несколько продуктов) + +8. `sizes` 1:N `product_variants` (размер может быть использован в нескольких вариантах продуктов) + +9. `products` 1:N `product_variants` (продукт может иметь несколько вариантов) +10. `products` 1:N `product_images` (продукт может иметь несколько изображений) +11. `products` 1:N `reviews` (продукт может иметь несколько отзывов) + +12. `product_variants` 1:N `cart_items` (вариант продукта может быть в нескольких корзинах) +13. `product_variants` 1:N `order_items` (вариант продукта может быть в нескольких заказах) + +14. `orders` 1:N `order_items` (заказ может содержать несколько товаров) +15. `addresses` 1:N `orders` (адрес может быть использован в нескольких заказах) \ No newline at end of file diff --git a/backend/uploads/products/2/ea1e8526-b67b-40ba-b971-b87694223a4a.png b/backend/uploads/products/2/ea1e8526-b67b-40ba-b971-b87694223a4a.png new file mode 100644 index 0000000000000000000000000000000000000000..e368ed9cb71d2e25fe8c42e031fd528916de9655 GIT binary patch literal 677827 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�&z7D^$aS~3rYYu|ng4r&LXOe6-JbOjWk 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