Files
amlhc/.planning/codebase/ARCHITECTURE.md
T
2026-04-21 23:02:15 +08:00

19 KiB

Architecture

Analysis Date: 2026-04-21

Pattern Overview

Overall: MVC (Model-View-Controller) with module-based multi-application architecture, built on ThinkPHP 5.x framework and FastAdmin 1.6.1 admin framework.

Key Characteristics:

  • Multi-module structure: admin (backend management), index (frontend user portal), api (RESTful API), common (shared code)
  • Trait-based CRUD inheritance: Backend controllers inherit index/add/edit/del/multi/recyclebin/destroy/restore from app\admin\library\traits\Backend
  • RBAC (Role-Based Access Control): Admin permissions via admin → auth_group → auth_group_access → auth_rule chain; user permissions via user → user_group → user_rule chain
  • Addon/plugin architecture: Extensible system via addons/ directory with lifecycle hooks
  • Dual Auth systems: app\admin\library\Auth (session-based admin auth) and app\common\library\Auth (token-based user auth)

Modules

The application is organized into 4 ThinkPHP modules under application/:

Admin Module (application/admin/)

  • Purpose: Backend management panel for administrators
  • Contains: Admin CRUD controllers, RBAC management, system config, user management, lottery data management (History, Num), command execution interface
  • Entry: public/index.php → module admin
  • Controllers: 18 controllers across 4 subdirectories

Index Module (application/index/)

  • Purpose: Frontend user-facing website
  • Contains: Public homepage, user login/register/profile, ajax endpoints, lottery data scraping
  • Controllers: Index.php (lottery scraping + homepage), User.php (member center), Ajax.php (frontend async operations)

API Module (application/api/)

  • Purpose: RESTful API endpoints for mobile/third-party clients
  • Contains: User auth, registration, profile, token management, SMS/EMS verification
  • Controllers: Index.php, User.php, Common.php, Demo.php, Ems.php, Sms.php, Token.php, Validate.php

Common Module (application/common/)

  • Purpose: Shared code across all modules
  • Contains: Base controllers, shared models, libraries (Auth, Upload, Email, Token drivers), exceptions

Controller Inheritance Chain

Backend (Admin Controllers)

think\Controller (ThinkPHP base)
  └── app\common\controller\Backend (base backend controller)
        └── app\admin\library\traits\Backend (trait: CRUD methods)
              └── app\admin\controller\* (all admin controllers)

app\common\controller\Backend (application/common/controller/Backend.php):

  • Properties: $noNeedLogin, $noNeedRight, $layout, $auth, $model, $searchFields, $relationSearch, $dataLimit, $dataLimitField, $dataLimitFieldAutoFill, $modelValidate, $modelSceneValidate, $multiFields, $selectpageFields, $excludeFields, $importHeadType
  • _initialize(): IP check → Auth instance → login verification → permission check → breadcrumb setup → layout → language loading → view config assignment
  • buildparams(): Constructs WHERE conditions from GET params (search, filter, op, sort, order, offset, limit) with support for LIKE, IN, BETWEEN, RANGE, FIND_IN_SET, NULL operators
  • selectpage(): Universal select/dropdown search with tree support
  • loadlang(): Loads language file for current controller
  • assignconfig(): Merges config into view
  • getDataLimitAdminIds(): Returns admin IDs for data scoping based on $dataLimit setting

app\admin\library\traits\Backend (application/admin/library/traits/Backend.php):

  • index(): List with pagination, JSON response for AJAX
  • add(): Create with validation, transaction support
  • edit(): Update with validation, data limit check
  • del(): Soft delete (batch supported)
  • recyclebin(): View soft-deleted records
  • destroy(): Permanent delete from recycle bin
  • restore(): Restore from recycle bin
  • multi(): Batch update specified fields
  • import(): Excel/CSV import with PhpSpreadsheet

Frontend (Index Controllers)

think\Controller (ThinkPHP base)
  └── app\common\controller\Frontend (base frontend controller)
        └── app\index\controller\* (all frontend controllers)

app\common\controller\Frontend (application/common/controller/Frontend.php):

  • _initialize(): Input filtering → IP check → layout → Auth init → token-based login check → user assignment → site config → language loading
  • Auth uses app\common\library\Auth (token-based)
  • loadlang(): Loads language file for current controller
  • assignconfig(): Merges config into view

API Controllers

(no ThinkPHP Controller base)
  └── app\common\controller\Api (base API controller, not extending think\Controller)
        └── app\api\controller\* (all API controllers)

app\common\controller\Api (application/common/controller/Api.php):

  • Does NOT extend think\Controller — manual constructor pattern
  • Properties: $noNeedLogin, $noNeedRight, $auth, $responseType, $failException, $batchValidate
  • _initialize(): CORS check → IP check → input filtering → token auth → permission check → language loading
  • success() / error(): Standard API response format {code, msg, time, data}
  • result(): Unified response with HTTP status code mapping
  • validate(): Data validation with fail-exception mode
  • beforeAction(): Before-action hook support

RBAC Auth System

Admin RBAC

fa_admin (管理员)
  └── fa_auth_group_access (管理员-角色关联, N:N)
        └── fa_auth_group (角色组)
              └── rules (权限规则ID列表, 逗号分隔)
                    └── fa_auth_rule (权限规则)

Key classes:

  • app\admin\library\Auth extends fast\Auth — admin authentication and authorization
  • app\admin\model\Admin — admin user model
  • app\admin\model\AuthGroup — role group model
  • app\admin\model\AuthGroupAccess — admin-role pivot model
  • app\admin\model\AuthRule — permission rule model
  • app\admin\model\AdminLog — admin operation log model

Auth flow:

  1. Login: Admin::login() → verifies password (MD5 double-hash with salt: md5(md5(password) . salt)) → sets Session + token + keeplogin cookie
  2. Permission check: Auth::check($path) → reads user's group rules → checks if controller/action path is in allowed rules
  3. Super admin: Auth::isSuperAdmin() → returns true if rule list contains *
  4. Data scoping: Backend::$dataLimit supports auth (group-scoped) and personal (user-scoped) data filtering via getDataLimitAdminIds()
  5. Session management: safecode validation ensures re-login on credential changes; supports single-session mode (fastadmin.login_unique) and IP check mode (fastadmin.loginip_check)
  6. Auto-login: Auth::autologin() checks keeplogin cookie with time-limited key validation

Key Auth methods:

  • login($username, $password, $keeptime) — admin login
  • logout() — clear session and token
  • check($name, $uid, $relation, $mode) — permission check
  • match($arr) — check if current action matches whitelist
  • isLogin() — session + safecode validation
  • isSuperAdmin() — check for * in rules
  • getSidebar($params, $fixedPage) — generate left/top navigation menu
  • getBreadCrumb($path) — breadcrumb navigation
  • getChildrenAdminIds($withself) — scoped admin IDs
  • getChildrenGroupIds($withself) — scoped group IDs

User RBAC (Frontend)

fa_user (会员)
  └── group_id → fa_user_group (会员组)
        └── rules → fa_user_rule (会员权限规则)

Key classes:

  • app\common\library\Auth — user authentication (token-based, singleton pattern)
  • app\common\model\User — user model with money/score log hooks
  • app\common\model\UserGroup — user group model
  • app\common\model\UserRule — user rule model
  • Token storage: app\common\library\Token with MySQL or Redis drivers

Auth flow:

  1. Token init: Auth::init($token) → Token::get() → load user → set _logined flag
  2. Login: Auth::login($account, $password) → finds user by email/mobile/username → verifies password → direct($user_id)
  3. Token management: UUID token stored in Token model (or Redis) with configurable TTL (keeptime = 2592000 = 30 days)
  4. Password encryption: md5(md5(password) . salt) — same algorithm as admin

Key Auth methods:

  • instance($options) — singleton getter
  • init($token) — initialize from token
  • login($account, $password) — user login
  • register($username, $password, $email, $mobile, $extend) — user registration
  • logout() — delete token
  • changepwd($newpassword, $oldpassword, $ignoreoldpassword) — change password
  • direct($user_id) — direct login (bypass password check)
  • check($path, $module) — permission check
  • delete($user_id) — delete user and clear tokens

MVC Patterns

Model Pattern

  • All models extend think\Model
  • Timestamps: autoWriteTimestamp = 'int' with custom field names (createtime, updatetime)
  • Attribute mutators: getXxxAttr() and setXxxAttr() for data transformation
  • Model events: self::init() with self::beforeWrite, self::afterInsert hooks
  • Relations: belongsTo, hasMany using ThinkPHP ORM
  • Appended attributes: $append = ['field_text'] for computed/display fields
  • Enum lists: getStatusList(), getGenderList() for select/radio options
  • Hidden fields: $hidden = ['password', 'salt'] for sensitive data

View Pattern

  • Template engine: ThinkPHP template with {} syntax
  • Layout: application/admin/view/layout/default.html includes common/meta, common/script, common/header, common/menu
  • Admin views: build_heading() generates toolbar/buttons, {:__()} for i18n
  • View config injection via $this->view->assign() and $this->assignconfig()
  • Layout template set via $this->layout property in controllers
  • Frontend layout: application/index/view/layout/default.html

Validation Pattern

  • Validators extend think\Validate
  • Rules defined in $rule array (require, unique, regex, email, length, etc.)
  • Scenes: $scene = ['add' => [...], 'edit' => [...]] for context-specific validation
  • Constructor customization for i18n field labels
  • Model-level validation: Backend::$modelValidate and $modelSceneValidate toggle automatic validation on add/edit

Addon Architecture

Directory: addons/

Plugin lifecycle:

  • Install: Service::install($name) → downloads, extracts, runs SQL
  • Uninstall: Service::uninstall($name) → removes files, optionally drops tables
  • Enable/Disable: Service::enable($name) / Service::disable($name)
  • Upgrade: Service::upgrade($name) → downloads new version, runs migration
  • Configure: get_addon_config($name) / set_addon_fullconfig($name, $config)

Addon structure:

addons/{name}/
├── info.ini          # Plugin metadata
├── {Name}.php        # Main class extends \think\addons\Addon
├── config.php        # Plugin configuration schema
├── config.html       # Config view (optional, custom config UI)
├── controller/       # Plugin controllers
├── model/            # Plugin models
├── view/             # Plugin views
└── install.sql       # Installation SQL

Admin addon controller (application/admin/controller/Addon.php):

  • Manages plugin list, install/uninstall, enable/disable, config, upgrade
  • Restricted to super admin for destructive operations (install, uninstall, local, upgrade, authorization, testdata)
  • Communicates with FastAdmin marketplace API (fastadmin.api_url)
  • Methods: index(), config($name), install(), uninstall(), state(), local(), upgrade(), testdata(), downloaded(), isbuy(), authorization(), get_table_list()

Admin commands for addons:

  • application/admin/command/Crud.php — one-click CRUD generation from table
  • application/admin/command/Menu.php — menu generation from controllers
  • application/admin/command/Min.php — JS/CSS minification
  • application/admin/command/Api.php — API documentation generation
  • application/admin/command/Install.php — installation wizard
  • application/admin/command/Addon.php — addon-related stubs and operations

Hook system: ThinkPHP Hook integration

  • admin_login_after, admin_logout_after, admin_nologin, admin_nopermission
  • user_login_successed, user_register_successed, user_logout_successed, user_delete_successed
  • upload_config_init, config_init, wipecache_after
  • upload_delete, admin_sidebar_begin
  • admin_login_init

Request Flow

Admin Request

public/index.php
  → define APP_PATH → check install.lock → require thinkphp/start.php
    → ThinkPHP dispatch (module/controller/action)
      → app\admin\controller\{Controller}
        → parent::_initialize() (app\common\controller\Backend)
          → check_ip_allowed()
          → Auth::instance() → login check → permission check
          → loadlang() → view config assignment
        → action method (index/add/edit/del from trait or custom)
          → model operations
          → $this->view->fetch() or json()

Frontend Request

public/index.php
  → ThinkPHP dispatch
    → app\index\controller\{Controller}
      → parent::_initialize() (app\common\controller\Frontend)
        → input filter → Auth init (token-based)
        → loadlang() → view config
      → action method → view->fetch()

API Request

public/index.php
  → ThinkPHP dispatch
    → app\api\controller\{Controller}
      → __construct() → _initialize() (app\common\controller\Api)
        → CORS → IP check → token init → permission check
      → action method → $this->success() / $this->error()
        → result() → JSON response {code, msg, time, data}

Data Flow: Lottery Feature (History, Num)

History Model

  • Table: fa_history (application/admin/model/History.php)
  • Fields: id, expect (期号), openTime (开奖时间), num1~num7 (7个开奖号码)
  • No timestamps: autoWriteTimestamp = false, createTime = false, updateTime = false, deleteTime = false
  • No validation rules defined in application/admin/validate/History.php

Num Model

  • Table: fa_num (application/admin/model/Num.php)
  • Fields: num, color (波色映射 — wave color mapping for lottery numbers)
  • No timestamps: autoWriteTimestamp = false

Data Scraping Flow (application/index/controller/Index.php::get_history())

  1. User visits index/index/get_history (no auth required: $noNeedLogin = '*')
  2. Controller creates \GuzzleHttp\Client instance
  3. GET request to https://history.macaumarksix.com/history/macaujc2/y/2026 (Macau lottery history API)
  4. Parses JSON response, extracts data array
  5. For each item: splits openCode by comma into num1~num7
  6. Checks if expect already exists in fa_history via Db::name('history')->where('expect', $item['expect'])->find()
  7. If new: Db::name('history')->insert($insert_data); if exists: Db::name('history')->where('expect', $item['expect'])->update($insert_data)
  8. Returns success/failure JSON via $this->success() / $this->error()

Admin History Management (application/admin/controller/History.php)

  • Extends Backend, uses standard CRUD from trait
  • Model: app\admin\model\History
  • View: application/admin/view/history/index.html — list only, add/edit buttons hidden in template
  • No custom methods — relies entirely on inherited CRUD

Admin Num Query (application/admin/controller/Num.php)

  • Extends Backend
  • Model: app\admin\model\Num
  • Custom method: getColorMap() — returns num→color mapping for frontend display as JSON

Key Abstractions

Auth (Dual System)

  • app\admin\library\Auth — session-based admin auth extending fast\Auth (base RBAC class from fast namespace)
  • app\common\library\Auth — token-based user auth (singleton), no ThinkPHP Controller dependency

Tree

  • fast\Tree — hierarchical data structure for menus, categories, rules
  • Methods: init(), getTreeList(), getTreeArray(), getChildrenIds(), getParentsIds(), getTreeMenu(), getChildren()

Token Drivers

  • app\common\library\Token — token storage abstraction
  • app\common\library\token\driver\Mysql — MySQL-backed token storage
  • app\common\library\token\driver\Redis — Redis-backed token storage

Upload

  • app\common\library\Upload — file upload with chunked upload support
  • Integrates with app\common\model\Attachment for metadata tracking
  • Exception: app\common\exception\UploadException

Date Utility

  • fast\Date — date manipulation utility (e.g., Date::unixtime('day', -6))

Random Utility

  • fast\Random — random string/UUID generation (used for salt, tokens)

Entry Points

public/index.php — Main entry point for all modules

  • Defines APP_PATH
  • Checks application/admin/command/Install/install.lock for installation status
  • Redirects to install.php if not installed
  • Loads thinkphp/start.php for framework bootstrap

think — CLI entry point for ThinkPHP commands

  • Used for CRUD generation, menu generation, API docs, minification, addon management

Error Handling

Strategy: Exception-based with user-friendly error pages

Patterns:

  • $this->error($msg) / $this->success($msg) — controller-level response helpers
  • try/catch with Db::startTrans() / Db::commit() / Db::rollback() for transaction safety
  • ValidateException — model validation failures
  • PDOException — database errors
  • UploadException — upload failures
  • AddonException — plugin operation failures with structured error data
  • HttpResponseException — API response termination

Cross-Cutting Concerns

Logging: AdminLog::record() auto-logs admin operations (title, content, URL, IP, user agent); filtered by ignoreRegex to skip selectpage/index actions; AdminLog::setTitle() for custom titles; behavior hook via app\admin\behavior\AdminLog

Validation: ThinkPHP Validate with rule-based validation, scene support, custom messages; model-level and controller-level validation modes

Authentication: Dual auth system — session-based for admin, token-based for users/API; IP allowlist check via check_ip_allowed(); CSRF tokens for forms

Internationalization: Language files per module under lang/zh-cn/ and lang/en/; __() function for translation; controller auto-loads matching lang file in _initialize(); admin loads zh-cn as default

IP Filtering: check_ip_allowed() called in all base controllers — reads fastadmin.ip_blacklist / fastadmin.ip_whitelist config

Caching: File-based cache (ThinkPHP default); menu cache via cache("__menu__"); template caching enabled; addon list cache via Cache::get("onlineaddons")


Architecture analysis: 2026-04-21