ThinkAdmin: annotation permissions, task queues and a bundled admin shell
A minimalist admin system based on ThinkPHP6&8, with built-in annotation-based permissions, async multitasking and a plugin ecosystem; supports PaaS-like updates for shared modules and plugins, with local plugin customization.
At a glance
- What is it?
- ThinkAdmin wraps ThinkPHP 6 and 8 with controller annotation permissions, one shared list page pattern, a pluggable file layer and a queue-backed task service. The bundle saves real work, but the default branch sits months past the newest packaged version and the WeChat module is a hard root dependency you cannot simply drop.
- Who is it for?
- Adopt ThinkAdmin when your team already writes PHP on ThinkPHP and would otherwise rebuild the admin shell, user management and list pages per client. Pass on it if you need a modern front-end build chain or a backend without WeChat code bundled in, because `zoujingli/think-plugs-wechat` sits in the root dependencies.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Controller annotations carry the permission decision
Permissions in ThinkAdmin are not a list of roles tested inside a controller body. You annotate a controller method with a login or permission requirement, and that single marker drives two separate outcomes: which buttons the page renders, and whether the server accepts the request that follows. A role meant to view and edit records can be offered an edit control with no delete control anywhere in the template, and the endpoint behind the hidden button still refuses the call.
That split makes authorising a new business screen a two-place job. Code carries the annotation on the method, and the grant lives in the admin interface where roles are assigned against menus. The pages that ship with the project, covering system users, menus, parameters, data dictionaries, operation logs and file records, all follow the same arrangement, so the first new controller has working code to sit beside.
There is a boundary worth stating early. Menu structure, button visibility and operation checks are the framework's job. Deciding which customers belong to which account, how an order moves through states, and how data is isolated per tenant are not, because those rules live entirely in your own business modules.
One list page pattern shared by every business module
ThinkLibrary, published as `zoujingli/think-library`, wraps the repetitive half of a management screen: query filtering, pagination, form submission, validation, state updates and deletion. The shape is fixed and familiar. Filters sit above the table, a paginated grid sits below, clicking edit opens a form, and saving refreshes the list. Once a team learns one page, the next one costs configuration rather than design.
The system user screen is the reference implementation, and reading it tells you where each piece lives. The controller organises the query, the template defines columns and buttons, and the form carries the submit path. Swap the model, the fields and the validation rules for your own entity and everything around that flow stays intact.
Rendering is server-side PHP templates plus JavaScript, with Layui, jQuery and RequireJS on the front end, and static assets shipped into `public/static/` by the plugins that need them. A plain deployment uses those assets as they arrive. Adjusting the interface means editing templates and components, while changing the theme means editing the Less sources and running the theme build. Charts and rich text editing have bundled resources too: ECharts, Vue, CKEditor and wangEditor are available for the pages that need them, and interface text is organised through language keys, with the shipped language packs serving as a reference for your own translations.
Storage is a per-page parameter, not a global setting
Uploads run through one component, and the page decides how it behaves. File type, size limits, storage destination and image dimensions are parameters on the page rather than one global setting, which matters when a profile avatar and a payment certificate have nothing in common. Single images, multiple images and a picker have separate entry points, and compression quality, maximum width and height, and crop size are set per page as well.
The flow also computes a file hash and checks whether that file already exists in the chosen storage. A hit reuses the stored result instead of uploading again, so a logo reused across dozens of forms costs one copy. Upload records are collected centrally, searchable in the admin, and editable or deletable within authorisation, including a cleanup pass for duplicate records.
Backends are local disk, Alist, Qiniu, Aliyun OSS, Tencent COS and Upyun. Pay attention to the safe mode for files that must not be public, such as payment certificates: those are written to local `safefile/`, and read access is left to your own business interface rather than a guessable URL. Two limits are explicit. Moving files already held in one backend to another, and rewriting addresses that point at them, is separate work the upload component will not do. And type detection depends on the `fileinfo` extension being present.
The queue listener process is not optional
Long jobs are not handled inside a page request. You register a task, a separate process executes it, the admin shows progress, and the result stays available for inspection afterwards. Task code reports its own position, such as which record it reached and how far the batch has advanced, so a slow sync is visible instead of looking like a hang. Delay execution, looping tasks and a background reset for re-running are all reachable from the interface.
The example already in the repository is WeChat fan synchronisation, which is a useful template because fan pulls are slow, partial and worth retrying. Anything that reads a remote API in pages or batches follows the same outline.
The constraint that catches people is ordering. Nothing executes until the listener process is running, and a deployment that only serves web traffic leaves every registered task sitting untouched. PHP CLI plus permission to execute processes is listed as a requirement for exactly this reason. The README also points readers to a troubleshooting section for failed tasks and re-runs, but it does not document how to keep the listener alive under a process supervisor, so that arrangement is left to you.
Two install paths and the Composer plugin behind them
Two routes reach the same tree. Composer suits starting from a packaged version, while a clone suits reading git history, tracking the v6 branch or contributing. Pick a project path with no Chinese characters and no spaces.
The Composer route installs a published version and names the directory:
composer create-project zoujingli/thinkadmin thinkadmin "^6.0"
cd thinkadminThe source route pulls the branch directly:
git clone --branch v6 https://github.com/zoujingli/ThinkAdmin.git thinkadmin
cd thinkadminThe installer publishes plugin files and attempts to run database migrations during that step, which is why the environment section asks you to allow the project's own Composer plugin, `zoujingli/think-install`, and points at Composer 2. Running it inside an existing application has consequences: the documentation tells you to back up the database and save local code changes before installing or updating dependencies there. SQLite needs no server, so the first run works with `pdo_sqlite` enabled. MySQL needs a root `.env` written first, then the ordinary install.
Every platform check in the documentation carries the `--no-plugins` flag, which keeps that install-time plugin out of the check itself.
Migrations, a debug server and the admin/admin first login
From the project root, three commands finish the setup:
# 检查已安装依赖的 PHP 版本与扩展要求
composer --no-plugins check-platform-reqs
# 执行尚未完成的数据库迁移;自动迁移成功后通常没有待执行项
php think migrate:run
# 启动本地调试服务器
php think run --host 127.0.0.1 --port 8000The entry point is `http://127.0.0.1:8000/admin`. The site root redirects to the login page rather than serving a separate portal home. On the very first initialisation of an empty user table the account is `admin` with password `admin`, and the documentation is explicit that you change it immediately afterwards; a database that already has users is not reset by that rule. The built-in server is for local debugging only, while production expects Nginx with the document root at `public/`.
Before any of that, check the platform directly:
php -v
php -m
composer --no-plugins check-platform-reqsThe shipped `.env.example` is a template, not a working credential set. It selects SQLite by default, then lists a MySQL block pointing at host `thinkadmin.top` on port 3306 as user root with an empty password against a database named `admin` in `utf8mb4`. Cache and session defaults are file based, with `CACHE_TYPE=file`, `SESSION_TYPE=file`, `SESSION_NAME=ssid` and `SESSION_EXPIRE=7200`, and the Redis entries sit there as commented alternatives rather than requirements.
The default branch moved months past the newest tag
Here is the detail worth checking before you plan around version numbers. The last push landed on 2026-09-08, while the newest packaged version carries the date 2025-11-19 and the one before it 2024-08-08, a gap of roughly nine months between what Packagist hands you and what sits on the branch. Anyone installing with `composer create-project` starts from that older tree and will not receive those later commits until a new version is published, which is exactly the case where a git clone of v6 is the more honest starting point for evaluation.
Distribution is under the MIT licence, which permits modification, use and redistribution provided the copyright and licence text travel with the work, while third-party components keep their own terms and deserve a separate check.
Upgrade cost is mostly operational. `php think migrate:run` applies outstanding migrations, the ORM constraint at the root allows 2.x or 3.x, and the static assets under `public/static/` are republished by the plugins rather than carried in your repository. Before updating dependencies in a live project, the documentation's own instruction applies: back up the database and preserve local edits first.
Bare ThinkPHP as the alternative and what the bundle costs
The real comparison is not against other admin panels but against assembling the same stack yourself on ThinkPHP 6 or 8. Doing it by hand means choosing your ORM version, wiring Layui with jQuery and RequireJS, and writing your own upload handling, progress reporting, background worker and admin scaffolding before a single business screen exists. ThinkAdmin packages that work as `zoujingli/think-library` for the core helpers plus storage and task services, `zoujingli/think-plugs-admin` for the base management modules, and `zoujingli/think-plugs-wechat` for public account operations covering fans, articles, menus, keyword replies, payment records and refunds.
The cost of the bundle is visible in the dependency list. The WeChat plugin is described as already required directly by the root project, with no need to install it again, so a back office with no WeChat features at all means editing `composer.json` rather than simply ignoring the screens. You also inherit a fixed rendering approach, server-rendered templates plus JavaScript through Layui and RequireJS, and an upgrade path tied to the ThinkPHP version your dependencies allow.
For code that must serve several projects, the project's answer is to keep single-application code inside separate applications and promote genuinely shared pieces into Composer plugins, and its description advertises a PaaS-style channel for updating common modules and application plugins while allowing local customisation of those plugins.
Editorial conclusion
Adopt ThinkAdmin when your team already writes PHP on ThinkPHP and would otherwise rebuild the admin shell, user management and list pages per client. Pass on it if you need a modern front-end build chain or a backend without WeChat code bundled in, because `zoujingli/think-plugs-wechat` sits in the root dependencies. Before committing, run `composer --no-plugins check-platform-reqs` on your target PHP, decide whether `php think migrate:run` may touch a live database, and measure how far your packaged version lags the v6 branch.
Frequently asked questions
What PHP version and database does ThinkAdmin need?
The root dependency declares `PHP >=7.1`, but the documentation states the real floor is also set by ThinkPHP, ThinkLibrary and the other dependencies, and it points at a maintained PHP 8.x. SQLite is the default database and a MySQL connection configuration is provided. Run `composer --no-plugins check-platform-reqs` to confirm your own installation.
What are the default admin credentials after installing ThinkAdmin?
On the first initialisation of an empty user table the account is `admin` with password `admin`, and the documentation says to change it right after the first login. A database that already contains users is not reset by that rule.
Does ThinkAdmin need a running process for background tasks?
Yes. Tasks are registered in the admin and executed by a separate queue listener process, which must be started before anything runs, and that step needs PHP CLI plus permission to execute processes. The README documents progress reporting, delayed and looping tasks and a reset for re-running.
Where can ThinkAdmin store uploaded files?
Storage is chosen per page through the upload component, supporting local disk, Alist, Qiniu, Aliyun OSS, Tencent COS and Upyun, with file hash checks that reuse an existing stored copy. Files that must not be public can use safe mode and be written to local `safefile/`, where read access is controlled by your own business interface.
Where are the ThinkAdmin documentation and the online demo?
The project points to thinkadmin.top for documentation and to v6.thinkadmin.top for the online demo, and recommends picking a familiar screen there and walking the matching source before committing to the framework.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/zoujingli-thinkadmin)