当前位置: 首页 > article >正文

hyperf 多租户 SaaS 基础框架 开源完整流程(从 0 到持续维护)==写开源项目全流程

一套 Hyperf 多租户 SaaS 基础框架的开源落地方案覆盖 从0搭建到持续维护并给出可直接改造的核心代码骨架。 ---1)先定多租户策略强烈建议这样起步 先用 共享库 行级隔离tenant_id后续再支持“独立库租户” esc to interrupt - 起步快、成本低、运维简单 - 业务模型统一适合开源模板 - 后续可按租户等级切换到独立库VIP 租户 ---2)项目结构建议 saas-hyperf/ ├─ app/ │ ├─ Context/ │ │ └─ TenantContext.php │ ├─ Middleware/ │ │ └─ TenantResolveMiddleware.php │ ├─ Model/ │ │ ├─ Tenant.php │ │ ├─ User.php │ │ └─ BaseTenantModel.php │ ├─ Service/ │ │ └─ TenantService.php │ ├─ Controller/ │ │ ├─ AuthController.php │ │ └─ ProjectController.php │ └─ Exception/Handler/ ├─ config/autoload/ │ ├─ databases.php │ ├─ middlewares.php │ └─ routes.php ├─ migrations/ ├─ tests/ ├─ .github/workflows/ci.yml ├─ docker-compose.yml ├─ CLAUDE.md ├─ LICENSE └─ README.md ---3)从0初始化命令composercreate-project hyperf/hyperf-skeleton saas-hyperfcdsaas-hyperf# 常用依赖按你项目版本调整composerrequire hyperf/db-connection hyperf/databasecomposerrequire hyperf/redis hyperf/validationcomposerrequire firebase/php-jwtcomposerrequire--devphpunit/phpunit friendsofphp/php-cs-fixer ---4)核心代码租户上下文 自动隔离4.1TenantContext协程安全 app/Context/TenantContext.php?php declare(strict_types1);namespace App\Context;use Hyperf\Context\Context;class TenantContext{private const KEY_IDtenant.id;private const KEY_CODEtenant.code;public staticfunctionset(int$tenantId, string$tenantCode): void{Context::set(self::KEY_ID,$tenantId);Context::set(self::KEY_CODE,$tenantCode);}public staticfunctionid(): ?int{returnContext::get(self::KEY_ID);}public staticfunctioncode(): ?string{returnContext::get(self::KEY_CODE);}public staticfunctionclear(): void{Context::set(self::KEY_ID, null);Context::set(self::KEY_CODE, null);}}---4.2租户解析中间件子域名 / Header app/Middleware/TenantResolveMiddleware.php?php declare(strict_types1);namespace App\Middleware;use App\Context\TenantContext;use App\Model\Tenant;use Hyperf\Di\Annotation\Inject;use Hyperf\HttpServer\Contract\RequestInterface;use Psr\Http\Message\ResponseInterface;use Psr\Http\Server\MiddlewareInterface;use Psr\Http\Server\RequestHandlerInterface;use Hyperf\HttpServer\Response;class TenantResolveMiddleware implements MiddlewareInterface{#[Inject]protected RequestInterface$request;#[Inject]protected Response$response;publicfunctionprocess($request, RequestHandlerInterface$handler): ResponseInterface{$host$this-request-getUri()-getHost();$tenantCode$this-request-header(X-Tenant-Code)??$this-parseSubdomain($host);if(!$tenantCode){return$this-response-json([code40001,messagetenant required])-withStatus(400);}/** var Tenant|null$tenant*/$tenantTenant::query()-where(code,$tenantCode)-where(status,1)-first();if(!$tenant){return$this-response-json([code40004,messagetenant not found])-withStatus(404);}TenantContext::set((int)$tenant-id,(string)$tenant-code);try{return$handler-handle($request);}finally{TenantContext::clear();}}privatefunctionparseSubdomain(string$host): ?string{// 例如 tenant1.example.com$partsexplode(.,$host);returncount($parts)3?$parts[0]:null;}}---4.3基础租户模型自动 tenant_id 过滤 app/Model/BaseTenantModel.php?php declare(strict_types1);namespace App\Model;use App\Context\TenantContext;use Hyperf\DbConnection\Model\Model;use Hyperf\Database\Model\Builder;abstract class BaseTenantModel extends Model{protected staticfunctionbooted(): void{static::addGlobalScope(tenant_scope,function(Builder$builder){$tenantIdTenantContext::id();if($tenantId!null){$builder-where($builder-getModel()-getTable()..tenant_id,$tenantId);}});static::creating(function(Model$model){if(empty($model-tenant_id)TenantContext::id()!null){$model-tenant_idTenantContext::id();}});}}业务模型示例 app/Model/Project.php?php declare(strict_types1);namespace App\Model;class Project extends BaseTenantModel{protected ?string$tableprojects;protected array$fillable[tenant_id,name,owner_id,status,];}---5)关键数据表迁移 migrations/2026_01_01_000001_create_core_tables.php?php use Hyperf\Database\Schema\Schema;use Hyperf\Database\Schema\Blueprint;use Hyperf\Database\Migrations\Migration;returnnew class extends Migration{publicfunctionup(): void{Schema::create(tenants,function(Blueprint$table){$table-bigIncrements(id);$table-string(name,100);$table-string(code,64)-unique();// 子域名/租户唯一编码$table-tinyInteger(status)-default(1);$table-timestamps();});Schema::create(users,function(Blueprint$table){$table-bigIncrements(id);$table-unsignedBigInteger(tenant_id);$table-string(email,191);$table-string(password,255);$table-string(name,100);$table-timestamps();$table-unique([tenant_id,email]);$table-index([tenant_id]);});Schema::create(projects,function(Blueprint$table){$table-bigIncrements(id);$table-unsignedBigInteger(tenant_id);$table-unsignedBigInteger(owner_id);$table-string(name,191);$table-tinyInteger(status)-default(1);$table-timestamps();$table-index([tenant_id,owner_id]);});}publicfunctiondown(): void{Schema::dropIfExists(projects);Schema::dropIfExists(users);Schema::dropIfExists(tenants);}};---6)路由与中间件注册 config/autoload/middlewares.php?phpreturn[http[\App\Middleware\TenantResolveMiddleware::class,],];config/autoload/routes.php?php use Hyperf\HttpServer\Router\Router;Router::addGroup(/api,function(){Router::post(/auth/login,[App\Controller\AuthController::class,login]);Router::get(/projects,[App\Controller\ProjectController::class,index]);Router::post(/projects,[App\Controller\ProjectController::class,store]);});---7)控制器示例天然按 tenant 隔离 app/Controller/ProjectController.php?php declare(strict_types1);namespace App\Controller;use App\Model\Project;use Hyperf\HttpServer\Contract\RequestInterface;use Hyperf\HttpServer\Contract\ResponseInterface;class ProjectController{publicfunctionindex(ResponseInterface$response){$listProject::query()-orderByDesc(id)-limit(20)-get();return$response-json([code0,data$list]);}publicfunctionstore(RequestInterface$request, ResponseInterface$response){$data$request-all();$projectProject::query()-create([name$data[name]??,owner_id(int)($data[owner_id]??0),status1,]);return$response-json([code0,data$project]);}}---8)开源必须补齐的工程化8.1Docker本地一键跑 docker-compose.yml 至少包含 - apphyperf - mysql - redis8.2CIGitHub Actions .github/workflows/ci.yml - PHP lint - 单元测试 - 静态分析phpstan/psalm 任选 - 格式检查php-cs-fixer8.3开源治理 - LICENSE推荐 MIT / Apache-2.0 - README.md安装、配置、租户接入流程、API 示例 - issue templates / PR template - SECURITY.md漏洞提交通道 - 版本规范SemVerv0.x -v1.0 ---9)持续维护路线你可以直接按这个迭代 v0.1MVP - 租户识别 - 行级隔离 - 用户/项目基础 CRUD - JWT 登录 v0.2 - RBACtenant_admin / member - 审计日志谁在何时改了什么 - 限流按租户 v0.3 - 计费模型套餐、成员上限、资源配额 - Webhook / OpenAPI v1.0 - 独立库租户能力 - 数据迁移工具共享库 -独立库 - 多环境发布标准化灰度/回滚 ---10)你这个开源框架最容易踩坑的5点1. 忘记给查询加租户过滤上面全局作用域已处理大部分2. 超级管理员接口误穿透租户边界必须显式 withoutGlobalScope 且审计3. 唯一索引没带 tenant_id导致跨租户冲突4. 缓存 key 没加租户前缀数据串租户5. 异步任务没带 tenant 上下文队列 payload 必须含 tenant_id --- 如果你要直接发布模板仓库这套骨架已经够做一个可运行的开源起点先把上面4个核心文件 迁移 CI 放进仓库第一版就能被社区用起来并持续迭代。

相关文章:

hyperf 多租户 SaaS 基础框架 开源完整流程(从 0 到持续维护)==写开源项目全流程

一套 Hyperf 多租户 SaaS 基础框架的开源落地方案,覆盖 从 0 搭建到持续维护,并给出可直接改造的核心代码骨架。---1) 先定多租户策略(强烈建议这样起步) …...

清音刻墨Qwen3智能字幕对齐:小白也能懂的快速入门指南

清音刻墨Qwen3智能字幕对齐:小白也能懂的快速入门指南 1. 引言:字幕对齐的痛点与解决方案 视频制作中最让人头疼的问题之一就是字幕不同步。传统字幕制作需要手动调整时间轴,不仅耗时耗力,还很难做到精准对齐。想象一下&#xf…...

9天掌握PyTorch深度学习:高效实战指南

1. 课程概览与学习价值这个9天PyTorch深度学习迷你课程是我在指导数百名学员后提炼出的高效学习路径。不同于传统教材按部就班的讲解方式,我们采用"问题驱动即时实践"的教学方法,每天聚焦一个核心主题,通过3-4个典型代码案例贯穿知…...

egergergeeert惊艳效果:银发少女插画中发丝细节、布料褶皱、光影过渡展示

egergergeeert惊艳效果:银发少女插画中发丝细节、布料褶皱、光影过渡展示 1. 效果亮点概览 egergergeeert文生图镜像在角色插画创作中展现出惊人的细节表现力,特别是在以下三个方面尤为突出: 发丝细节:能够生成单根分明的发丝效…...

k-Means聚类算法优化实战:从初始化到核技巧

1. k-Means算法回顾与常见痛点分析k-Means作为无监督学习中最经典的聚类算法之一,其简洁性和高效性使其成为数据分析的入门必修课。算法通过迭代计算样本点到聚类中心的距离,不断调整中心点位置,最终实现数据的分组。但正是这种简洁性&#x…...

云原生智能代理架构实战:基于事件驱动与基础设施即代码的快速构建

1. 项目概述:一个面向云原生应用的智能代理启动包最近在整理云原生项目的开发工具链时,我又一次翻出了GoogleCloudPlatform下的agent-starter-pack。这可不是一个简单的代码仓库,而是一个被很多团队低估了的“瑞士军刀”。简单来说&#xff0…...

AWPortrait-Z完整攻略:科哥WebUI从安装到精通全流程解析

AWPortrait-Z完整攻略:科哥WebUI从安装到精通全流程解析 1. 快速启动与界面初探 如果你对AI生成人像充满好奇,但又被复杂的命令行和参数吓退,那么AWPortrait-Z的WebUI界面就是为你准备的。这个由科哥基于Z-Image精心构建并二次开发的人像美…...

构建垂直领域智能助手:混合智能体与RAG架构实战解析

1. 项目概述:一个专为宝可梦世界打造的智能对话系统如果你是一个宝可梦的资深爱好者,或者对构建垂直领域的智能助手感兴趣,那么“可萌”这个项目绝对值得你花时间研究。它不是一个简单的聊天机器人,而是一个融合了知识图谱、大语言…...

Banana Pi BPI-W3开发板:RK3588 SoC与模块化设计解析

1. Banana Pi BPI-W3开发板深度解析作为一款基于Rockchip RK3588 SoC的高性能单板计算机,Banana Pi BPI-W3在硬件配置和接口丰富度上都达到了业界领先水平。这款开发板最引人注目的特点是采用了模块化设计——核心处理器部分采用独立的BPI-RK3588核心板,…...

量子纠错与实时解码:CUDA-Q QEC技术解析

1. 量子纠错与实时解码的核心价值在量子计算领域,量子比特的脆弱性一直是实现实用化量子计算机的主要障碍。量子态极易受到环境噪声干扰,导致量子相干性在极短时间内衰减——这种现象被称为退相干(Decoherence)。以超导量子比特为…...

Tailwind CSS 指令与函数

Tailwind CSS 指令与函数学习笔记 一、总览 Tailwind CSS 的指令与函数分为两大类:类别作用域用途指令(Directives)CSS 文件中控制 Tailwind 的编译行为函数(Functions)CSS 文件 / 配置文件中动态引用主题值 二、指令&…...

Tailwind CSS 自定义样式

Tailwind CSS 自定义样式学习笔记 一、自定义样式的层次结构 ┌──────────────────────────────────────────────────────┐ │ tailwind.config.js → 设计系统 Token(颜色/间距/字号) │ │…...

基于Mastra框架构建生产级AI应用:从Agent与Workflow设计到实战部署

1. 从零到一:为什么选择 Mastra 来构建你的 AI 应用?如果你正在用 TypeScript 栈开发 AI 应用,并且已经尝试过直接调用 OpenAI 的 API 或者用 LangChain 搭过一些原型,那你大概率会遇到几个绕不开的痛点:模型切换成本高…...

M2FP人体解析零基础教程:5分钟搭建WebUI服务,一键识别身体部位

M2FP人体解析零基础教程:5分钟搭建WebUI服务,一键识别身体部位 1. 什么是M2FP人体解析? M2FP(Mask2Former-Parsing)是一种先进的计算机视觉模型,专门用于识别图片中人物的各个身体部位。想象一下&#xf…...

Phi-3.5-mini-instruct部署避坑指南:vLLM加载失败排查、Chainlit连接超时解决方案

Phi-3.5-mini-instruct部署避坑指南:vLLM加载失败排查、Chainlit连接超时解决方案 1. 模型简介 Phi-3.5-mini-instruct是Phi-3模型家族中的轻量级成员,作为一款先进的开放模型,它具备以下核心特点: 128K超长上下文:…...

开源无代码数据库Baserow:自托管部署与CRM应用实战

1. 项目概述:为什么我们需要一个开源的“Airtable”? 如果你曾经为团队寻找过一款既能像电子表格一样直观操作,又能像数据库一样结构化存储数据的工具,那么Airtable这个名字大概率会出现在你的搜索结果里。它确实很棒,…...

Weka机器学习工具入门与实战指南

1. Weka机器学习工具入门指南Weka作为一款开源的机器学习工具集,自1997年由怀卡托大学开发以来,已成为学术界和工业界广泛使用的数据挖掘平台。它集成了数据预处理、分类、回归、聚类、关联规则挖掘和可视化等完整功能链,特别适合没有编程基础…...

Vivado仿真器底层工具链揭秘:xvlog、xelab、xsim到底在干什么?

Vivado仿真器底层工具链揭秘:xvlog、xelab、xsim到底在干什么? 当你在Vivado中点击"Run Simulation"按钮时,背后实际上启动了一个精密的工具链流水线。这个看似简单的操作背后,隐藏着三个关键角色:xvlog、xe…...

【深入解析LoRA】从低秩自适应到高效微调:原理、实践与调优指南

1. 为什么LoRA能成为大模型微调的首选方案 第一次接触LoRA是在去年部署一个客服对话系统时遇到的。当时客户扔过来一个175B参数的GPT-3模型,要求我们在两周内完成业务场景适配。看着服务器上那几块可怜的A100显卡,团队里所有人都觉得这是个不可能完成的任…...

从零开始打造AI画图大师:条件扩散模型完整实现与无分类器指引详解

你有没有想过,AI是如何听懂你的指令,画出你想要的东西的?当你对Midjourney输入“一只穿着宇航服的柴犬”,它真的能生成那张图——这背后究竟发生了什么?今天,我将带你亲手实现一个基础的文本控制AI绘图系统…...

机器学习数据预处理:数据标准化(Z-Score)

机器学习数据预处理:数据标准化(Z-Score)超通俗全解 数据标准化是**把所有特征统一变成“均值为0,标准差为1”**的最经典预处理方法,彻底解决量纲不一致、数值差距大的问题,所有对尺度敏感的模型都必须做。…...

【限时技术解禁】:VSCode 2026 Dev Tunnels直连容器的私有化部署方案(绕过GitHub Auth,企业级离线可用)

更多请点击: https://intelliparadigm.com 第一章:VSCode 2026 Dev Tunnels直连容器的技术演进与企业适配价值 VSCode 2026 引入的 Dev Tunnels 原生直连容器能力,标志着远程开发范式从 SSH 代理与端口转发迈向零配置、身份感知、双向加密隧…...

本地GPU预训练Llama模型全流程与优化策略

1. 本地GPU预训练Llama模型全流程解析在自然语言处理领域,Transformer架构已成为大语言模型的事实标准。作为其中的佼佼者,Llama系列模型因其出色的性能和开源特性备受关注。本文将手把手教你如何在本地GPU上完成Llama模型的预训练全流程。1.1 为什么选择…...

深度学习模型集成方法:Bagging实战与优化

1. 深度学习模型集成方法概述在机器学习领域,集成学习(Ensemble Learning)是一种通过组合多个模型的预测结果来提升整体性能的技术。这种方法的核心思想是"三个臭皮匠顶个诸葛亮"——多个模型的集体智慧往往比单个模型表现更好。特别是在深度学习领域&…...

GeniA:大语言模型驱动的生物信息学智能体框架实战指南

1. 项目概述:当AI遇上基因,GeniA如何重塑生物信息学工作流如果你是一名生物信息学研究员、计算生物学家,或者任何需要与高通量测序数据打交道的从业者,那么你一定对“数据洪流”这个词深有体会。从二代测序到三代测序,…...

Transformer位置编码原理与实战技巧详解

1. 位置编码的本质与必要性在传统RNN结构中,序列数据是逐个元素处理的,这种顺序处理方式天然包含了位置信息。但Transformer模型采用并行处理的注意力机制,需要显式地注入位置信息才能理解序列中元素的相对或绝对位置。这就是位置编码&#x…...

神经网络反向传播算法实现与优化指南

1. 神经网络与反向传播算法基础神经网络是机器学习中最强大的工具之一,而反向传播算法则是训练神经网络的核心技术。让我们从一个开发者的角度来理解这个看似复杂的概念。想象你正在教一个孩子识别动物。最初孩子会犯很多错误,但每次错误后你会指出哪里错…...

流体天线阵列与空中计算技术的联合优化实践

1. 流体天线阵列与空中计算技术解析在物联网设备数量爆炸式增长的今天,传统"先通信后计算"的模式正面临严峻挑战。想象一下,当数千个传感器同时向云端发送数据时,不仅会挤占宝贵的无线频谱资源,还会产生难以忍受的通信延…...

3步解密网页视频下载:VideoDownloadHelper智能解析实战指南

3步解密网页视频下载:VideoDownloadHelper智能解析实战指南 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 你是否曾遇到过这样的…...

NovelClaw:基于动态记忆与可观测架构的AI长篇叙事工作台

1. 项目概述:从“一次性生成”到“可检视的写作工作台”如果你尝试过用大语言模型(LLM)来创作长篇小说,大概率会遇到这样的困境:你给了一个精彩的开头设定,模型也洋洋洒洒生成了几千字。但当你想要继续写第…...