Files
tehran_taj/docs/parity/_inv-ref-server.md
s.esmaeiliandClaude Opus 5 71192ba2ba parity(docs): Phase 0 inventory, mapping and draft PROTECTED list
Read-only inventory of all 7 projects (3 reference + 4 target) produced by
parallel subagents, every claim cited path:line. No source code changed.

- 00-INVENTORY.md  consolidated mapping: stack, backend, admin, user apps
- PROTECTED.md     draft protected list (awaiting user confirmation)
- ISSUES.md        26 logged issues (security, money/stock, validation, dead code)
- CHANGELOG.md     change log scaffold
- PROGRESS.md      resumable state + Q1-Q5 blocking Phase 1
- _inv-*.md        7 raw per-project inventories (8111 lines)

Key finding: the reference is a gold-jewellery B2B/B2C e-commerce system, not a
gold bank. Buy/sell, deposit/withdraw, transfer, KYC levels, payment callbacks,
cron and websockets do not exist in it, so they cannot be parity gaps.

[ref: henza_server, henza_admin, henza_pwa]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 18:09:46 +03:30

121 KiB
Raw Permalink Blame History

Inventory — henza_server (reference backend)

Evidence-based inventory. All path:line are relative to henza_server/. Domain note: this codebase is a gold jewelry B2B/B2C e-commerce + wholesale ledger, not a "gold bank". There is no buy/sell order book, no deposit/withdraw, no KYC-level system, no transfer between users. Gold is handled as (a) a live 18-ayar price feed used in product pricing, and (b) a gram-denominated wallet (cashback/loyalty). See §7 for what exists vs. what does not.


1. Stack & versions

Item Value Evidence
Framework laravel/framework: ^8.0 composer.json:19
PHP ^7.3 composer.json:10
App name/env APP_NAME, APP_ENV, APP_DEBUG, APP_URL config/app.php
Autoload PSR-4 App\ → app/, Rooyesh\Wallet\ → packages/rooyesh/wallet/src/ composer.json:41-46
Custom app version 2.2.0 config/version.php:3

Key packages (composer.json:9-27)

Package Constraint Line Purpose
apility/laravel-fcm ^1.4 11 Push (FCM)
brozot/laravel-fcm ^1.3 13 Push (FCM, second impl)
barryvdh/laravel-dompdf ^0.9.0 12 PDF invoices
niklasravnsborg/laravel-pdf ^4.1 24 PDF (mPDF)
fideloper/proxy ^4.2 14 Trusted proxies
fruitcake/laravel-cors ^2.0 15 CORS
guzzlehttp/guzzle ^7.0.1 16 HTTP (SMS/price feeds)
hekmatinasser/verta ^2.1 17 Jalali dates
morilog/jalali 3.* 22 Jalali dates (primary, used in Utility)
ixudra/curl ^6.21 18 cURL (payping)
jgrossi/corcel ^5.0 19 WordPress DB bridge (config/corcel.php)
maatwebsite/excel ^3.1 21 Excel export (TableEngine)
phpoffice/phpspreadsheet * 23 Excel
phpro/soap-client ^1.4 25 SOAP (legacy Zarinpal)
laravel/tinker ^2.0 20 —

Dev: facade/ignition ^2.3.6, fzaninotto/faker ^1.9.1, mockery/mockery ^1.3.1, nunomaduro/collision ^5.0, phpunit/phpunit ^9.3 (composer.json:29-35).

Local package: packages/rooyesh/wallet — in-repo gold/credit wallet module (see §7).


2. Bootstrap / Middleware / Auth

2.1 Global middleware — app/Http/Kernel.php:17-25 (order as declared)

# Class Line
— App\Http\Middleware\TrustHosts 18 (commented out)
1 App\Http\Middleware\TrustProxies 19
2 Fruitcake\Cors\HandleCors 20
3 App\Http\Middleware\PreventRequestsDuringMaintenance 21
4 Illuminate\Foundation\Http\Middleware\ValidatePostSize 22
5 App\Http\Middleware\TrimStrings 23
6 Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull 24

2.2 Middleware groups — app/Http/Kernel.php:32-47

Group Stack (in order) Lines
web EncryptCookies, AddQueuedCookiesToResponse, StartSession, (AuthenticateSession commented, :37), ShareErrorsFromSession, VerifyCsrfToken, SubstituteBindings 33-41
api throttle:api, SubstituteBindings 43-46

Rate limit: Limit::perMinute(500) for the api limiter — app/Providers/RouteServiceProvider.php:76-78.

2.3 Route middleware aliases — app/Http/Kernel.php:56-68

Alias Class Line
auth App\Http\Middleware\Authenticate 57
auth.basic Illuminate\Auth\Middleware\AuthenticateWithBasicAuth 58
cache.headers Illuminate\Http\Middleware\SetCacheHeaders 59
can Illuminate\Auth\Middleware\Authorize 60
guest App\Http\Middleware\RedirectIfAuthenticated 61
password.confirm Illuminate\Auth\Middleware\RequirePassword 62
signed Illuminate\Routing\Middleware\ValidateSignature 63
throttle Illuminate\Routing\Middleware\ThrottleRequests 64
verified Illuminate\Auth\Middleware\EnsureEmailIsVerified 65
version App\Http\Middleware\VersionMiddleware 66
create_log App\Http\Middleware\CreateLog 67

Custom middleware behavior:

  • VersionMiddleware — reads config('version.version'); if request header version present and ≠ config, returns {"version": false} — app/Http/Middleware/VersionMiddleware.php:19-33.
  • CreateLog — writes a RequestLog row (customer_id from auth()->id(), ip, data, user_agent, route, method) on every request in the group — app/Http/Middleware/CreateLog.php:18-30. Note bug: 'device', is a positional value, not a key (:23).
  • Authenticate::redirectTo() — abort(401,'no authorised') instead of redirect — app/Http/Middleware/Authenticate.php:15-21.

2.4 Route file prefixes/middleware — app/Providers/RouteServiceProvider.php:41-66

File Prefix Group middleware Lines
routes/api.php api api 43-46
routes/web.php (none) web 48-50
routes/admin.php admin api 52-55
routes/site.php site api 57-60
routes/customer.php cu api 62-65

HOME = '/home' (:20). $namespace is commented out (:29) so string-controller routes use FQCN strings.

2.5 Auth guards & providers — config/auth.php

Guard Driver Provider hash Line
web session users — 39-42
api (default) token users false 44-48
api-customer token customers false 50-54
api-singleCustomer token singleCustomers false 56-60

Defaults: guard api, passwords users (:16-19).

Provider Driver Model Line
users eloquent App\Models\User 81-84
customers eloquent App\Models\Customer 85-88
singleCustomers eloquent App\Models\SingleCustomer 89-92

Password resets: table password_resets, expire 60, throttle 60 (:115-122). password_timeout: 10800 (:135).

Three-actor model: User = staff/admin (guard api), Customer = wholesale/major shopkeeper (guard api-customer), SingleCustomer = retail web customer, table login (guard api-singleCustomer).


3. Routes (exhaustive)

name column: no route is given a ->name() anywhere in any route file. Resource routes get Laravel's implicit names (cat.index, …) which are listed. Middleware column = group middleware from RouteServiceProvider + any explicit route middleware.

3.1 routes/admin.php — prefix admin, middleware api

⚠️ The entire file's auth wrapper Route::middleware('auth:api')->group(...) is COMMENTED OUT at routes/admin.php:12 and :264. Every admin route below is unauthenticated.

METHOD path name controller@method middleware/guards line
POST admin/product/create — Adm\ProductController@store api 14
GET admin/product/show/{id} — Adm\ProductController@show api 15
PUT admin/product/update/{id} — Adm\ProductController@update api 16
POST admin/product/test — Adm\ProductController@testSearch api 17
POST admin/product/report — Adm\ProductController@report api 18
GET admin/product/color — Adm\ProductController@color api 19
POST admin/product/variant — Adm\ProductController@getProductsVaraints api 20
GET admin/product/offer/{product_id} — Adm\ProductController@changeOffer api 21
GET admin/product/exist/{product_id} — Adm\ProductController@changeIsExist api 22
GET admin/product/warranty/{product_id} — Adm\ProductController@changeHasWarranty api 23
GET admin/dashboard/all — Adm\DashboardController@getAll api 26
GET admin/dashboard/change — Adm\DashboardController@change api 27
GET admin/dashboard/info — Adm\DashboardController@info api 28
GET admin/dashboard/link — Adm\DashboardController@link api 29
POST admin/admin-login — Adm\AdminController@login api 33
POST admin/products — Adm\AdminController@getProducts api 34
POST admin/single-customer — Adm\AdminController@getSingleCustomer api 35
GET admin/category — Adm\AdminController@queryCategory api 36
GET admin/get-analytics — Adm\AdminController@getAnalytics api 37
GET admin/get-analytics-tak — Adm\AdminController@getAnalyticsTak api 38
POST admin/product — Adm\AdminController@addProduct api 39
POST admin/add/variant — Adm\AdminController@addVariant api 40
GET admin/get/variant — Adm\AdminController@getVariant api 41
POST admin/get/variants — Adm\AdminController@getVariants api 42
GET admin/config/statics — Adm\AdminController@getConfigStatics api 43
GET admin/product/{id} — Adm\AdminController@getProduct api 44
POST admin/delete/product/{id} — Adm\AdminController@deleteProduct api 45
POST admin/category — Adm\AdminController@getCategory api 46
POST admin/add/category — Adm\AdminController@AddCategory api 47
GET admin/category/{id} — Adm\AdminController@getOneCategory api 48
GET admin/havale/list — Adm\AdminController@getHavaleList api 49
DELETE admin/category/{id} — Adm\AdminController@deleteCategory api 50
GET admin/price — Closure → WebServiceGold::getAllPrice() api 51-53
POST admin/change/percent — Adm\AdminController@changePercent api 54
POST admin/change/percent/count — Adm\AdminController@countProductForPercent api 55
POST admin/change/all — Adm\AdminController@changeAll api 56
POST admin/single/order-sts/edit — Adm\AdminController@orderStsSingle api 59
POST admin/single-order — Adm\AdminController@getSingleOrders api 60
POST admin/order — Adm\OrderController@store api 61
PUT admin/order/{id} — Adm\OrderController@update api 62
GET admin/order/type — Adm\OrderController@getType api 63
GET admin/order/pdf/{id} — Customer\OrderController@generateReportOrder api 64
POST admin/cat — Adm\CategoryController@index api 70
GET admin/cat cat.index Adm\CategoryController@index api 71 (resource)
GET admin/cat/create cat.create Adm\CategoryController@create api 71
POST admin/cat cat.store Adm\CategoryController@store api 71
GET admin/cat/{cat} cat.show Adm\CategoryController@show api 71
GET admin/cat/{cat}/edit cat.edit Adm\CategoryController@edit api 71
PUT/PATCH admin/cat/{cat} cat.update Adm\CategoryController@update api 71
DELETE admin/cat/{cat} cat.destroy Adm\CategoryController@destroy api 71
POST admin/major/order/table — Adm\MajorOrderController@index api 78
GET admin/major/order major/order.index Adm\MajorOrderController@index api 79 (resource)
GET admin/major/order/create major/order.create Adm\MajorOrderController@create api 79
POST admin/major/order major/order.store Adm\MajorOrderController@store api 79
GET admin/major/order/{order} major/order.show Adm\MajorOrderController@show api 79
GET admin/major/order/{order}/edit major/order.edit Adm\MajorOrderController@edit api 79
PUT/PATCH admin/major/order/{order} major/order.update Adm\MajorOrderController@update api 79
DELETE admin/major/order/{order} major/order.destroy Adm\MajorOrderController@destroy api 79
DELETE admin/major/order_item/{id} — Adm\MajorOrderController@deleteOrderItem api 80
POST admin/order-tamin — Adm\MajorOrderController@getTaminOrders api 81
POST admin/order-sts/edit — Adm\MajorOrderController@orderSts api 82
POST admin/order-item/edit — Adm\MajorOrderController@orderItemEdit api 83
POST admin/delete-order — Adm\MajorOrderController@deleteOrder api 84
POST admin/brand/create — Adm\BrandController@store api 88
GET admin/brand — Adm\BrandController@index api 89
PUT admin/brand/{id} — Adm\BrandController@update api 90
DELETE admin/brand/{id} — Adm\BrandController@destroy api 91
POST admin/report/order_item — Adm\ReportController@getOrderItemWithDetails api 96
POST admin/major/table — Adm\MajorCustomerController@index api 100
GET admin/major/dashboard/{id} — Adm\MajorCustomerController@dashboard api 101
POST admin/major/order — Adm\MajorCustomerController@order api 102 (shadowed by resource at :79)
POST admin/major/cash — Adm\MajorCustomerController@cash api 103
POST admin/major/customer — Adm\MajorCustomerController@shopkeeper api 104
POST admin/major/sms — Adm\MajorCustomerController@indexSms api 105
POST admin/major/verify — Adm\MajorCustomerController@verifyRegister api 106
POST admin/major/archive/table — Adm\MajorCustomerController@indexArchive api 107
POST admin/major/verify/table — Adm\MajorCustomerController@indexVerify api 108
GET admin/major/archive/{customer_id} — Adm\MajorCustomerController@archive api 109
GET admin/major/list_type — Adm\MajorCustomerController@listTypeCustomer api 110
POST admin/reagent — Adm\AdminController@getReagent api 113
POST admin/banker — Adm\AdminController@getBanker api 114
POST admin/shopkeeper — Adm\AdminController@getShopkeeper api 115
POST admin/customer/toggle-sts — Adm\AdminController@customerToggleSts api 116
POST admin/customer/toggle-active — Adm\AdminController@customerToggleActive api 117
GET admin/customer/{id} — Adm\AdminController@getCustomerById api 118
POST admin/customer — Adm\AdminController@getCustomer api 119
GET admin/query/customer — Adm\AdminController@queryCustomer api 120
GET admin/query/reagent — Adm\AdminController@queryReagent api 121
POST admin/major/promotion/table — Adm\PromotionController@index api 125
PUT admin/autopromotion — Adm\PromotionController@updateAutoPromotion api 126
GET admin/autopromotion — Adm\PromotionController@getAutoPromotion api 127
POST admin/brand — Adm\PromotionController@getBrand api 128
GET admin/major/promotion major/promotion.index Adm\PromotionController@index api 129 (resource)
GET admin/major/promotion/create major/promotion.create Adm\PromotionController@create api 129
POST admin/major/promotion major/promotion.store Adm\PromotionController@store api 129
GET admin/major/promotion/{promotion} major/promotion.show Adm\PromotionController@show api 129
GET admin/major/promotion/{promotion}/edit major/promotion.edit Adm\PromotionController@edit api 129
PUT/PATCH admin/major/promotion/{promotion} major/promotion.update Adm\PromotionController@update api 129
DELETE admin/major/promotion/{promotion} major/promotion.destroy Adm\PromotionController@destroy api 129
GET admin/ignore ignore.index Adm\IgnoreController@index api 132 (resource)
GET admin/ignore/create ignore.create Adm\IgnoreController@create (not defined) api 132
POST admin/ignore ignore.store Adm\IgnoreController@store api 132
GET admin/ignore/{ignore} ignore.show Adm\IgnoreController@show api 132
GET admin/ignore/{ignore}/edit ignore.edit Adm\IgnoreController@edit (not defined) api 132
PUT/PATCH admin/ignore/{ignore} ignore.update Adm\IgnoreController@update (not defined) api 132
DELETE admin/ignore/{ignore} ignore.destroy Adm\IgnoreController@destroy($type) api 132
POST admin/cash/table — Adm\CashController@index api 137
GET admin/cash cash.index Adm\CashController@index api 138 (resource)
GET admin/cash/create cash.create Adm\CashController@create api 138
POST admin/cash cash.store Adm\CashController@store api 138
GET admin/cash/{cash} cash.show Adm\CashController@show api 138
GET admin/cash/{cash}/edit cash.edit Adm\CashController@edit api 138
PUT/PATCH admin/cash/{cash} cash.update Adm\CashController@update api 138
DELETE admin/cash/{cash} cash.destroy Adm\CashController@destroy api 138
POST admin/cash/confirem/{id} — Adm\CashController@toggleConfiremCash api 139
POST admin/file/create — Adm\FileController@storeWithoutData api 145
PUT admin/file/update/{file_id} — Adm\FileController@updateBody api 146
POST admin/comment/table — Adm\CommentController@index api 150
GET admin/comment comment.index Adm\CommentController@index api 151 (resource)
GET admin/comment/create comment.create Adm\CommentController@create api 151
POST admin/comment comment.store Adm\CommentController@store api 151
GET admin/comment/{comment} comment.show Adm\CommentController@show api 151
GET admin/comment/{comment}/edit comment.edit Adm\CommentController@edit api 151
PUT/PATCH admin/comment/{comment} comment.update Adm\CommentController@update api 151
DELETE admin/comment/{comment} comment.destroy Adm\CommentController@destroy api 151
POST admin/comment/sts — Adm\CommentController@changeStatus api 152
GET admin/const const.index Adm\ConstController@index (not defined) api 155 (resource)
GET admin/const/create const.create Adm\ConstController@create (not defined) api 155
POST admin/const const.store Adm\ConstController@store api 155
GET admin/const/{const} const.show Adm\ConstController@show api 155
GET admin/const/{const}/edit const.edit Adm\ConstController@edit (not defined) api 155
PUT/PATCH admin/const/{const} const.update Adm\ConstController@update api 155
DELETE admin/const/{const} const.destroy Adm\ConstController@destroy api 155
DELETE admin/const/by-id/{id} — Adm\ConstController@deleteById api 156
POST admin/roles — Adm\PermissionController@store api 160
POST admin/roles/create — Adm\PermissionController@create api 161
DELETE admin/roles/{ut}/{rid} — Adm\PermissionController@destroy api 162
GET admin/roles/{ut}/{rid} — Adm\PermissionController@has api 163
GET admin/roles — Adm\PermissionController@get api 164
GET admin/roles/{id} — Adm\PermissionController@getByUt api 165
GET admin/cities cities.index Adm\CitiesController@index (not defined) api 168 (resource)
GET admin/cities/create cities.create Adm\CitiesController@create (not defined) api 168
POST admin/cities cities.store Adm\CitiesController@store api 168
GET admin/cities/{city} cities.show Adm\CitiesController@show api 168
GET admin/cities/{city}/edit cities.edit Adm\CitiesController@edit (not defined) api 168
PUT/PATCH admin/cities/{city} cities.update Adm\CitiesController@update api 168
DELETE admin/cities/{city} cities.destroy Adm\CitiesController@destroy api 168
POST admin/cities/list — Adm\CitiesController@list api 169
GET admin/cities/get-percent/{id} — Adm\CitiesController@getPercent api 170 (shadowed by cities.show)
GET admin/cities/get-percent-aux/{id} — Adm\CitiesController@getPercentAux api 171 (shadowed)
POST admin/customer/create — Adm\AdminController@createCustomer api 175
GET admin/report/order — Adm\AdminController@generateReportOrder api 176
GET admin/report/doc — Adm\AdminController@generateReportDocument api 177
GET admin/users/show — Adm\UserController@showData api 180
POST admin/users/list — Adm\UserController@index api 181
GET admin/users users.index Adm\UserController@index api 182 (resource)
GET admin/users/create users.create Adm\UserController@create (not defined) api 182
POST admin/users users.store Adm\UserController@store api 182
GET admin/users/{user} users.show Adm\UserController@show api 182
GET admin/users/{user}/edit users.edit Adm\UserController@edit (not defined) api 182
PUT/PATCH admin/users/{user} users.update Adm\UserController@update api 182
DELETE admin/users/{user} users.destroy Adm\UserController@destroy api 182
POST admin/wallet/percent — Adm\WalletController@changePercent api 186
POST admin/wallet/table — Adm\WalletController@index api 187
POST admin/wallet/charge — Adm\WalletController@charge api 188
POST admin/wallet/config — Adm\WalletController@setConst api 189
GET admin/wallet/config — Adm\WalletController@getConfig api 190
GET admin/wallet/birthday/config — Adm\WalletController@getConfigBirthday api 191
POST admin/single/order — Adm\SingleCustomerController@indexOrder api 194
POST admin/single/transaction — Adm\SingleCustomerController@indexTransaction api 195
POST admin/single/sms — Adm\SingleCustomerController@indexSms api 196
GET admin/single/wallet/{id} — Adm\SingleCustomerController@getWallet api 197
GET admin/single/report/{id} — Adm\SingleCustomerController@report api 198
GET admin/single single.index Adm\SingleCustomerController@index (not defined) api 199 (resource)
GET admin/single/create single.create @create (not defined) api 199
POST admin/single single.store Adm\SingleCustomerController@store api 199
GET admin/single/{single} single.show Adm\SingleCustomerController@show api 199
GET admin/single/{single}/edit single.edit @edit (not defined) api 199
PUT/PATCH admin/single/{single} single.update Adm\SingleCustomerController@update api 199
DELETE admin/single/{single} single.destroy @destroy (only delete($id) exists) api 199
POST admin/sms/table — Adm\SmsController@index api 202
GET admin/sms/customer — Adm\SmsController@getCustomer api 203
POST admin/sms/other — Adm\SmsController@sendSmsToOther api 204
POST admin/notify/customer — Adm\NotifyController@customer api 207
GET admin/notify/unread — Adm\NotifyController@getUnreadNotify api 208
GET admin/notify/read/{id} — Adm\NotifyController@read api 209
POST admin/notify/table — Adm\NotifyController@index api 210
GET admin/notify notify.index Adm\NotifyController@index api 211 (resource)
GET admin/notify/create notify.create @create (not defined) api 211
POST admin/notify notify.store Adm\NotifyController@store api 211
GET admin/notify/{notify} notify.show Adm\NotifyController@show api 211
GET admin/notify/{notify}/edit notify.edit @edit (not defined) api 211
PUT/PATCH admin/notify/{notify} notify.update @update (not defined) api 211
DELETE admin/notify/{notify} notify.destroy @destroy (not defined) api 211
POST admin/log/title — Adm\LogController@queryTitle api 214
POST admin/log/customer/all — Adm\LogController@queryAllCustomer api 215
POST admin/log/customer/{id} — Adm\LogController@queryCustomer api 216
GET admin/log/list/customer — Adm\LogController@listCu api 217
GET admin/log/ago/{id} — Adm\LogController@ago api 218
POST admin/fashion/table — Adm\AdminController@getListFashion api 221
POST admin/branch/table — Adm\BranchController@index api 224
GET admin/branch/active/{id} — Adm\BranchController@activeBranch api 225
GET admin/branch/list — Adm\BranchController@listBranch api 226
GET admin/user/list — Adm\BranchController@listUser api 227 (overridden at :248)
POST admin/branch/product — Adm\BranchController@addProduct api 228
PUT admin/branch/product/{inventory_id} — Adm\BranchController@updateProduct api 229
GET admin/branch/product/{inventory_id} — Adm\BranchController@getProduct api 230
DELETE admin/branch/product/{inventory_id} — Adm\BranchController@deleteProduct api 231
POST admin/branch/product/table — Adm\BranchController@productTable api 232
GET admin/branch/dashboard — Adm\BranchController@dashboard api 233
GET admin/branch/admin/dashboard — Adm\BranchController@adminDashboard api 234
GET admin/branch branch.index Adm\BranchController@index api 235 (resource)
GET admin/branch/create branch.create @create (not defined) api 235
POST admin/branch branch.store Adm\BranchController@store api 235
GET admin/branch/{branch} branch.show Adm\BranchController@show api 235
GET admin/branch/{branch}/edit branch.edit @edit (not defined) api 235
PUT/PATCH admin/branch/{branch} branch.update Adm\BranchController@update api 235
DELETE admin/branch/{branch} branch.destroy Adm\BranchController@destroy api 235
GET admin/get-custom-order/{id} — Api\CustomOrderController@getCustomOrder api 238
PUT admin/custom-order/{id} — Api\CustomOrderController@editCustomOrder api 239
POST admin/get-custom-orders — Api\CustomOrderController@getCustomOrdersAdmin api 240
POST admin/create-custom-order — Api\CustomOrderController@creatCustomOrder api 241
POST admin/workshop/table — Adm\WorkshopController@index api 245
GET admin/workshop/active/{id} — Adm\WorkshopController@activeWorkshop api 246
GET admin/workshop/list — Adm\WorkshopController@listWorkshop api 247
GET admin/user/list — Adm\WorkshopController@listUser api 248 (duplicate path, wins over :227)
POST admin/workshop/product — Adm\WorkshopController@addProduct api 249
PUT admin/workshop/product/{inventory_id} — Adm\WorkshopController@updateProduct api 250
GET admin/workshop/product/{inventory_id} — Adm\WorkshopController@getProduct api 251
DELETE admin/workshop/product/{inventory_id} — Adm\WorkshopController@deleteProduct api 252
POST admin/workshop/product/table — Adm\WorkshopController@productTable api 253
GET admin/workshop/dashboard — Adm\WorkshopController@dashboard api 254
GET admin/workshop/admin/dashboard — Adm\WorkshopController@adminDashboard api 255
GET admin/workshop workshop.index Adm\WorkshopController@index api 256 (resource)
GET admin/workshop/create workshop.create @create (not defined) api 256
POST admin/workshop workshop.store Adm\WorkshopController@store api 256
GET admin/workshop/{workshop} workshop.show Adm\WorkshopController@show api 256
GET admin/workshop/{workshop}/edit workshop.edit @edit (not defined) api 256
PUT/PATCH admin/workshop/{workshop} workshop.update Adm\WorkshopController@update api 256
DELETE admin/workshop/{workshop} workshop.destroy Adm\WorkshopController@destroy api 256
GET admin/ciny/list — Adm\CinyController@listCiny api 261
POST admin/ciny/table — Adm\CinyController@index api 262
GET admin/ciny ciny.index Adm\CinyController@index api 263 (resource)
GET admin/ciny/create ciny.create @create (not defined) api 263
POST admin/ciny ciny.store Adm\CinyController@store api 263
GET admin/ciny/{ciny} ciny.show Adm\CinyController@show api 263
GET admin/ciny/{ciny}/edit ciny.edit @edit (not defined) api 263
PUT/PATCH admin/ciny/{ciny} ciny.update Adm\CinyController@update api 263
DELETE admin/ciny/{ciny} ciny.destroy Adm\CinyController@destroy api 263

admin.php total: 216 registered routes (77 explicit + 139 from 14 Route::resource declarations... see count table §3.6).

3.2 routes/api.php — prefix api, middleware api

Public (no auth):

METHOD path name controller@method middleware/guards line
GET api/user — Closure → $request->user() api + auth:api 31-33
POST api/check/version — Api\ApiMobileController@checkVersion api 37
POST api/login — Api\ApiMobileController@login api 38
POST api/user-auth — Api\ApiMobileController@userAuth api 39
POST api/user-verfiy — Api\ApiMobileController@userVerfiy api 40
POST api/sms — Api\ApiMobileController@sms (method not defined) api 41
GET api/sms — Api\ApiMobileController@sendSms (not defined) api 42
GET api/report/order — Adm\AdminController@generateReportOrder api 43
GET api/report/doc — Adm\AdminController@generateReportDocument api 44
POST api/customer/create — Adm\AdminController@createCustomer api 45
POST api/product/luxe — Api\ApiMobileController@getLuxeProduct api 46
GET api/price — Api\ApiMobileController@PriceFromWebService api 47
POST api/front — Api\ApiMobileController@front api 49
GET api/config — Api\ApiMobileController@getConfig api 50
GET api/product/{id} — Api\ApiMobileController@getProduct api 51
POST api/get-products — Api\ApiMobileController@getProducts api 52
GET api/ciny/{collection_id} — Api\ApiMobileController@getCinyByCollectionId api 53
POST api/get-products/test — Api\ApiMobileController@getProductsTest (not defined) api 54
POST api/log/create/{title} — Api\LogController@create api 57
GET api/log/update/{id} — Api\LogController@update api 58
POST api/major/register — Major\CustomerController@register api 61

Authenticated group — Route::middleware('auth:api-customer') (routes/api.php:64-117); guard = api-customer → Customer model:

METHOD path name controller@method middleware/guards line
GET api/get-custom-order/{id} — Api\CustomOrderController@getCustomOrder api + auth:api-customer 68
GET api/get-custom-orders — Api\CustomOrderController@getCustomOrders api + auth:api-customer 69
POST api/create-custom-order — Api\CustomOrderController@creatCustomOrder api + auth:api-customer 70
POST api/update-custom-order/{id} — Api\CustomOrderController@updateCustomOrder api + auth:api-customer 71
POST api/set-order — Api\ApiMobileController@setOrder api + auth:api-customer 74
POST api/product — Api\ApiMobileController@setProduct api + auth:api-customer 75
POST api/me-data — Api\ApiMobileController@me api + auth:api-customer 76
POST api/get-notify — Api\ApiMobileController@getNotify api + auth:api-customer 77
GET api/notify/count — Api\ApiMobileController@getCountNotify api + auth:api-customer 78
POST api/get-orders — Api\ApiMobileController@myOrder api + auth:api-customer 79
POST api/get-my-findoc — Api\ApiMobileController@myFindoc api + auth:api-customer 80
POST api/update-profile — Api\ApiMobileController@updateProfile api + auth:api-customer 81
POST api/set-findoc — Api\ApiMobileController@setFindoc api + auth:api-customer 82
POST api/my-child — Api\ApiMobileController@myChild api + auth:api-customer 83
POST api/add-to-fav — Api\ApiMobileController@toggleFavorite api + auth:api-customer 84
POST api/get-favorites — Api\ApiMobileController@getFavorites api + auth:api-customer 85
POST api/tokenmobile — Api\ApiMobileController@updateTokenMobile api + auth:api-customer 86
GET api/promotion — Api\ApiMobileController@getPromotion api + auth:api-customer 87
GET api/ignore — Api\ApiMobileController@getIgnore api + auth:api-customer 88
POST api/order/child — Api\ApiMobileController@getChildOrder api + auth:api-customer 89
PUT api/order/child/{id} — Api\ApiMobileController@updateChildOrder api + auth:api-customer 90
PUT api/notify/read/{id} — Api\ApiMobileController@readNotify api + auth:api-customer 91
POST api/file/create — Adm\FileController@storeWithoutData api + auth:api-customer 95
POST api/customer/update — Adm\AdminController@updateCustomer api + auth:api-customer 98
POST api/customer/toggle-active — Adm\AdminController@customerToggleActive api + auth:api-customer 99
POST api/customer/toggle-sts — Adm\AdminController@customerToggleSts api + auth:api-customer 100
POST api/hesab_detail/table — Api\ApiMobileController@hesabDetail api + auth:api-customer 103
POST api/moshtarian — Api\ApiMobileController@moshtarian api + auth:api-customer 104
GET api/tahesab/me — Customer\TahesabController@mandeh api + auth:api-customer 108
GET|POST api/fin_tahesab/table — Customer\TahesabController@index api + auth:api-customer 109
GET api/fin_tahesab/detail/{id} — Customer\TahesabController@detail api + auth:api-customer 110
GET api/fin_tahesab/my_detail/{offset} — Customer\TahesabController@my_detail api + auth:api-customer 111
POST api/major/complete — Major\CustomerController@complete api + auth:api-customer 114

Public (after group):

METHOD path name controller@method middleware/guards line
POST api/sms/batch — Adm\SmsController@batch api 122
POST api/sms/batch/test — Adm\SmsController@testNet api 123
GET api/send/all — Closure — mass-SMS to ALL customers api 126-180
POST api/test — Closure → "this is true" api 184-220
GET api/cities cities.index Adm\CitiesController@index (not defined) api 223 (resource)
GET api/cities/create cities.create @create (not defined) api 223
POST api/cities cities.store Adm\CitiesController@store api 223
GET api/cities/{city} cities.show Adm\CitiesController@show api 223
GET api/cities/{city}/edit cities.edit @edit (not defined) api 223
PUT/PATCH api/cities/{city} cities.update Adm\CitiesController@update api 223
DELETE api/cities/{city} cities.destroy Adm\CitiesController@destroy api 223
POST api/cities/list — Adm\CitiesController@list api 224
GET api/cities/get-percent/{id} — Adm\CitiesController@getPercent api 225 (shadowed)
GET api/cities/get-percent-aux/{id} — Adm\CitiesController@getPercentAux api 226 (shadowed)
POST api/web/auth — WebApp\AuthController@userAuth api 229
GET api/testt — Customer\TahesabController@test api 235

Duplicate name collision: cities.* resource names are registered in BOTH routes/admin.php:168 and routes/api.php:223. Laravel 8 keeps the first registration for name lookup; api.php loads first (RouteServiceProvider:43), so cities.* names resolve to /api/cities/*.

3.3 routes/customer.php — prefix cu, middleware api

Whole file wrapped in Route::middleware('create_log') (routes/customer.php:3).

METHOD path name controller@method middleware/guards line
POST cu/register — Api\SingleCustomerController@register api, create_log 5
POST cu/login — Api\SingleCustomerController@login api, create_log 6
POST cu/verfiy/token — Api\SingleCustomerController@verfiy api, create_log 7
GET cu/order/pdf/{id} — Customer\OrderController@generateReportOrder api, create_log 8

Inner group ['middleware' => ['auth:api-singleCustomer']] (:10-46) — guard api-singleCustomer → SingleCustomer:

METHOD path name controller@method middleware/guards line
POST cu/transaction — Api\SingleCustomerController@getTransaction api, create_log, auth:api-singleCustomer 11
POST cu/update-profile — Api\SingleCustomerController@updateProfile (not defined) ″ 12
GET cu/get-user — Api\SingleCustomerController@getUserInfo ″ 13
GET cu/comment comment.index Customer\CommentController@index ″ 15 (resource)
GET cu/comment/create comment.create Customer\CommentController@create ″ 15
POST cu/comment comment.store Customer\CommentController@store ″ 15
GET cu/comment/{comment} comment.show Customer\CommentController@show($product_id) ″ 15
GET cu/comment/{comment}/edit comment.edit Customer\CommentController@edit ″ 15
PUT/PATCH cu/comment/{comment} comment.update Customer\CommentController@update ″ 15
DELETE cu/comment/{comment} comment.destroy Customer\CommentController@destroy ″ 15
GET|POST cu/fin_tahesab/table — Customer\TahesabController@index ″ 18
GET cu/fin_tahesab/detail/{id} — Customer\TahesabController@detail ″ 19
GET cu/fin_tahesab/my_detail/{offset} — Customer\TahesabController@my_detail ″ 20
GET cu/fin_tahesab/mandeh — Customer\TahesabController@mandeh ″ 21
POST cu/order/table — Customer\OrderController@index ″ 23
GET cu/order/report — Customer\OrderController@report ″ 24
GET cu/order/promotion — Customer\OrderController@getPromotion ″ 25
GET cu/order order.index Customer\OrderController@index ″ 26 (resource)
GET cu/order/create order.create Customer\OrderController@create ″ 26
POST cu/order order.store Customer\OrderController@store ″ 26
GET cu/order/{order} order.show Customer\OrderController@show ″ 26
GET cu/order/{order}/edit order.edit Customer\OrderController@edit ″ 26
PUT/PATCH cu/order/{order} order.update Customer\OrderController@update ″ 26
DELETE cu/order/{order} order.destroy Customer\OrderController@destroy ″ 26
GET cu/fav fav.index Customer\FavController@index ″ 29 (resource)
GET cu/fav/create fav.create Customer\FavController@create ″ 29
POST cu/fav fav.store Customer\FavController@store ″ 29
GET cu/fav/{fav} fav.show Customer\FavController@show ″ 29
GET cu/fav/{fav}/edit fav.edit Customer\FavController@edit ″ 29
PUT/PATCH cu/fav/{fav} fav.update Customer\FavController@update ″ 29
DELETE cu/fav/{fav} fav.destroy Customer\FavController@destroy ″ 29
GET cu/address address.index Customer\AddressController@index ″ 32 (resource)
GET cu/address/create address.create @create (not defined) ″ 32
POST cu/address address.store Customer\AddressController@store ″ 32
GET cu/address/{address} address.show @show (not defined) ″ 32
GET cu/address/{address}/edit address.edit @edit (not defined) ″ 32
PUT/PATCH cu/address/{address} address.update Customer\AddressController@update ″ 32
DELETE cu/address/{address} address.destroy Customer\AddressController@destroy ″ 32
POST cu/set-default — Customer\AddressController@setDefaultAddress ″ 33
POST cu/transaction/gateway — Customer\TransactionController@gateway ″ 36
POST cu/product/variant — Customer\ProductController@getVariant ″ 39
GET cu/customer/wallet — Customer\CustomerController@getWallet ″ 42
POST cu/customer/wallet/transaction — Customer\CustomerController@detailWallet ″ 43

3.4 routes/site.php — prefix site, middleware api

METHOD path name controller@method middleware/guards line
GET site/test — Closure → 'this is test' api 4-6
GET site/get-config — Api\SiteController@config api 8
POST site/config — Api\SiteController@newConfig api 9
POST site/products — Api\SiteController@Products api 10
GET site/get-product — Api\SiteController@getProduct api 11
GET site/front — Api\SiteController@ّFront (note leading Arabic kasra U+0651 in method name) api 12
GET site/counter — Api\SiteController@counterInstagram api 13
GET site/price — Closure → WebServiceGold::getAllPrice() api 14-16
POST site/get/products — Api\SiteController@getProductsVaraints api 17
POST site/get/fashion — Api\SiteController@setRequestFashion api 18
GET site/product/ready — Api\SiteController@readySend api 19
GET site/te/print/{id} — Closure → DB\Te\TableEngine::viewPrint($id) api 22-24
GET site/comment/{id} — Customer\CommentController@show api 26
GET site/app/download — Api\SiteController@downloadApk api 27
GET site/fix-cat — Closure — one-off category remap, dd()s api 30-65
GET site/const/{id} — Adm\ConstController@show api 68
GET site/body/{id} — Site\CollectionController@getBody api 71
POST site/category/product — Site\CollectionController@products api 72
GET site/product — Site\SiteController@getProduct api + version 75-78
GET site/product/random — Api\SiteController@getRandomProduct api 79
GET site/login/active — Api\SiteController@counterActive api 80
GET site/landing/page — Api\SiteController@counterLanding api 81
POST site/test — Site\SiteController@products api 83
GET site/customer — Site\SiteController@getCustomer api 84
GET site/tag — Site\SiteController@addTag api 85
GET site/birthday — Site\SiteController@getBirthday api 86
GET site/service — Site\SiteController@serviceGold api 87
GET site/test/tr — Site\SiteController@test123 api 88
GET site/test/active — Site\SiteController@searchDeactive api 89
GET site/test/g — Site\SiteController@testG api 90

3.5 routes/web.php — no prefix, middleware web

METHOD path name controller@method middleware/guards line
GET|POST /fin_tahesab/table — Customer\TahesabController@index web 26
GET /fin_tahesab/detail/{id} — Customer\TahesabController@detail web 27
GET /fin_tahesab/my_detail/{offset} — Customer\TahesabController@my_detail web 28
GET /fin_tahesab/mandeh — Customer\TahesabController@mandeh web 29
GET / — Closure — scrapes tgju.org and writes gold_price + gold_price_pwa ConfigStatic web 32-124
GET /login — Closure — Link::set(...) + redirect to https://henzagold.com/app web 127-130
GET /download — Closure — Link::set(...) + redirect to APK web 131-134
GET /totalify — Closure — recount category totals, dd()s web 137-152
GET /confirem/order — Adm\AdminController@confiremOrder web 156
GET /test2 — Closure — mass-SMS to ALL customers web 158-186

3.6 Route counts per file

File Explicit routes Route::resource blocks Routes from resources (7 each) Total registered
routes/admin.php 117 14 98 215
routes/api.php 63 1 7 70
routes/customer.php 16 4 28 44
routes/site.php 30 0 0 30
routes/web.php 10 0 0 10
TOTAL 236 19 133 369

Resource blocks: admin.php:71,79,129,132,138,151,155,168,182,199,211,235,256,263 (14); api.php:223 (1); customer.php:15,26,29,32 (4).


4. Controllers (app/Http/Controllers, recursive)

24 controllers total (excluding base Controller.php, which is listed separately as it holds shared business logic).

Controller Public methods
Controller.php (base) addLimit, convert, createTransactionOrder, createSingleOrderActivity, createSingleCustomerOrders, createSingleCustomerOrderItems, createPromotionForOrder, afterCreateOrder, createTransactionInterface, checkCustomer
Adm/AdminController.php __construct, login, getProducts, queryCategory, getCustomer, getReagent, getBanker, getShopkeeper, getSingleCustomer, updateCustomer, createCustomer, queryCustomer, queryReagent, customerToggleSts, customerToggleActive, confiremOrder, getAnalytics, getAnalyticsTak, addProduct, addVariant, getVariant, getVariants, getConfigStatics, getProduct, deleteProduct, getCustomerById, getCategory, AddCategory, getOneCategory, deleteCategory, getSingleOrders, changePercent, countProductForPercent, generateReportOrder, orderStsSingle, chargeWalletAfterOrder, getHavaleList, changeAll, generateReportDocument, getListFashion
Adm/BranchController.php index, store, show, update, destroy, activeBranch, listBranch, listUser, allocateProduct, addProduct, updateProduct, getProduct, deleteProduct, createInventoryTransaction, productTable, dashboard, adminDashboard
Adm/BrandController.php index, store, update, destroy
Adm/CashController.php index, create, store, show, edit, update, destroy, toggleConfiremCash
Adm/CategoryController.php index
Adm/CinyController.php store, update, destroy, show, listCiny, index
Adm/CitiesController.php store, destroy, show, list, getPercent, getPercentAux, update
Adm/CommentController.php index, create, store, show, edit, update, destroy, changeStatus
Adm/ConstController.php store, destroy, deleteById, show, update
Adm/DashboardController.php getAll, change, info, link
Adm/FileController.php index, store, storeWithoutData, show, update, destroy, updateBody
Adm/IgnoreController.php index, store, show, destroy
Adm/LogController.php queryTitle, queryAllCustomer, queryCustomer, queryForLog, listCu, ago
Adm/MajorCustomerController.php index, dashboard, order, cash, shopkeeper, indexSms, verifyRegister, indexArchive, indexVerify, archive, listTypeCustomer
Adm/MajorOrderController.php index, create, store, show, edit, update, destroy, getTaminOrders, orderSts, orderItemEdit, deleteOrder, deleteOrderItem
Adm/NotifyController.php store, customer, index, getUnreadNotify, show, read
Adm/OrderController.php getType, store, update
Adm/PermissionController.php create, store, destroy, has, get, getByUt
Adm/ProductController.php createImage, store, show, update, testSearch, report, color, getProductsVaraints, changeOffer, changeIsExist, changeHasWarranty
Adm/PromotionController.php index, create, createTablePromotionProduct, createPromotionProduct, store, show, edit, update, destroy, updateAutoPromotion, getAutoPromotion, getBrand
Adm/ReportController.php __construct, collection, registerEvents, headings, getOrderItemWithDetails (implements Maatwebsite Excel export contracts)
Adm/SingleCustomerController.php store, update, delete, show, indexOrder, indexTransaction, indexSms, getWallet, report
Adm/SmsController.php batch, testNet, replaceName, index, getCustomer, sendSmsToOther
Adm/UserController.php store, index, destroy, update, show, showData
Adm/WalletController.php charge, changePercent, index, setConst, getConfig, getConfigBirthday
Adm/WorkshopController.php index, store, show, update, destroy, activeWorkshop, listWorkshop, listUser, allocateProduct, addProduct, updateProduct, getProduct, deleteProduct, createInventoryTransaction, productTable, dashboard, adminDashboard
Api/ApiMobileController.php userAuth, userVerfiy, login, me, setFindoc, updateProfile, getProduct, myChild, myOrder, getNotify, getCountNotify, myFindoc, front, getCinyByCollectionId, getProducts, setProduct, toggleFavorite, getFavorites, updateTokenMobile, getConfig, getPromotion, getIgnore, setOrder, getChildOrder, readNotify, updateChildOrder, getLuxeProduct, checkVersion, PriceFromWebService, hesabDetail, moshtarian, moshtarianFilter
Api/CustomOrderController.php getCustomOrders, getCustomOrdersAdmin, getCustomOrder, editCustomOrder, creatCustomOrder, updateCustomOrder, acceptCustomOrder, deleteCustomOrder
Api/CustomerController.php getVaraints
Api/LogController.php create, update
Api/SingleCustomerController.php register, verfiy, login, getTransaction, getUserInfo
Api/SiteController.php getConfig, config, newConfig, getMenu, getProduct, sendDiscount, products, searchProduct, ّFront, getProductsVaraints, test, counterInstagram, getRandomProduct, counterActive, counterLanding, setRequestFashion, readySend
Customer/AddressController.php index, store, update, destroy, setDefaultAddress
Customer/CommentController.php index, create, store, show, edit, update, destroy
Customer/CustomerController.php getWallet, detailWallet
Customer/FavController.php index, create, store, show, edit, update, destroy
Customer/OrderController.php index, create, store, cancel, show, edit, update, destroy, report, generateReportOrder, getPromotion
Customer/ProductController.php getVariant
Customer/TahesabController.php index, my_detail, detail, mandeh, test
Customer/TransactionController.php gateway
Major/CustomerController.php register, complete, sendSmsToAdmin
ProductController.php (root) index
Site/CollectionController.php getBody, products
Site/SiteController.php products, getCustomer, getProduct, addTag, getBirthday, serviceGold, test123, searchDeactive, testG
WebApp/AuthController.php userAuth

Controller count: 46 files (45 concrete controllers + base Controller.php).


5. Models (app/Models) — 57 files

Selector (app/DB/Selector.php) is a shared trait providing Jalali accessors (caj,uaj,eaj,daj), sts_str, type_str, sts_verify_step_one_str/two_str, type_show_str, birth_date_j, brj, expire_at_j, plus static lookups GetSts, GetTypes, GetConfirmed, GetShowType, GetStsVerifyStepOne/Two, selectWithjDate, convertColumns (app/DB/Selector.php:57-206). Duplicated at app/Te/* and app/DB/Te/* (TableEngine).

Model Table Key fillable Casts Relations Scopes Constants / statics Accessors / mutators
ApkLog :14 apk_log :17 ip,version :30 — — — $timestamps=false :19; boot() :21 —
Branch :10 (branches) name,address,phone,user_id,is_active :13 is_active→bool :20 user()→User :23 — — —
Category :10 category_collection :32 title,parent_id_id,priority,image_id,meta,body,icon_id,disabled,type,total,is_master,header,is_active :16 disabled,is_active→bool :45 parent() hasOne self :51; childs() hasMany self :57; image()→Image :63; icon()→Image :68 scopeDesktop :74, scopeMobile :80 reloadTotal($id) :86, reloadCategory($cats,$pid) :93 $hidden :34
Ciny :9 cinies title,icon_id,collection_id,is_active,description :12 :19 icon()→Image :22; collection()→Category :26 — — —
CinyProduct :9 ciny_products product_id,ciny_id :12 — product() :16; ciny() :20 — — —
City :9 cities title,parent,level,percent,percent_aux :14 — — — — —
Collect :9 category_collect :14 collection_id_id,product_id_id :16 — product() :21; collection() :26 — — —
Comment :10 (comments) product_id,comment,reply_to,sts,customer_id :16 — Reply() hasMany self :31; customer()→SingleCustomer :36; product() :42 — $SELECT_CAJ (via Selector) —
ConfigStatic :10 config_statics :15 key,val :17 (val→array commented out :21-23) — — getValue($key) :25 — throws NotFoundHttpException if 0 rows —
CustomOrder :12 (custom_orders) customer_id,file_id,city_id,weight,color,size,sum,color_stone,color_mina,workshop_id,sts,description :17 sts→int, weight/sum→float, deleted_at→datetime :32 file()→Image :77; customer() :81; CustomOrderLog() hasMany :85 — $appends=['sts_str_en','sts_str_fa','time_creat_fa','time_update_fa'] :15 getTimeCreatFaAttribute :59, getTimeUpdateFaAttribute :63, getStsStrEnAttribute :68, getStsStrFaAttribute :73
CustomOrderLog :10 — :15 :23 order() :37; user() withDefault :43 — $appends :13 getTimeCreatFa/UpdateFa :28,:32
Customer :13 (Authenticatable, guard api-customer) customers api_token,address,phone,fname,lname,name,mobile,rnd,ncode,notify_count,total_order,gram_level,percent,input,output,remain,city_id,new_city,rial_remain,rial_output,rial_input,reagent_id,type,open_order,child,sts,token_mobile,send_password,store_name,zone,pasazh_name,active,birth_date,marriage_date,image_id,mcode,sts_verify_step_one,sts_verify_step_two,is_archive,business_license_image_id,shop_image_id,ncode_image_id :18-72 is_archive→bool :73 reagent() :119; cash() hasMany Major\Cash :124; order() hasMany :130; orderOne() (sts=6) :135; children() hasMany Order by reagent_id :140; city() :145; image() :166; business_license_image() :170; shop_image() :174; ncode_image() :178; workshop() :182 scopeSelectify :105, scopeActive :162 $hidden=['password','send_password'] :83 setPasswordAttribute (Hash) :100; getToAttribute :110; getOrderTitleAttribute :115; getRemainAttribute :150; getGramsSellAttribute :156
CustomerTest :13 customers_test :18 mirror of Customer :20 — same set :94-137 scopeSelectify,scopeActive $hidden :62 same
Fav :14 fav :17 customer_id,product_id :23 — product() (active only) :30; customer() :34 — $timestamps=false :22; composite PK (migration) —
Image :8 image :13 title,position,image,resize*,link,width,height,banner,original_name,ext,body :15 — product() :42; productImage() :46; pi() :53 — $SELECT_FULL getFullAttribute :35, getImageAttribute :58
InventoryBranch :10 — :13 — allocator_user() :20; branch() :24; product() :28 — — —
InventoryTransaction :9 — product_id,product_variant_id,branch_id,allocator_user_id,order_id,type :12 — product() :25; branch() :29; product_variant() :33; allocator_user() :37 — — —
Kids :10 kids :15 :17 — — — — —
Link :8 (links) :11 — — — set($url) :15 — click tracker —
Log :9 (logs) customer_id,time_present,start_at,end_at,ip,title,data,title_fa,product_id :12 data→array :23 customer() :27; product() :31 — — —
Major\Cash :13 (cashes) user_id,customer_id,input,output,remain,rial_input,rial_output,rial_remain,type,sts,title,to,note,ayar,lab,balance,value,price,confirmed,no,proceed_at,account_name,bank_name,recive_date,order_id,ang,original_value,price_per_gram,discount :19 — customer() :86 scopeMe :74 $TYPES = [9=>سفارش, 1=>آب شده, 2=>حواله, 3=>چک, 4=>پولی] :56; $STS = [-1=>بررسی نشده, 1=>ثبت سند] :63; $CONFIRMED = [1=>تایید شده, 0=>تایید نشده] :68 getTimeAttribute :81; getValueAttribute → Utility::round() :91; getConfirmedStrAttribute :96; $appends=['time','confirmed_str'] :51
Major\Favorite :9 major_favorites :14 :16 — — — — —
Major\Promotion :14 major_promotion :21 title,description,start_at,end_at,type,type_customer,discount_percent,discount_price,is_active,use_only,show :32 is_active,use_only,show→bool :57 items() hasMany PromotionItem :86 scopeActive :24, scopeWeb :27 safeDelete($promotionID) :79 getStartAtjAttribute :69, getEndAtjAttribute :74, getItemsAttribute :91; $appends :63
Major\PromotionIgnore :11 major_promotion_ignores :17 :19 — — — — —
Major\PromotionItem :11 major_promotion_item :17 :19 — promotion() :24 — — —
Major\PromotionUsed :10 major_promotion_used :16 customer_id,promotion_id,promotion_item_id,order_id,order_item_id :18 — — — — —
Notification :11 — :13 :21 user() :24; customer() :28 — store($token,$title,$body) :33 (FCM) —
Notify :14 notify :17 title,customer_id,user_id,note,read,value,type,type_send,sender_id :21 read→bool :32 — scopeMe :50 store($token,$title,$body) :57 (FCM push); sendToGroup($tokens,$title,$body) :88 —
Order :16 (major/wholesale order) orders customer_id,reagent_id,type,input,output,remain,w,wage,city_id,price,percent,sts,confirmed,rial_input,discount :25 (empty :144) items() hasMany OrderItem :149; customer() :156; parent()→Customer by reagent_id :168; activity() hasMany OrderActivity :173; cashe() hasOne Major\Cash by order_id :232 scopeMe :161 $TYPES=[1=>ثبت سفارش توسط مسئول فروش, 2=>ثبت مشتری] :45; $CONFIRMED=[1=>تایید شده,2=>در انتظار تایید] :60; $STS = [0=>معلق, 1=>ثبت سفارش, 2=>تایید مدیر سیستم, 3=>درحال تامین, 4=>درحال آماده سازی, 5=>تحویل مسئول فروش, 6=>تحویل مشتری] :65; $STS_TAB :73; $STS_COLOR :105; $STS_IMG :122; $SELECT_COLOR,$SELECT_IMG :23-24; safeDelete($orderID) :211 getConfirmedStrAttribute :178, getColorAttribute :184, getImgAttribute :190, getInputAttribute :197, getPercentAttribute :202, getWageAttribute :207, getWAttribute :222, getTimeAttribute :227; $appends=['time','confirmed_str'] :121; $hidden :138
OrderActivity :10 order_activity :13 title,note,user_id,customer_id,order_id,meta,proceed,key :17 :28 order() :34; customer() :39; user() :44 — — —
OrderItem :10 order_items order_id,variant_id,product_id,product_title,variant_title,percent,price,rial_pay,note,wage,qty,sts,w,rash_weight,original_rash_weight,discount,original_percent :15 — product() :36; variants()→ProductVariant :40; order() :54 — — getWAttribute → Utility::round :45; getWageAttribute :49
Permission :7 permission :14 rid,ut :9 — — — Composite PK ['rid','ut'] :16; $timestamps=false :17; $incrementing=false :18 —
Product :14 product :20 title,body_html,desk_note,product_code,indicator_id_id,mobile_pic_id,number_of_purchase,is_active,brand_id,disabled,file_id,show_type,delivery_type,message_long_delivery,count_fav,count_order,count_view,min_gram,max_gram,offer_day,branch_id,inventory_id,is_exist,has_warranty :22 is_active,disabled,offer_day,is_exist,has_warranty→bool :60 images() :75; ciny() :79; thumb() :90; tmobile() :96; variants() (active) :102; variantsAll() :106; variantOne() :111; variantsPromotion() :116; collect() :123; category() :128; image() :140; brand()→ProductBrand :145; gallery() hasManyThrough :153; file() :187; tags() :192; promotion()→PromotionProduct :196; inventory()→InventoryBranch :204; branch() :209 scopeCool :69, scopeMobile :173, scopeSite :178, scopeActive :182 safeDelete($productId) :165 —
ProductBrand :10 product_brand :17 :19 — — — — —
ProductImage :9 products_productimage :14 :15 — image() :22; product() :27 scopeMobile :32, scopeDesktop :37 — —
ProductTags :10 product_tags :16 product_id,const_id :18 — product() :24; cnt()→ConfigStatic :28 — $timestamps=false :15 —
ProductVariant :15 products_productvarient :20 title,qty,grams,percentage_pay,product_id_id,barcode,color,width,length,height,rial_pay,inventory,details,description,meta,position,requires_shipping,taxable,is_pre_order,is_active :24 is_pre_order,is_active→bool; rial_pay,percentage_pay,grams→double :121 product() :312; promotion() :316; inventory()→InventoryTransaction :324; inventory_branch() :328 — $product_price_extra_percent (loaded in boot() from ConfigStatic product_price_extra_percent, default 7) :45-52; $goldPrice :132; $dis_product :133; $COLOR_STR :57; $COLORS = [0=>سفید,1=>زرد,2=>شکلاتی,3=>رزگلد] :94 getPriceAttribute :156 (core gold price formula); getPriceWithDiscountAttribute :248; getColorStrAttribute :135; $appends=['price','color_str','price_with_discount'] :115
PromotionProduct :9 promotion_products promotion_id,promotion_item_id,product_variant_id,product_id,discount,type,active,start_at,end_at,use_only :12 active,use_only→bool :28 — — — —
RequestFashion :8 — :11 — — — — —
RequestLog :9 (request_logs) customer_id,ip,device,data,user_agent,route,method :14 data→array :23 — — UPDATED_AT = null :12; $timestamps=['created_at'] :13 —
SingleCustomer :13 (Authenticatable, guard api-singleCustomer) login :19 id,password,username,lname,fname,name,phone,email,user_type,is_active,last_login,token_sms,percent,birth_day,branch_id :21 — transaction() :45; branch() :48 — $hidden=['password'] :39 setPasswordAttribute (Hash) :41
SingleCustomer\OrderActivity :10 orders_histroy :17 :19 :28 — — — —
SingleCustomer\PromotionUsed :10 single_promotion_used :15 :17 — — — — —
SingleCustomerAddress :13 accounts_address :19 reciver_lname,reciver_fname,reciver_phone,reciver_fixed_phone,province,city,zipcode,address,latitude,longitude,is_default,user_id_id :21 (empty :36) — — — —
SingleCustomerOrderItems :12 orders_orderitem :18 title,price,approximate_price,qty,deposit,amount_paid,approximate_gram,exact_gram,debtor_amount,is_active,supply_at,delivery_at,order_id,product_id,variant_id,grams,rial_pay,variant_title,is_preorder,promotion_id,promotion_item_id,total_discount,total_price,gold_price_in_formula,branch_id :20 is_preorder→bool :48 product() :54 — — —
SingleCustomerOrders :13 (retail order) orders_orders :19 app,billing_address,browser_ip,buyer_accepts_marketing,email,phone,note,prcessing_method,processed_at,shipping_address,shipping_line,subtotal_price,discount_codes,total_discount,total_price (pre-discount),price (post-discount),total_tax,total_weight,tags,sts,is_active,canceled_at,canceled_reason,closed_at,send_time_id,user_id_id,gold_price,gold_price_original,type,reagent_id,use_wallet,payment_after_wallet,branch_id :21 shipping_address→array, use_wallet→bool :61 items() :84; customer()→SingleCustomer by user_id_id :93; user()→User by reagent_id; branch(); activity() hasMany SingleCustomer\OrderActivity — $STS = [1=>ثبت سفارش, 2=>تایید مدیر سیستم, 3=>در حال تامین, 4=>در حال آماده سازی, 5=>خروج از انبار, 6=>ارسال, 7=>تحویل مشتری] :66; $TYPES = [1=>تلفنی,2=>تلگرام,3=>واتس آپ,4=>اینستا,5=>حضوری] :76 getStsStrAttribute :88; $appends=['sts_str'] :57
SingleCustomerTransaction :16 transactions_transaction :22 amount,transaction_type,sts,message,receipt,gateway,is_active,order_id_id,user_id_id :24 — — — createAndGetToken($order,$ip) :38 — payping/zarinpal payment init (hardcoded amount 1000, hardcoded bearer token :86) —
Sms :12 messages :16 customer_id,mobile,massage,token,type,user_id :44 — — — $TYPES=[-1=>یک شماره تلفن,0=>همه کاربران,1=>کارشناسان فروش,2=>مشتریان عمده,9=>چند شماره تفن] :53; Send($to,$msg,…) :61; SendSms(...) :89; set(...) :125 —
TransactionOrder :8 (transaction_orders) customer_id,order_id,total_price,transaction_type,total_weight,order_date,payment :11 payment→bool :20 — — — —
User :12 (Authenticatable, guard api/web) users name,fname,lname,mobile,ut (user type = role id),city_id,token_mobile,branch_id :22 email_verified_at→datetime :48 user_type()→ConfigStatic by ut :51 — $hidden=['password','remember_token'] :38; SoftDeletes :15 —
Utility :6 (not a real table) — — — — $formatJ='Y/n/j-H:i' :8; round($value) → round($value, 2) :10; convertDate() (Jalali) :15; faTOen() Persian/Arabic digit → ASCII :26; baseURLStorage() = https://henzagold.com/oapi/storage/ :30 —
WebServiceGold :13 (not a real table) — — — — getPriceGold18Ayar() :17 — reads ConfigStatic['gold_price'], geram18.p, strips commas, intval, /10 (rial→toman); getAllPrice() :27; getAllPriceFromWebService() :33 — ratebox.ir feed, maps 4→mesghal, 5→geram18, 6→geram24, writes ConfigStatic['gold_price'] only when all three present —
Workshop :10 (workshops) name,address,phone,user_id,is_active :13 is_active→bool :20 user()→Customer (note: class mismatch vs. column) :23 — SoftDeletes :12 —

Model count: 57 files under app/Models (incl. 6 in Major/, 2 in SingleCustomer/, and Selector.php which is a trait, not a model).


6. Database

6.1 Migrations — database/migrations (31 files)

# File Op Table Key columns
1 2014_10_12_000000_create_users_table.php create users id, name, mobile unique, password, rememberToken, timestamps, softDeletes (:16-23)
2 2014_10_12_100000_create_password_resets_table.php create password_resets mobile index, token, created_at nullable (:16-19)
3 2019_08_19_000000_create_failed_jobs_table.php create failed_jobs id, uuid unique, connection, queue, payload, exception, failed_at useCurrent (:16-23)
4 2020_10_01_120354_order_table.php create orders id, customer_id uint, reagent_id uint null, type tinyint, input/output/remain/w/wage/percent double null, sts tinyint null, timestamps, softDeletes (:16-29)
5 2020_10_01_120408_order_items_table.php create order_items id, order_id, product_id, product_title, variant_title, w/wage/percent double null, timestamps (:16-25)
6 2020_10_01_120430_customers_table.php create customers id, fname(50), lname(50), name(75), mobile(20), ncode(20), password, input/output double, remain double default 0, rial_input/rial_output/rial_remain bigint uint, reagent_id, type/sts tinyint, timestamps, softDeletes (:16-34)
7 2020_10_01_120914_cash_table.php create cashes id, user_id, customer_id, input/output/remain double, rial_* bigint, type/sts tinyint, timestamps, softDeletes (:16-29)
8 2020_10_19_153228_customer_add.php alter customers +api_token(60), rnd(60), notify_count def 0, total_order def 0, gram_level double def 0, percent double def 0, open_order def 0, child def 0 (:26-34)
9 2020_10_25_155247_customers_cols.php alter customers +phone(15), address (:16-18)
10 2020_10_25_164102_order_acitvity.php create+alter order_activity; order_items; orders; cashes create order_activity: id,title(50),note,user_id,customer_id,order_id,meta json,timestamps (:16-24). alter order_items: +variant_id,price double,sts tinyint,qty (:26-30). alter orders: +price double (:32-34). alter cashes: +title,to,note,ayar(20),lab,balance double,value double,price bigint (:36-44)
11 2020_10_25_170047_notify_table.php create notify id,title,customer_id,user_id,note(512),type tinyint,value tinyint,read bool def false,timestamps (:16-25)
12 2020_10_27_192859_proceed_activity.php alter order_activity +proceed bool def false (:16-17)
13 2021_09_18_115342_permissions_table.php create permission rid string, ut int, primary(['rid','ut']) (:16-19)
14 2021_09_18_164552_file_id_product.php alter product +file_id uint null (:16-17)
15 2021_09_18_171700_city_table.php create+alter cities; users; orders create cities: id,title(50),parent,level,percent float,timestamps,softDeletes (:16-23). alter users: +ut uint null, city_id (:27-29). alter orders: +city_id (:32-33)
16 2021_09_18_172722_cities_p_2.php alter cities +percent_aux float null (:16-17)
17 2021_09_21_160213_product_tags.php create product_tags id increments, product_id, const_id (:16-19)
18 2021_09_28_173620_customer_city_id.php alter customers +city_id uint null (:16-17)
19 2021_10_21_092358_fav_table.php create fav customer_id, product_id, primary(['customer_id','product_id']) (:16-19)
20 2021_10_21_094849_apk_log.php create apk_log id,ip(15),version,created_at (:16-20)
21 2021_11_01_155307_mobile_note.php alter product +desk_note null (:16-17)
22 2021_11_01_162712_cat_image.php alter category_collection +image_id null (:16-17)
23 2021_11_01_164540_cat_image_total.php alter category_collection +total def 0 (:16-17)
24 2021_11_03_113752_icon_category.php alter category_collection +icon_id null (:16-17); down() targets category (mismatch, :28)
25 2021_11_07_103558_product_gallery_id.php alter products_productimage +w string null (:16-17)
26 2021_11_15_202459_type_category.php alter category_collection +type tinyint null (:16-17)
27 2021_11_17_105202_body_category.php alter category_collection +body null (:16-17)
28 2021_11_23_114049_product_disabled.php alter product; category_collection +disabled bool def false (:16-17); category_collection.disabled bool nullable(false) (:20-21)
29 2021_12_18_161611_create_promotion_products.php create promotion_products id,promotion_id,promotion_item_id,product_variant_id,product_id,discount_percent double,discount_price double,timestamps (:16-24)
30 2024_06_14_232311_create_cinies.php create cinies id,title(150),icon_id,collection_id,is_active bool def 1,description(1024),timestamps,softDeletes (:16-24)
31 2024_06_21_203640_create_ciny_products.php create ciny_products id,product_id,ciny_id,timestamps,softDeletes (:16-21)

Package migration (autoloaded via WalletServiceProvider):

File Table Columns
packages/rooyesh/wallet/src/migrations/2021_12_02_065938_create_wallet_moudle_table.php:16-39 wallets id, owner_type enum(1=user,2=shop) def 1, timestamps, owner bigint, gold double (gold grams held), hash(128) null, credit bigint, unique(['owner','owner_type'])
″ :41-56 transactions id, wallet bigint uint, transaction_type enum(1=gold,2=credit,3=expire) def 1, timestamps, value bigint, expire_at datetime null, hash(128) null, note text null, customer_id bigint uint null
″ :58-66 transaction_metas transaction bigint uint, order_id bigint uint null, total_weight double uint null, percent int uint null, order_date timestamp null, id, timestamps

Note: transactions migration lacks a balance column, but TransactionInterface writes $_inp['balance'] (packages/rooyesh/wallet/src/interfaces/TransactionInterface.php:141) and hashes it (:110) — the column exists in the live DB but not in this migration.

6.2 Seeders — database/seeders

File Content
database/seeders/DatabaseSeeder.php:14-17 run() is empty — the only line is a commented User::factory(10)->create() (:16). No seeders exist.

Factory: database/factories/UserFactory.php (default Laravel).

6.3 Final schema (tables referenced by models but NOT in migrations)

These tables exist in the production DB (legacy/Django-imported; names like orders_orders, accounts_address, products_productvarient indicate a Django origin) and are only known through model $table + $fillable:

Table Model Source
login SingleCustomer app/Models/SingleCustomer.php:19
orders_orders SingleCustomerOrders app/Models/SingleCustomerOrders.php:19
orders_orderitem SingleCustomerOrderItems app/Models/SingleCustomerOrderItems.php:18
orders_histroy (sic) SingleCustomer\OrderActivity app/Models/SingleCustomer/OrderActivity.php:17
accounts_address SingleCustomerAddress app/Models/SingleCustomerAddress.php:19
transactions_transaction SingleCustomerTransaction app/Models/SingleCustomerTransaction.php:22
products_productvarient (sic) ProductVariant app/Models/ProductVariant.php:20
products_productimage ProductImage app/Models/ProductImage.php:14
product Product app/Models/Product.php:20
product_brand ProductBrand app/Models/ProductBrand.php:17
category_collection Category app/Models/Category.php:32
category_collect Collect app/Models/Collect.php:14
image Image app/Models/Image.php:13
config_statics ConfigStatic app/Models/ConfigStatic.php:15
messages Sms app/Models/Sms.php:16
major_promotion Major\Promotion app/Models/Major/Promotion.php:21
major_promotion_item Major\PromotionItem :17
major_promotion_used Major\PromotionUsed :16
major_promotion_ignores Major\PromotionIgnore :17
major_favorites Major\Favorite :14
single_promotion_used SingleCustomer\PromotionUsed :15
customers_test CustomerTest :18
kids Kids :15
transaction_orders TransactionOrder implicit
branches, workshops, inventory_branches, inventory_transactions, custom_orders, custom_order_logs, comments, logs, request_logs, links, notifications, request_fashions respective models implicit (no migration)

Table count: 31 migration-created + 3 wallet package + ~28 legacy/implicit ≈ 62 tables. Only 34 have migrations.


7. Business logic

7.1 Gold price

Concern Where Detail
Price source of truth app/Models/ConfigStatic.php:15 key gold_price JSON blob with mesghal, geram18, geram24 (each with p price string, h, l, updated_at, uaj Jalali)
18-ayar price read app/Models/WebServiceGold.php:17-25 getPriceGold18Ayar() = intval(str_replace(',','', $data['geram18']['p'])) / 10 — rial→toman conversion baked in
All prices app/Models/WebServiceGold.php:27-31 getAllPrice() returns whole decoded blob
Feed #1 (ratebox.ir) app/Models/WebServiceGold.php:85-116 Http::get('https://api.ratebox.ir/apijson.php?token='.env('WEBSERVICE_TOKEN')); maps index 4→mesghal, 5→geram18, 6→geram24; only writes gold_price if all three arrive (:109-112)
Feed #2 (tgju.org) app/Console/Commands/GetGoldPriceForPwa.php:45-71 https://call3.tgju.org/ajax.json, whitelist of 10 slugs (geram18, silver_999, mesghal, price_dollar_rl, sekeb, rob, nim, sekee_down, rob_down, nim_down); writes both gold_price_pwa and gold_price
Feed #3 (duplicate in web route) routes/web.php:32-124 GET / runs the same tgju scrape inline and writes both keys
Feed #4 (unused) app/Http/Controllers/Site/SiteController.php:261 ratebox again
Live price endpoints routes/admin.php:51, routes/site.php:14, routes/api.php:47 GET admin/price, GET site/price (closures), GET api/price → ApiMobileController@PriceFromWebService:886
No websocket / live push — see §10

7.2 Gram / weight calculation & pricing formula

Retail (SingleCustomer) price per variant — app/Models/ProductVariant.php:156-180 (getPriceAttribute):

G = ProductVariant::$goldPrice                 // injected per-request, = getPriceGold18Ayar()
E = static::$product_price_extra_percent       // ConfigStatic 'product_price_extra_percent', default 7  (:45-52)
p = G + G * ((percentage_pay + E) / 100)       // ساخت/اجرت  (making charge %)
p = p + p * 0.07                               // +7%  (سود / profit margin)
t = p - G                                       // isolate the non-metal portion
t = t + t * 0.09                               // +9% VAT applied ONLY to the non-metal portion
p = G + t
p = p * grams
return floor(p / 1000) * 1000                  // round DOWN to nearest 1,000 toman

Note rial_pay (stone cost) is not added in the current formula — only in the commented-out older variants (:183-206).

With promotion discount — app/Models/ProductVariant.php:248-296 (getPriceWithDiscountAttribute):

  • Looks up self::$dis_product (pre-loaded PromotionProduct array) by product_id_id (:250-252)
  • If use_only and a SingleCustomer\PromotionUsed row exists for auth()->id() + promotion_id → discount forced to 0 (:253-257)
  • type == 1 → discount_percent; else → discount_price (a percent, applied as $price -= $price*($discount_price/100) :293)
  • Discount percent is subtracted from the 7% margin: $price += $price * (0.07 - $discount_percent/100) (:289) — i.e. a discount erodes margin, not metal
  • Same floor(/1000)*1000 rounding (:294)

Wholesale (major Customer) order gram math — app/Http/Controllers/Api/ApiMobileController.php:538-563 (setOrder):

percent   = item.percent_pay - item.discount
gram_item = rash_weight + rash_weight * (percent/100)
allGram   = Σ gram_item * qty                     // total gold grams owed
wage      = Σ rash_weight * qty                   // net metal weight
order.wage = allGram - wage                        // the "اجرت" portion, in grams
rial_input = Σ rial_pay * qty                      // stone/other rial charges
discount   = Σ item.discount

Per line item written at :617-634 with both rash_weight and original_rash_weight preserved, and w = rash_weight * (1 + percent/100).

Per-item implied gold price stored on retail orders — app/Http/Controllers/Controller.php:144: gold_price_in_formula = (item.total_price / item.qty) / item.grams

7.3 Fees / commissions / tax / spread / rounding

Item Value Where
Making-charge extra % product_price_extra_percent ConfigStatic, default 7 app/Models/ProductVariant.php:45-52
Profit margin hardcoded 7% (0.07) ProductVariant.php:175, :289
VAT hardcoded 9% (0.09), applied only to price - goldPrice ProductVariant.php:178, :291
Rounding (price) floor($price/1000)*1000 — round down to 1,000 toman ProductVariant.php:180, :294
Rounding (weight display) round($value, 2) — 2 decimals app/Models/Utility.php:10-13; used by Order::getW/Wage, OrderItem::getW/Wage, Major\Cash::getValue
Cashback % percent ConfigStatic (global) app/Http/Controllers/Adm/AdminController.php:994
Cashback expiry (days) expire ConfigStatic AdminController.php:995, :1002
Birthday gift value birthday_credit ConfigStatic app/Console/Commands/birthdayCommand.php:46
Birthday gift expiry (days) birthday_expire ConfigStatic birthdayCommand.php:47, :64
City-level percent cities.percent, cities.percent_aux database/migrations/2021_09_18_171700_city_table.php:21, 2021_09_18_172722_cities_p_2.php:17
Per-customer percent customers.percent / login.percent migration 2020_10_19_153228:32; SingleCustomer fillable :32
No spread (buy vs sell price) — Not implemented. Single price per item.

7.4 Wallet / balance — packages/rooyesh/wallet

Dual-currency wallet: gold (grams, double) and credit (toman, bigint), one row per (owner, owner_type) — packages/rooyesh/wallet/src/migrations/...:16-30.

Concern Where Detail
Wallet open / get WalletInterface::__construct :17-40 find-or-create by (owner_id, owner_type); validates hash on load
Hash chain (tamper detection) WalletInterface::generate_hash :51-57 sha256(sha256(credit) + sha256(gold) + sha256(owner) + sha256(last_tx.hash) + "yhoenszeaf") — secret pepper is hardcoded
Wallet validate WalletInterface::validate :42-49 throws UnprocessableEntityHttpException('امکان شارز این کیف پول وجود ندارد'); the package's own WalletValidateFailed is commented out (:45)
Transaction hash TransactionInterface::generate_hash :101-114 sha256(sha256(value)+sha256(balance)+sha256(wallet)+"yhoenszeaf"+last_tx.hash)
Balance check TransactionInterface::apply_transaction :127-135 if not deposit: type 1 (gold) requires wallet.gold >= value → NotEnoughCashBalance; type 2 (credit) requires wallet.credit >= value → NotEnoughCreditBalance
Sign convention :136 value = abs(value) * (deposit ? 1 : -1)
Running balance :141 balance = wallet.gold + wallet.credit + value — mixes grams and toman in one number (known modeling defect)
Validation rules :142-153 wallet,type required; expire_at date; value integer|required (gram values are doubles — this rule is effectively bypassed because $validator->failed() is called instead of fails() at :151, which always returns an array/empty and never throws)
Apply to wallet :159-165 type 1 → wallet.gold += value; type 2 → wallet.credit += value; then re-hash wallet
Meta rows :157-158 TransactionMeta::create($meta) with order_id, total_weight, percent, order_date
Transaction types migration :42-46 1=gold, 2=credit, 3=expire
Owner types migration :27-30 1=user, 2=shop — all call sites pass 1
Read wallet (customer) app/Http/Controllers/Customer/CustomerController.php:14-19 gold, credit, + computed gold_toman = gold * getPriceGold18Ayar()
Wallet tx list (customer) Customer/CustomerController.php:21-30 paginated via addLimit
Wallet tx list (admin) app/Http/Controllers/Adm/WalletController.php:49-59 TableEngine
Admin manual charge Adm/WalletController.php:19-39 deposit = value > 0; pre-check credit sufficiency; always type 2 (credit), expire_at = now()+1 year
Wallet config get/set Adm/WalletController.php:61-79 setConst writes arbitrary ConfigStatic keys; getConfig returns percent+expire; getConfigBirthday returns birthday_credit+birthday_expire
Global percent reset Adm/WalletController.php:41-46 SingleCustomer::query()->update(['percent' => …]) — updates every row

Cashback on delivery — app/Http/Controllers/Adm/AdminController.php:985-1013 (chargeWalletAfterOrder):

percent = ConfigStatic['percent']; expire = ConfigStatic['expire']
value   = transaction_order.total_weight * (percent / 100)        // in GRAMS
new TransactionInterface(wallet, {value, order_id, expire_at: now()+expire days}, type=1 /*gold*/, deposit=true,
                          meta:{order_id, total_weight, percent, order_date})
transaction_order.payment = 1

Triggered from Controller::afterCreateOrder when sts == 6 (app/Http/Controllers/Controller.php:202-215), which also SMSes the customer the gram amount and "6-month validity" text (:207-214) — note the SMS says 6 months but the actual expiry is expire days from ConfigStatic.

Spending the wallet at checkout — app/Http/Controllers/Customer/OrderController.php:99-136:

if order.use_wallet:
  gold_value_toman = wallet.gold * order.gold_price_original
  all = gold_value_toman + wallet.credit
  if all <= order.price:                      // wallet cannot cover → drain it
      withdraw all gold (type 1) and all credit (type 2)
  else:                                        // wallet covers → partial
      if wallet.gold <= order.total_weight: withdraw all gold;
          if gold < total_weight: withdraw (all - order.price) credit
      else: withdraw exactly order.total_weight grams
  // recompute what is still payable
  amount = Σ |tx.value| * gold_price_original (type 1) + Σ |tx.value| (type 2)
  order.payment_after_wallet = order.price - amount

Refund on cancel — Customer/OrderController.php:150-168: re-deposits every Transaction for the order back into the wallet with the same transaction_type.

7.5 Buy / sell orders

There is no buy/sell order book, no market order, no limit order. Two distinct purchase order flows exist:

Flow Model/table Entry point Status enum
Wholesale ("major") order — shopkeeper orders gold goods from the wholesaler, denominated in grams Order / orders, OrderItem / order_items, OrderActivity / order_activity ApiMobileController@setOrder :528-758 (guard api-customer); admin Adm\OrderController@store :32, Adm\MajorOrderController Order::$STS 0..6 — app/Models/Order.php:65-72
Retail order — web customer buys a product, denominated in toman SingleCustomerOrders / orders_orders, SingleCustomerOrderItems / orders_orderitem, SingleCustomer\OrderActivity / orders_histroy Customer\OrderController@store :68-148 (guard api-singleCustomer); admin Adm\AdminController@orderStsSingle :898 SingleCustomerOrders::$STS 1..7 — app/Models/SingleCustomerOrders.php:66-74
Custom order (bespoke jewelry request) CustomOrder, CustomOrderLog Api\CustomOrderController CustomOrder::$appends['sts_str_en'/'sts_str_fa'] :15, :68-76

7.6 Order & transaction status enums and transitions

Order::$STS (wholesale) — app/Models/Order.php:65-72:

key Persian notes
0 معلق (suspended) set when gram limit exceeded
1 ثبت سفارش (placed) default happy path
2 تایید مدیر سیستم (sysadmin approved)
3 درحال تامین (sourcing)
4 درحال آماده سازی (preparing)
5 تحویل مسئول فروش (handed to sales rep)
6 تحویل مشتری (delivered) triggers wallet cashback
7 (کنسل شده — commented out :71)

Supporting statics: $STS_TAB (with -1 => همگی) :73-104; $STS_COLOR :105-113 (0 = #FF5252, 1-5 = #f5cb83, 6 = #4CAF50); $STS_IMG :122-130. $CONFIRMED = [1=>تایید شده, 2=>در انتظار تایید] :60-63. $TYPES = [1=>ثبت سفارش توسط مسئول فروش, 2=>ثبت مشتری] :45-48.

Transition mechanism (wholesale): all 7 status rows are pre-created in order_activity at order creation (ApiMobileController@setOrder:652-664), each with proceed 0/1. Advancing a status = flipping proceed=1 on that row — Adm\MajorOrderController@orderSts:121-211. On create: proceed = inValidOrder ? (key==0) : (key==1) (:662).

SingleCustomerOrders::$STS (retail) — app/Models/SingleCustomerOrders.php:66-74: 1=ثبت سفارش, 2=تایید مدیر سیستم, 3=در حال تامین, 4=در حال آماده سازی, 5=خروج از انبار, 6=ارسال, 7=تحویل مشتری. Types $TYPES = [1=تلفنی,2=تلگرام,3=واتس آپ,4=اینستا,5=حضوری] :76-82. Same pre-create-all-rows pattern: Controller::createSingleOrderActivity:81-92; afterCreateOrder flips the requested sts row (:182-186) and fires cashback at sts==6 (:202). Note the mismatch: $STS[6] = 'ارسال' (shipped) not delivered, yet cashback fires at 6.

Major\Cash::$TYPES — app/Models/Major/Cash.php:56-62: 9=سفارش (order), 1=آب شده (melted/bullion), 2=حواله (transfer note), 3=چک (cheque), 4=پولی (cash). $STS = [-1=>بررسی نشده, 1=>ثبت سند] :63-66. $CONFIRMED = [1=>تایید شده, 0=>تایید نشده] :68-71.

Wallet transaction types: 1=gold, 2=credit, 3=expire (migration :42-46).

SingleCustomerTransaction.sts is a free-text Persian string (e.g. 'پرداخت نشده' — app/Models/SingleCustomerTransaction.php:43), not an enum.

7.7 KYC levels

No KYC-level system exists. What exists is a two-step manual verification flag on wholesale customers:

Field Where
customers.sts_verify_step_one, customers.sts_verify_step_two app/Models/Customer.php:18 fillable
Accessors sts_verify_step_one_str, sts_verify_step_two_str + lookups GetStsVerifyStepOne, GetStsVerifyStepTwo app/DB/Selector.php:101-127
Document images: business_license_image_id (جواز کسب), shop_image_id (سر در فروشگاه), ncode_image_id (کارت ملی) app/Models/Customer.php:18; relations :170-181
Admin approval Adm\MajorCustomerController@verifyRegister:97-144, @indexVerify:157, @archive:175
Activation toggles Adm\AdminController@customerToggleSts:426, @customerToggleActive:432
National code customers.ncode (migration 2020_10_01_120430:22)

No tiered limits are derived from verification status.

7.8 Limits (min / max / daily)

No daily limits. No min/max order amount. No withdrawal limit. The only limit is a per-customer gram ceiling on wholesale orders:

Concern Where
Ceiling field customers.gram_level double default 0 — database/migrations/2020_10_19_153228_customer_add.php:31; fillable app/Models/Customer.php:18
Running usage customers.remain double default 0 — database/migrations/2020_10_01_120430_customers_table.php:26
Check app/Http/Controllers/Api/ApiMobileController.php:566-567: $inValidOrder = ($allGram + $remain) > $gramLevel
Effect order sts forced to 0 (معلق/suspended) instead of 1 (:577, :592); activity note "تعلیق سفارش به دلیل عبور از سقف مجاز گرمی" (:661); a Notify row explains the suspension (:669-677)
Note The $customer->increment('remain', $allGram) on success is commented out (:604-607) — remain is maintained elsewhere (cash ledger)
Product-level gram bounds product.min_gram, product.max_gram — app/Models/Product.php:22 (display/filter only)
Pagination limit Controller::addLimit — default 10, hard cap 50 — app/Http/Controllers/Controller.php:31-36
Rate limit 500 req/min on api — app/Providers/RouteServiceProvider.php:77

7.9 OTP / SMS

Concern Where Detail
SMS gateway (active) app/Models/Sms.php:74-84 (Send), :101-111 (SendSms) POST https://smspanel.trez.ir/SendMessageWithCode.ashx, form fields PhoneNumber=9998882797, Username=hajiabolfath, Password=Aa@09195540836 (hardcoded), Mobile, Message; 20s timeout
SMS gateway (dead) Sms.php:63-73, :91-99 0098sms.com/sendsmslink.aspx with USERNAME=zsms6916 — commented out
Every send is logged Sms::set :125-134 → messages table customer_id, mobile, massage(sic), token, type, user_id
OTP — wholesale Customer Api\ApiMobileController@userAuth:40-50 rand(1000,9999) → stored in customers.send_password (plain text, no expiry, no attempt counter); SMS body includes <#> code is … + Android SMS Retriever hash aMo6iFyUQaY
OTP verify (wholesale) ApiMobileController@userVerfiy:52-81 compares Utility::faTOen($request->password) != $customer->send_password → abort(422); on success issues api_token = Str::random(60) only if null (:59-61) — token never rotates
OTP — retail SingleCustomer Api\SingleCustomerController@login:58-76 rand(1000,9999) → login.token_sms (plain, no expiry); returns {id}; SMS "کد تایید ورود"
OTP verify (retail) Api\SingleCustomerController@verfiy:42-56 compares token_sms; sets is_active = true; issues api_token = Str::random(60) if null
Legacy password login ApiMobileController@login:83-110 (Hash::check); Adm\AdminController@login:60-78 (staff)
Batch SMS Adm\SmsController@batch:23-76 validates payload,type numeric,mobiles array,token; @replaceName:91-111 does %%NAME%% substitution
Ad-hoc SMS Adm\SmsController@sendSmsToOther:150
Mass-SMS to ALL customers via GET routes/api.php:126-180 (GET api/send/all), routes/web.php:158-186 (GET /test2) unauthenticated closures that loop Customer::get() and SMS everyone
Hardcoded admin phones (order alerts) ApiMobileController:601-604 (09128081392, 09124871664, 09124406015, 09120363240); Customer/OrderController:139-144 (09128081392, 09124406015 ×2, 09363366849)

7.10 Notifications (push)

Concern Where
FCM config config/fcm.php:4-9 — FCM_PROTOCOL (def http), FCM_SERVER_KEY, FCM_SENDER_ID
In-app notification store Notify model / notify table — app/Models/Notify.php:14-33
Single push Notify::store($token,$title,$body) :57-86
Group push Notify::sendToGroup($tokens,$title,$body) :88+
Second impl Notification::store() app/Models/Notification.php:33
Device token storage customers.token_mobile, users.token_mobile (Customer.php:18, User.php:29); updated via POST api/tokenmobile → ApiMobileController@updateTokenMobile:477
Admin send Adm\NotifyController@store:27, @customer:67
Read/unread Notify.read bool; Adm\NotifyController@read:95, @getUnreadNotify:86; customer PUT api/notify/read/{id} → @readNotify:784

7.11 Payment gateway + callbacks

Concern Where Detail
Gateway: PayPing (init) app/Http/Controllers/Customer/TransactionController.php:11-27 POST https://api.payping.ir/v1/pay with clientRefId, amount, returnUrl = https://henzagold.com/oapi/site/transaction/verify. No Authorization header is sent (the withHeaders call is chained after post() at :100, so it is a no-op).
Gateway: PayPing (verify, dead code) app/Models/SingleCustomerTransaction.php:84-100 POST https://api.payping.ir/v2/pay/verify with hardcoded bearer token :86; hardcoded amount=1000, payerIdentity='09134139430', payerName='Azizan'; returnUrl = url('/bank-back')
Gateway: Zarinpal (SOAP) SingleCustomerTransaction.php:49-82 entirely commented out
Callback route — The returnUrl site/transaction/verify is NOT registered in any route file. routes/site.php has no transaction/* route. /bank-back is also not registered. The payment callback is missing / dead.
Transaction record transactions_transaction via SingleCustomerTransaction gateway = 'paypal' (sic, hardcoded :44), sts free-text Persian
Route POST cu/transaction/gateway — routes/customer.php:36

7.12 File uploads

Concern Where
Primary upload Adm\FileController@storeWithoutData:144-192 — POST admin/file/create, POST api/file/create
Filename md5(time() . original_name) . '.' . ext (:155-156)
Destination public_path('storage') — flat, no date directory (the createDir() path logic is commented out :150, :162-179)
Record App\Models\Image::create($data) with original_name, ext, image (:186-190)
No validation no mime/size/extension check, no auth on admin/file/create
WebP conversion / watermark commented out (:162-172)
Body/caption update @updateBody:268 — PUT admin/file/update/{file_id}
Full CRUD (legacy) @store:58, @show:200, @update:215, @destroy:255
Product image resize Adm\ProductController@createImage:22-29
URL base Utility::baseURLStorage() = https://henzagold.com/oapi/storage/ — app/Models/Utility.php:30-32; Image::getFullAttribute:35, getImageAttribute:58
APK download Api\SiteController@downloadApk — env('APK_PATH', storage_path('app/public/henza.apk')), env('APK_VERSION',0) — app/Http/Controllers/Api/SiteController.php:494-495

7.13 Settings / config table

config_statics (ConfigStatic) is the universal key/value settings table — app/Models/ConfigStatic.php:10-33. It doubles as a lookup/enum table (users.ut is an FK to it — Adm\UserController:26 validates ut exists:config_statics,id; User::user_type() :51).

Known key Purpose Evidence
gold_price live price JSON (geram18/geram24/mesghal) WebServiceGold.php:19,:28,:110
gold_price_pwa PWA price JSON (10 instruments) GetGoldPriceForPwa.php:70; routes/web.php:60
product_price_extra_percent making-charge extra %, default 7 ProductVariant.php:49
percent wallet cashback % of order weight AdminController.php:994; Controller.php:203
expire cashback validity, in days AdminController.php:995,:1002
birthday_credit birthday gift amount (toman) birthdayCommand.php:46
birthday_expire birthday gift validity (days) birthdayCommand.php:47
brand product brand list (legacy, superseded by product_brand) ApiMobileController.php:75 (commented)
(arbitrary) Adm\WalletController@setConst:61-70 writes any key from the request body

Accessors: ConfigStatic::getValue($key) — returns scalar if exactly 1 row, collection if >1, throws NotFoundHttpException('Const not found') if 0 (:25-33). CRUD via Adm\ConstController (admin/const/*), read via GET site/const/{id}, full list via GET admin/config/statics → AdminController@getConfigStatics:752.

7.14 What does NOT exist (explicit negatives for parity work)

Expected in a gold-banking backend Status in henza_server
Buy / sell gold orders (market/limit) Absent — only product purchase orders
Bid/ask spread Absent — one price per item
Deposit (cash in) Absent — only admin manual wallet charge (Adm\WalletController@charge)
Withdraw (cash out / physical gold delivery) Absent
Peer-to-peer transfer Absent (the "حواله" in Cash::$TYPES[2] and config/havaleh.php is a static list of 9 broker names, not a transfer feature)
KYC levels / tiers Absent — only 2 manual verification booleans + 3 document images
Daily / monthly limits Absent — only a per-customer total gram ceiling
Payment callback / verify endpoint Route missing (§7.11)
Idempotency keys on money ops Absent
DB transactions around wallet ops Absent — apply_transaction does 4 unwrapped writes (TransactionInterface.php:154-164)
Audit/event sourcing Partial — wallet hash chain + order_activity + RequestLog

8. Jobs / Queues / Cron

8.1 Jobs — app/Jobs (3)

Job Constructor args handle() Evidence
SendSmsJob $mobile, $message, $customer_id, $user_id Sms::SendSms($mobile,$message,$customer_id,null,null,$user_id) app/Jobs/SendSmsJob.php:25-41
SendSmsAfterCreate $mobile, $message Sms::Send($mobile,$message) app/Jobs/SendSmsAfterCreate.php:23-37
PromotionAfterCreate $customer_id body fully commented out; return; — "new customer 1% promo for 5 days" disabled app/Jobs/PromotionAfterCreate.php:33-53

All three implement ShouldQueue with Dispatchable, InteractsWithQueue, Queueable, SerializesModels.

Queue driver: config/queue.php 'default' => env('QUEUE_CONNECTION', 'sync') — defaults to sync (jobs run inline) unless env overrides. failed_jobs table exists (migration #3).

8.2 Console commands — app/Console/Commands (5)

Signature Class Purpose
price:get GetGoldPrice :15 WebServiceGold::getAllPriceFromWebService() (ratebox.ir) — :39-43
pwa:price GetGoldPriceForPwa :18 tgju.org scrape → writes gold_price_pwa and gold_price; then calls Tahesab DoListMoshtari [1,510] at https://31.7.68.147:3030/ with hardcoded bearer token :76-81
transaction:expire ExpireCommand :18 loops all SingleCustomer; sums expired-vs-spent gold and credit; posts negative (withdraw) TransactionInterface entries for the surplus — :42-80
birthday:sms birthdayCommand :20 finds customers whose birth_day day+month = today; SMSes a gift message; deposits birthday_credit as type 2 (credit) with expire_at = now() + birthday_expire days — :44-68
wallet:sms SmsWalletCommand :17 finds wallets with sms_at exactly 3 months ago; if gold>0 || credit>0 SMSes the owner the literal string 'هنزا'; updates sms_at/sent — :41-57

8.3 Schedule — app/Console/Kernel.php

Item Evidence
$commands registry birthdayCommand, ExpireCommand, GetGoldPriceForPwa — app/Console/Kernel.php:18-22 (note: GetGoldPrice and SmsWalletCommand are not listed, but $this->load(__DIR__.'/Commands') at :42 auto-discovers them)
schedule() EMPTY — the only line is a commented $schedule->command('inspire')->hourly(); — app/Console/Kernel.php:30-33

⇒ There is NO Laravel cron schedule. Price refresh, expiry sweeps and birthday SMS must be driven by external OS cron calling artisan pwa:price / transaction:expire / birthday:sms, or by hitting GET / (routes/web.php:32) which performs the price scrape inline.

routes/console.php:17-19 defines only the stock inspire closure command.


9. Permissions / roles

No Spatie, no Gates, no Policies. AuthServiceProvider::$policies is empty (app/Providers/AuthServiceProvider.php:15-17); boot() only calls registerPolicies() (:24-29). No Gate::define anywhere. The can middleware alias is registered (Kernel.php:60) but never used on any route.

9.1 Model

Piece Detail Evidence
Role = users.ut integer "user type" on User; FK into config_statics migration 2021_09_18_171700_city_table.php:28; User.php:27; User::user_type() :51
Permission = permission table composite PK (rid, ut) — rid is a free-text permission string, ut is the role id migration 2021_09_18_115342_permissions_table.php:16-19; app/Models/Permission.php:14-18
Validation of ut 'ut' => 'required|numeric|exists:config_statics,id' Adm\UserController.php:26, :64

9.2 Where permissions are read

Operation Where
Returned at login Adm\AdminController@login:74 — $per = Permission::whereUt($user->ut)->get(); attached to the login response. The server never enforces it — enforcement is entirely client-side in the admin SPA.
Set (replace all for a role) Adm\PermissionController@create:12-40 — diffs requested roles[] against existing, creates missing, deletes surplus
Set (additive) @store:42-57 — firstOrCreate per role
Delete one @destroy:59-65 — DELETE admin/roles/{ut}/{rid}
Check one @has:67-74 — GET admin/roles/{ut}/{rid} → boolean
My permissions @get:76-81 — Permission::where('ut', Auth::user()->ut)
Permissions of a role @getByUt:83-88 — GET admin/roles/{id}
Attached to user detail Adm\UserController@show:96 — Permission::where('ut',$user->ut)->pluck('rid')

9.3 Permission names found

No permission (rid) string literals exist anywhere in the codebase. rid values are created purely from client-supplied roles[] arrays (PermissionController@create:21, @store:51) and stored as-is. The catalogue of permission names lives only in the admin front-end and in the DB — it is not derivable from henza_server. Likewise there is no seeded list of ut (role) values; they are rows in config_statics.

9.4 Actual enforcement in practice

Surface Enforcement
routes/admin.php (215 routes) NONE — the auth:api wrapper is commented out (:12, :264). Fully public.
routes/api.php public block none
routes/api.php:64-117 auth:api-customer only (authentication, not authorization)
routes/customer.php:10-46 auth:api-singleCustomer only
routes/site.php, routes/web.php none (except version on one route)
Ownership checks ad-hoc: Controller::checkCustomer($auth_id,$store_id) throws AccessDeniedHttpException (app/Http/Controllers/Controller.php:232-236); scopes Order::scopeMe:161, Notify::scopeMe:50, Major\Cash::scopeMe:74; where('customer_id', auth()->id()) in Customer\CustomerController:135 etc.

10. Broadcasting / sockets

Item Detail Evidence
Channels file Contains exactly one channel: App.Models.User.{id}, authorized by (int)$user->id === (int)$id (Laravel's stock private-notification channel) routes/channels.php:28-30
Provider BroadcastServiceProvider exists app/Providers/BroadcastServiceProvider.php
Driver default 'default' => env('BROADCAST_DRIVER', 'null') — null (disabled) unless env overrides config/broadcasting.php:18
Available connections pusher (:34, keys PUSHER_APP_KEY/PUSHER_APP_SECRET/PUSHER_APP_ID/PUSHER_APP_CLUSTER), redis (:45), log (:50), null (:54) config/broadcasting.php:31-56
Events broadcast NONE — no class implements ShouldBroadcast; app/Events/ does not exist; EventServiceProvider::$listen is stock app/Providers/EventServiceProvider.php
Live price over socket NOT IMPLEMENTED. Price is delivered by polling GET api/price / GET site/price / GET admin/price, all of which read ConfigStatic['gold_price'] routes/api.php:47, routes/site.php:14-16, routes/admin.php:51-53
Real-time client hint package.json may include laravel-echo but no server-side publisher exists —

⇒ There is no real-time/websocket layer. Live price = HTTP polling of a DB-cached JSON blob refreshed by a cron-driven command.


11. Env / config keys

11.1 Custom (non-stock) config files

File Content
config/havaleh.php:5-16 Flat array of 9 hardcoded broker name+phone strings (e.g. 'مسعود آتشی | 33977786-021'). Returned verbatim by GET admin/havale/list (Adm\AdminController@getHavaleList:1018) and attached to the mobile login payload as $customer->to (ApiMobileController:66, :96).
config/version.php:2-4 ['version' => '2.2.0'] — compared against the version request header by VersionMiddleware (app/Http/Middleware/VersionMiddleware.php:21-27).
config/validation.php:2-9 Single route-keyed rule set: 'admin/product/create@post' => ['cats'=>'required|array','title'=>'required','indicator_id'=>'required','mobile_pic'=>'required']. Never read by any code (no config('validation') usage) — dead config.
config/corcel.php Corcel/WordPress bridge connection.
config/fcm.php:4-9 FCM_PROTOCOL (def http), FCM_SERVER_KEY, FCM_SENDER_ID.
config/pdf.php, config/dompdf.php PDF rendering (invoice generation).

11.2 env() calls inside app/ and routes/ (outside config/)

Key Default Where
WEBSERVICE_TOKEN — app/Models/WebServiceGold.php:85; app/Http/Controllers/Site/SiteController.php:261; app/Console/Commands/GetGoldPriceForPwa.php:170 (commented)
APK_VERSION 0 app/Http/Controllers/Api/SiteController.php:494
APK_PATH storage_path('app/public/henza.apk') app/Http/Controllers/Api/SiteController.php:495
APP_NAME — app/DB/Te/print.blade.php:5
BASE_PATH_STORAGE '' app/Models/Image.php:60 (commented out)

⚠️ These are runtime env() calls outside config files — they return null when php artisan config:cache is used.

11.3 Stock env keys consumed via config/*

APP_NAME, APP_ENV, APP_KEY, APP_DEBUG, APP_URL, LOG_CHANNEL; DB_CONNECTION (default 'localhost' — unusual, config/database.php:18), DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD, DB_SOCKET, DATABASE_URL, DB_FOREIGN_KEYS, MYSQL_ATTR_SSL_CA; REDIS_CLIENT, REDIS_CLUSTER, REDIS_PREFIX, REDIS_URL, REDIS_HOST, REDIS_PASSWORD, REDIS_PORT, REDIS_DB, REDIS_CACHE_DB; BROADCAST_DRIVER (def null), PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_ID, PUSHER_APP_CLUSTER; CACHE_DRIVER, CACHE_PREFIX, MEMCACHED_*, DYNAMODB_CACHE_TABLE, DYNAMODB_ENDPOINT; QUEUE_CONNECTION, SESSION_DRIVER, SESSION_LIFETIME; FILESYSTEM_DRIVER, FILESYSTEM_CLOUD, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_BUCKET; MAIL_*, MAILGUN_DOMAIN, MAILGUN_SECRET, MAILGUN_ENDPOINT, POSTMARK_TOKEN; FCM_PROTOCOL, FCM_SERVER_KEY, FCM_SENDER_ID.

11.4 Hardcoded secrets / endpoints (parity + security relevant)

Secret / endpoint Location
SMS panel user + password hajiabolfath / Aa@09195540836 app/Models/Sms.php:80-81, :107-108
PayPing bearer 413471e0…d7b1 app/Models/SingleCustomerTransaction.php:86
Tahesab bearer S3F1P8Q4…U8 + host 31.7.68.147:3030 app/Console/Commands/GetGoldPriceForPwa.php:78-80
Wallet hash pepper "yhoenszeaf" packages/rooyesh/wallet/src/interfaces/WalletInterface.php:56; TransactionInterface.php:112
Storage base URL https://henzagold.com/oapi/storage/ app/Models/Utility.php:31
Payment return URL https://henzagold.com/oapi/site/transaction/verify app/Http/Controllers/Customer/TransactionController.php:99
Admin alert phone numbers app/Http/Controllers/Api/ApiMobileController.php:601-604; app/Http/Controllers/Customer/OrderController.php:139-144
Customer-facing URLs (henzagold.com/customer/my-orders, /dashboard, /app, /download/henza.apk) app/Http/Controllers/Controller.php:199, :213; routes/web.php:128, :132

12. Validation

There are ZERO FormRequest classes — app/Http/Requests/ does not exist. All validation is inline, using either $this->validate($request, [...]) (ValidatesRequests trait) or Validator::make($request->all(), [...]). config/validation.php defines one route-keyed rule set that nothing reads.

Distribution (rule-block counts per controller):

Controller blocks
Adm/AdminController 17
Api/ApiMobileController 5
Api/SingleCustomerController 4
Adm/MajorOrderController, Adm/UserController, Api/CustomOrderController, Api/SiteController 3 each
Adm/BranchController, Adm/OrderController, Adm/PermissionController, Adm/ProductController, Adm/SmsController, Adm/WorkshopController, Major/CustomerController 2 each
Adm/CitiesController, Adm/CommentController, Adm/MajorCustomerController, Adm/SingleCustomerController, Customer/CommentController, Customer/FavController, Customer/OrderController, WebApp/AuthController 1 each

Main rule sets

Endpoint Rules Evidence
Admin login phone: required, password: required Adm/AdminController.php:62
Update customer id: required|exists:customers,id, fname: required, lname: required Adm/AdminController.php:264-267
Update customer (mobile uniqueness) mobile: unique:customers,mobile,{id} Adm/AdminController.php:303-304
Create customer (with reagent) mobile: required|unique:customers, reagent: required Adm/AdminController.php:321-323
Create customer (reagent path) mobile: required|unique:customers, percent: required Adm/AdminController.php:352-354
Confirm cash doc id: required Adm/AdminController.php:455-456
Set gram for fin-doc (commented) id: required, gram: required Adm/AdminController.php:480-482
Read SMS (commented) FROM/TO/TEXT: required Adm/AdminController.php:505-508
Confirm order cId: required (customer), oId: required (order) Adm/AdminController.php:517-519
Set fin-doc (commented) customer_id/price/value: required Adm/AdminController.php:583-586
Add product cats: required|array, title: required Adm/AdminController.php:600-602
Get variant(s) id: required Adm/AdminController.php:736, :745
Add category title: required Adm/AdminController.php:794-795
Change percent (bulk) percentage_pay: required Adm/AdminController.php:845-846
Report order id: required Adm/AdminController.php:900-901
Branch store/update user_id: required Adm/BranchController.php:48-49, :83-84
Cities store title: required, parent: exists:cities,id, level: numeric|required, percent: numeric Adm/CitiesController.php:15-19
Comment status comment_id: required, sts: required Adm/CommentController.php:123-124
Verify major customer customer_id: required Adm/MajorCustomerController.php:98-99
Major order sts id: required Adm/MajorOrderController.php:123-124
Major order item edit id: required, w: required, order_id: required Adm/MajorOrderController.php:214-217
Delete major order id: required Adm/MajorOrderController.php:275-276
Admin order store order_items: required Adm/OrderController.php:35-36
Admin order update order_items: required, shipping_address: required Adm/OrderController.php:66-67
Permissions (create/store) ut: required, roles: required|array Adm/PermissionController.php:13-15, :45-47
Product store cats: required|array, title: required (product_code: required|unique:product,product_code is commented out :45) Adm/ProductController.php:42-45
Product update (rule array empty — product_code unique rule commented out) Adm/ProductController.php:114-115
Single customer store fname: required, lname: required, phone: required|unique:login Adm/SingleCustomerController.php:20
SMS batch payload: required, type: required|numeric, mobiles: array, token: required Adm/SmsController.php:25-29
SMS to other payload: required, mobile: required Adm/SmsController.php:79-81
User store fname: required, lname: required, mobile: required|unique:users, ut: required|numeric|exists:config_statics,id, city_id: exists:cities,id, password: required|min:6 Adm/UserController.php:22-28
User update mobile: unique:users,mobile,{id}, ut: numeric|exists:config_statics,id, city_id: exists:cities,id; if password present: password: required|min:6|confirmed Adm/UserController.php:62-72
OTP request (wholesale) username: required Api/ApiMobileController.php:42
OTP verify (wholesale) username: required, password: required Api/ApiMobileController.php:54
Legacy login (wholesale) username: required, password: required Api/ApiMobileController.php:85
Retail register fname: required, lname: required, phone: required|unique:login Api/SingleCustomerController.php:30
Retail OTP verify token: required, id: required Api/SingleCustomerController.php:43
Retail login (OTP request) phone: required Api/SingleCustomerController.php:59
Retail order store order_items: required, shipping_address: required Customer/OrderController.php:73-75 (returns 422 with $validator->errors())

Notable validation gaps (parity-relevant)

Gap Evidence
setOrder (wholesale order creation) has NO validation at all — $request->items is consumed raw Api/ApiMobileController.php:528-758
Wallet charge has NO validation — $data['value'], $data['customer_id'] taken raw Adm/WalletController.php:19-39
setConst writes arbitrary ConfigStatic keys with no whitelist/validation Adm/WalletController.php:61-70
File upload has no mime/size/extension validation Adm/FileController.php:144-192
Payment gateway gateway() has no validation — amount, customer_id raw Customer/TransactionController.php:11-27
Wallet package's own validator is never enforced — calls $validator->failed() (returns array) instead of fails() (returns bool) packages/rooyesh/wallet/src/interfaces/TransactionInterface.php:150-153
Product::update validation array is empty Adm/ProductController.php:114-116
No numeric/min/max on any money or weight field anywhere —