Skip to content

hzb666/LabStorageManager

Repository files navigation

LabStorageManager

3.gif

Python Node.js SQLite License zread deepwiki

面向实验室场景的试剂与耗材管理系统,覆盖申购、审批、到货、入库、借用、归还、公告、设备会话管理等完整流程。项目采用 FastAPI + React 前后端分离架构,后端以 SQLite WAL 模式为核心存储,前端基于 React 19 和 Vite 8 构建,适合单实验室或中小团队快速部署。

目录

项目简介

LabStorageManager 解决的是实验室中最容易失控的几类问题:

  • 试剂和耗材分开管理,但又能共享统一的认证、审批和搜索体验。
  • CAS 号、防重复采购、拼音检索、模糊搜索、批量导入这些实验室高频需求由系统直接支持。
  • 订单到库存的流转保留审计链路,避免“入库后订单消失”带来的追溯困难。
  • 图片不入库,只落文件系统并在数据库中保存 URL,减轻数据库压力。

适用场景:

  • 高校课题组或研究平台
  • 企业研发实验室
  • 需要部署在单机 / 轻量服务器上的库存系统

核心能力

  • 试剂与耗材双流程管理 试剂支持 CAS 号、到货确认、一键入库;耗材支持独立订单流程与完成态管理。
  • CAS 防重与库存预警 申购时可按 CAS 查询现有库存和历史订单,降低重复购买概率。
  • 中文拼音检索与 FTS 搜索 名称、分类、品牌、位置等字段会预计算拼音,并结合 SQLite FTS5 提供搜索能力。
  • 库存借还闭环 支持借出、归还、借用历史、当前借用人、临时保管人等字段。
  • 公共货架与常用试剂 支持公共库存场景,便于管理共享样品或常备试剂。
  • 用户、设备、会话治理 支持 HttpOnly Cookie 登录、设备列表、批量注销、IP/设备数量限制。
  • 公告与图片上传 公告支持图片,图片文件落地到 static/,并受尺寸、类型、上传频率控制。
  • CLI 与自动化入口 提供 python -m lsm_cli 命令行入口,适合脚本、agent 和无 UI 场景操作。
  • 部署简单 内置 Docker Compose,可快速拉起 frontend + backend + redis

技术栈

层级 技术
后端 FastAPI, SQLModel, SQLite, Redis, python-jose, bcrypt, Pillow, pypinyin
前端 React 19, TypeScript 5.9, Vite 8, React Router 7, Zustand, React Hook Form, Valibot
UI Radix UI, Tailwind CSS 4, Lucide React, Framer Motion
表格与数据 TanStack Table 8, TanStack Virtual, Axios
化学相关 RDKit(前端分子结构渲染)
构建与校验 Poetry, npm, ruff, ESLint, TypeScript build
部署 Docker Compose, Nginx, Uvicorn

快速开始

1. 前置要求

建议本地环境:

  • Python 3.11+
  • Node.js 20+
  • npm 10+
  • Redis 6+ 或 7+(本地开发可选,但推荐开启)

2. 克隆仓库

git clone <your-repo-url> LabStorageManager
cd LabStorageManager

3. 配置后端环境

推荐使用 Poetry:

poetry install

如果你使用 pip

python -m venv .venv

# Windows PowerShell
.venv\Scripts\Activate.ps1

# macOS / Linux
source .venv/bin/activate

pip install -r requirements.txt

4. 配置前端环境

cd frontend
npm install
cd ..

5. 创建环境变量文件

# Windows PowerShell
Copy-Item .env.example .env

# macOS / Linux
cp .env.example .env

最少需要确认这些字段:

变量 说明
ENV 本地开发建议 development
CORS_ORIGINS 前端地址白名单,开发时通常为 http://localhost:5173
DEFAULT_ADMIN_PASSWORD 必填;后端首次启动会用它初始化管理员
ALGORITHM 默认 RS256
DATABASE_URL 默认 SQLite 文件

开发环境建议:

  • ENV=development
  • CORS_ORIGINS 改成你的前端地址
  • 首次启动前设置 DEFAULT_ADMIN_PASSWORD

说明:

  • ENV=development 且本地还没有 RSA 密钥时,后端可自动生成临时密钥对。
  • ENV=production 时,ALGORITHM 必须为 RS256,并且 .keys/private.pem / .keys/public.pem 必须可用。

6. 启动后端

python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

启动后可访问:

  • 开发文档: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc
  • 健康检查: http://localhost:8000/health

注意:

  • 只有开发模式会暴露 /docs/redoc/openapi.json
  • 首次启动会自动初始化至少一个管理员账户。

7. 启动前端

cd frontend
npm run dev

默认前端地址:

  • http://localhost:5173

环境变量

必填项

变量 示例 说明
ENV development development/devproduction
CORS_ORIGINS ["http://localhost:5173"] JSON 数组字符串
DEFAULT_ADMIN_PASSWORD your-password 默认管理员密码,未设置将导致启动失败
ALGORITHM RS256 生产环境必须使用 RS256

常用项

变量 默认值 说明
DATABASE_URL sqlite:///./lab_inventory.db SQLite 数据库连接串
TRUST_PROXY_HEADERS false 是否信任反向代理头
ACCESS_TOKEN_EXPIRE_MINUTES 10080 登录态默认 7 天
SESSION_EXPIRE_HOURS 72 会话有效期
MAX_IP_PER_USER 5 每个用户允许的最大 IP 数
MAX_DEVICE_PER_USER 10 每个用户允许的最大设备数
REDIS_HOST 127.0.0.1 Redis 主机
REDIS_PORT 6379 Redis 端口
REDIS_DB 1 Redis 逻辑库
REDIS_KEY_PREFIX lsm Redis key 前缀

上传与图片

变量 默认值 说明
MAX_FILE_SIZE_MB 10 单文件体积限制
MAX_UPLOAD_REQUEST_SIZE_MB 12 单次请求总上传限制
ALLOWED_IMAGE_TYPES image/jpeg,image/png,image/webp 允许的 MIME 类型
MAX_IMAGE_WIDTH 800 最大宽度
MAX_IMAGE_HEIGHT 800 最大高度
MAX_IMAGE_SIZE_KB 100 压缩后图片大小上限
UPLOAD_RATE_LIMIT_COUNT 10 上传限流次数
UPLOAD_RATE_LIMIT_WINDOW_SECONDS 300 上传限流时间窗口

JWT 与密钥

变量 说明
PRIVATE_KEY_PATH RS256 私钥路径
PUBLIC_KEY_PATH RS256 公钥路径
SECRET_KEY HS256 时使用;开发环境可自动生成临时值

常用命令

后端

# 开发启动
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# 代码检查
ruff check app/

前端

cd frontend

# 开发启动
npm run dev

# Lint
npm run lint

# 生产构建
npm run build

Docker

# 构建并启动
APP_PORT=80 docker compose up -d --build

# 查看状态
docker compose ps

# 查看日志
docker compose logs -f backend
docker compose logs -f frontend
docker compose logs -f redis

CLI 支持

仓库提供本地命令行入口 lsm_cli/README.md,适合 agent、脚本任务和不想打开前端的开发者。CLI 只通过后端 API 工作,不直接访问数据库,也不导入服务层。

支持范围

  • auth 支持 loginlogoutwhoami
  • inventory 支持列表、详情、CAS 查询、借还、手工入库、更新等日常库存操作
  • reagent-orders 支持列表、创建、更新、到货确认、一键入库等试剂订单流程
  • consumable-orders 支持列表、创建、更新、完成等耗材订单流程

限制说明:

  • 不开放 delete
  • 不开放 export
  • 不开放文件上传
  • 不开放 CLI 未显式暴露的 API

快速示例

# 查看顶层帮助
python -m lsm_cli --help

# 交互式登录
python -m lsm_cli auth login --username alice

# 查询库存
python -m lsm_cli inventory list --page 1 --page-size 20 --param search=乙醇

# 创建试剂订单
python -m lsm_cli reagent-orders create --data-file payload.json

# 查看当前登录用户
python -m lsm_cli auth whoami

使用约定

  • 默认 API 地址为 http://127.0.0.1:8000/api
  • auth login 支持 --base-url--timeout
  • 自动化脚本推荐使用 --password-stdin 传递密码,避免明文出现在 shell history
  • 所有命令向 stdout 输出 JSON,并通过退出码区分错误类别
  • 面向 agent 的受限 CLI 操作流程见 AGENTS Skill
  • Windows / macOS 目录版安装、配置文件位置、完整退出码契约见 lsm_cli/README.md

系统架构

总体结构

Browser / Browser Extension
        |
        v
React 19 + Vite + Axios
        |
        v
FastAPI
  |- Auth / Session
  |- Inventory
  |- Reagent Orders
  |- Consumable Orders
  |- Announcements
  |- Event Stream
        |
        v
SQLite (WAL) + Redis + static/

后端特点

  • 使用 FastAPI 暴露 API,开发模式下提供 Swagger/ReDoc。
  • SQLite 在每个连接上都会显式开启 PRAGMA journal_mode=WAL
  • 数据库初始化时会自动创建表、性能索引、FTS 表与触发器,并检查 schema 一致性。
  • 全局中间件处理以下问题:
    • 请求日志与 X-Request-ID
    • 上传请求体积限制
    • 生产环境 HTTPS 跳转
    • Cookie 鉴权下的 CSRF Origin/Referer 校验
    • 安全响应头与 CSP/HSTS

前端特点

  • 使用 BrowserRouter 管理路由。
  • 登录态通过 HttpOnly Cookie 持有,Axios 统一开启 withCredentials
  • 页面采用懒加载,主要模块包括:
    • 仪表盘
    • 试剂订单
    • 耗材订单
    • 库存
    • 公共货架
    • 导入页
    • 设备管理
    • 用户管理
    • 公告管理
    • 操作日志

认证与会话

  • 登录接口写入 Cookie,不依赖浏览器 localStorage 保存 token。
  • 支持多设备登录与会话列表管理。
  • 会话可按设备名称、IP 等信息追踪。
  • 401 会统一触发前端登出与跳转。

前端本地存储

Key 用途
app-ui 主题、字体来源、Dashboard 页签、公告已读/关闭、Bug 按钮隐藏
app-table 表格 expandAllfuzzySearch、列宽
app-auth-meta 设备 id/name、remembered user
auth-storage Zustand 登录态持久化,带 TTL
sidebar-storage Zustand 侧栏状态持久化,带 TTL
chemical_properties_cache 化学属性缓存,独立长 TTL
cart_import_batch_latest 扩展导入桥接批次,2 小时 TTL

搜索与性能

  • inventoryreagent_orderconsumable_orderusers 建有 SQLite FTS5 虚表。
  • 名称、拼音、拼音首字母等字段会被索引,便于中文检索。
  • 大量列表查询配套了状态、申请人、时间、公共货架等复合索引。

关键业务规则

这些规则直接影响系统正确性,开发和运维都应该了解。

1. SQLite 必须启用 WAL

这是并发读写的基础约束,项目在数据库连接层已强制设置。

2. 订单到库存是 Copy,不是 Move

试剂一键入库时会根据订单生成库存记录,但订单本身保留,用于审计和回溯。

3. 所有格式化输入在后端标准化

CAS 号等关键字段会在服务端清洗,避免由于大小写、空格、分隔符差异导致重复数据。

4. 数据写接口必须带权限控制

涉及写操作的接口需要校验当前用户身份,管理员能力与普通用户能力分离。

5. 错误反馈分层

  • 输入校验错误应在表单字段旁展示
  • toast 主要用于非字段级错误

6. 生产环境有额外约束

  • 生产环境必须使用 RS256
  • Cookie 场景下会启用更严格的 CSRF 与 HTTPS 策略
  • 未配置 HTTPS 时,不应把 ENV 直接切到 production

目录结构

根目录

.
├── app/                  # FastAPI 后端
├── frontend/             # React 前端
├── browser-extension/    # 浏览器扩展,用于购物车导入等场景
├── docker/               # Dockerfile、Nginx、入口脚本
├── static/               # 图片与静态文件
├── docs/                 # 项目文档
├── tests/                # 后端测试目录
├── docker-compose.yml    # 一体化部署编排
├── pyproject.toml        # 后端依赖与工具配置
├── requirements.txt      # pip 安装入口
└── README.md

后端

app/
├── main.py               # FastAPI 入口、中间件、路由装配
├── database.py           # SQLModel 引擎、WAL、FTS、索引初始化
├── api/                  # 路由层
├── core/                 # 配置、认证、常量、请求工具
├── models/               # SQLModel 数据模型
└── services/             # 业务服务

主要接口模块:

  • users.py
  • user_sessions.py
  • user_logs.py
  • inventory.py
  • reagent_orders.py
  • consumable_orders.py
  • announcements.py
  • cart_sync.py
  • events.py
  • error_logs.py

前端

frontend/src/
├── api/                  # Axios API 封装
├── components/           # UI 组件
├── hooks/                # 自定义 hooks
├── lib/                  # 工具、常量、校验
├── pages/                # 页面级组件
└── store/                # Zustand 状态管理

部署说明

方案一:Docker Compose

这是当前仓库最直接的部署方式。

包含的服务:

  • frontend
  • backend
  • redis

步骤:

git clone <your-repo-url> LabStorageManager
cd LabStorageManager
cp .env.example .env

至少修改:

  • DEFAULT_ADMIN_PASSWORD
  • CORS_ORIGINS
  • REDIS_PASSWORD
  • ENV

然后启动:

APP_PORT=80 docker compose up -d --build

检查服务:

docker compose ps
curl http://127.0.0.1:${APP_PORT:-80}/
curl http://127.0.0.1:${APP_PORT:-80}/health

说明:

  • 前端镜像基于 node:20-alpine 构建,运行层是 nginx:1.27-alpine
  • 后端镜像基于 python:3.11-slim,使用 uvicorn 启动。
  • Compose 会把 Redis 地址注入为容器内部服务名 redis

方案二:本地前后端分开跑

适合开发调试。

  1. 本地启动 Redis(推荐)
  2. 启动后端 uvicorn
  3. 启动前端 vite
  4. 前端通过 CORS_ORIGINS 与 API 基地址访问后端

附属模块

浏览器扩展

仓库包含 browser-extension/,用于浏览器侧导入或购物车同步相关场景。后端提供了 /cart-import 路由,会将入口跳转到前端页面。

公告图片与静态资源

  • 静态资源默认挂载在 /static
  • 响应头附带缓存控制
  • 图片安全头由后端统一补齐

故障排查

启动时报 DEFAULT_ADMIN_PASSWORD must be set

原因: 未设置默认管理员密码。

处理: 在 .env 中补充 DEFAULT_ADMIN_PASSWORD 后重启后端。

生产环境访问 /docs 为 404

原因: 生产模式默认关闭 API 文档。

处理: 确认 ENV=development 时再访问 /docs

登录后立刻掉线或 Cookie 不生效

原因:

  • CORS_ORIGINS 未正确配置
  • 浏览器与后端地址不匹配
  • 在无 HTTPS 的环境使用了 production

处理:

  • 开发时设为 ENV=development
  • 检查前端域名是否在 CORS_ORIGINS
  • 确认浏览器实际请求携带 Cookie

Redis 连不上

影响: 会话或限流相关能力可能异常,核心库存数据仍在 SQLite。

处理:

  • 确认 REDIS_HOSTREDIS_PORTREDIS_PASSWORD
  • 检查容器或本地 Redis 是否已启动

图片上传失败

检查以下几项:

  • 文件类型是否在 ALLOWED_IMAGE_TYPES
  • 请求体是否超过 MAX_UPLOAD_REQUEST_SIZE_MB
  • 单图是否超过限制或服务器目录无写权限

搜索结果异常或性能下降

检查以下几项:

  • 数据库初始化是否完整执行
  • FTS 虚表和触发器是否存在
  • 是否误删了 SQLite 索引或数据库文件

AGENTS Skill

仓库在 lsm_cli/lab-storage-manager-cli/ 提供了一个专门用于操作 CLI 的 skill。它的作用不是解释开发约定,而是约束 agent 只能通过 python -m lsm_cli 与系统交互,并严格遵守当前 CLI 已暴露的命令面。

适用场景

  • 需要通过 CLI 登录、查询库存、查看借用状态
  • 需要通过 CLI 创建或更新试剂订单、确认到货、一键入库
  • 需要通过 CLI 创建、更新或完成耗材订单
  • 需要在 agent 自动化中避免 raw HTTP、数据库直连、直接导入后端模块

硬限制

  • 只允许调用 python -m lsm_cli 及其已暴露子命令
  • 禁止使用 curlInvoke-RestMethodrequestshttpx、数据库直连或伪造本地 token
  • 写操作前必须先通过 CLI 查询拿到准确 ID;禁止猜测 ID
  • 目标不唯一、字段含义不清或单位/数量有歧义时,必须先确认,不能“先试一下”
  • 登录只允许普通用户账号;推荐 --password-stdin
  • 不支持 deleteexport、文件上传、用户管理、会话管理、密码修改、头像修改

推荐执行流程

  1. python -m lsm_cli --help 确认目标能力是否存在。
  2. 需要认证时,用 auth login 登录,再用 auth whoami 校验身份。
  3. 对写操作先用 listgetcascodemy-* 等读命令定位准确 ID。
  4. 再执行真正的写操作,并再次核对目标 ID、动作和输入值。
  5. 如果命令失败,优先按退出码处理;不要切换到 HTTP 或数据库旁路。

参考入口

许可证

本项目使用 Apache License 2.0。详见 LICENSE

Releases

No releases published

Packages

 
 
 

Contributors