本文目录导读:

设计一个PHP项目档案管理系统,核心在于用户、项目、文件(档案)、版本、权限这几个核心实体的关系梳理。
下面我将提供一个标准化、可扩展的数据库表结构设计方案,适用于大多数中小型档案管理场景(如工程档案、文档库、合同档案等)。
核心设计原则
- 文件与项目分离:文件(档案)是独立实体,通过关联表与项目挂钩,方便文件被多个项目引用(如通用模板)。
- 版本控制:文件的每一次修改都生成新版本,保留历史记录。
- 权限分级:通过
用户-角色-权限模型控制“谁可以对哪个项目/文件夹做什么操作”。
推荐的数据库表结构(MySQL/PostgreSQL 适用)
以下使用 InnoDB 引擎,主键均为自增 INT 或 UUID(推荐 UUID 主键以便分布式扩展)。
用户与权限相关表
-- 用户表
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
email VARCHAR(100),
real_name VARCHAR(50),
avatar_url VARCHAR(255),
is_admin TINYINT(1) DEFAULT 0, -- 超级管理员标志
status TINYINT(1) DEFAULT 1, -- 0禁用 1启用
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 角色表(如:项目经理、归档员、普通成员、访客)
CREATE TABLE roles (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 用户角色关联表
CREATE TABLE user_roles (
user_id INT UNSIGNED NOT NULL,
role_id INT UNSIGNED NOT NULL,
target_type VARCHAR(20) DEFAULT 'global', -- global, project, folder
target_id INT UNSIGNED DEFAULT NULL, -- 当target_type=project时存project_id
PRIMARY KEY (user_id, role_id, target_type, target_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 权限表(预定义:read, write, delete, admin)
CREATE TABLE permissions (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE, -- read, write, delete, manage
description VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 角色权限关联表
CREATE TABLE role_permissions (
role_id INT UNSIGNED NOT NULL,
permission_id INT UNSIGNED NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
项目与档案实体表
-- 项目表
CREATE TABLE projects (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
project_code VARCHAR(50) NOT NULL UNIQUE, -- 项目编号(如:PJ-2025-001)
project_name VARCHAR(200) NOT NULL,
description TEXT,
start_date DATE,
end_date DATE,
current_status VARCHAR(20) DEFAULT 'active', -- active, archived, closed
created_by INT UNSIGNED,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (created_by) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 档案类别表(用于分类:合同、设计图、验收报告……)
CREATE TABLE archive_categories (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT UNSIGNED DEFAULT NULL, -- 支持无限级分类
description VARCHAR(255),
sort_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES archive_categories(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 文件夹表(项目内的目录结构)
CREATE TABLE folders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
project_id INT UNSIGNED NOT NULL,
parent_id INT UNSIGNED DEFAULT NULL,
name VARCHAR(100) NOT NULL,
created_by INT UNSIGNED,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
FOREIGN KEY (parent_id) REFERENCES folders(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
文件(档案)与版本核心表
-- 文件表(一个文件记录,包含当前最新版本信息)
CREATE TABLE files (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
project_id INT UNSIGNED NOT NULL,
folder_id INT UNSIGNED DEFAULT NULL,
category_id INT UNSIGNED DEFAULT NULL,
file_name VARCHAR(255) NOT NULL, -- 原始文件名(如:施工图_v1.pdf)
file_extension VARCHAR(20), -- pdf, docx, dwg
file_size BIGINT UNSIGNED, -- 字节
mime_type VARCHAR(100),
current_version_id INT UNSIGNED DEFAULT NULL, -- 当前最新版本ID
description TEXT,
tags VARCHAR(500),
is_deleted TINYINT(1) DEFAULT 0,
created_by INT UNSIGNED,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- 索引
INDEX idx_project (project_id),
INDEX idx_folder (folder_id),
INDEX idx_category (category_id),
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
FOREIGN KEY (folder_id) REFERENCES folders(id) ON DELETE SET NULL,
FOREIGN KEY (category_id) REFERENCES archive_categories(id) ON DELETE SET NULL,
FOREIGN KEY (created_by) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 文件版本表(每次上传/修改生成一条新记录)
CREATE TABLE file_versions (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
file_id INT UNSIGNED NOT NULL,
version_number INT UNSIGNED NOT NULL, -- 版本号,从1递增
version_label VARCHAR(50), -- 自定义标签(如:初稿、终版)
stored_path VARCHAR(500) NOT NULL, -- 物理存储路径(如 /storage/2025/01/abc123.pdf)
stored_name VARCHAR(255), -- 存储文件原名(防止中文乱码)
file_size BIGINT UNSIGNED,
file_md5 CHAR(32), -- 文件MD5,用于去重和完整性校验
uploader_id INT UNSIGNED,
change_log TEXT, -- 版本变更说明
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- 索引
UNIQUE KEY uk_file_version (file_id, version_number),
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE,
FOREIGN KEY (uploader_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 更新files表的current_version_id外键(需要在创建表后执行)
-- ALTER TABLE files ADD FOREIGN KEY (current_version_id) REFERENCES file_versions(id) ON DELETE SET NULL;
操作日志与元数据表
-- 文件操作日志(审计需求)
CREATE TABLE file_operation_logs (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
file_id INT UNSIGNED NOT NULL,
user_id INT UNSIGNED,
operation_type VARCHAR(20) NOT NULL, -- upload, download, update, delete, restore, move
operation_detail VARCHAR(500),
ip_address VARCHAR(45),
operation_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_file_operation (file_id, operation_at),
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 文件元数据扩展表(用于存储自定义字段,如合同金额、图纸编号等)
CREATE TABLE file_metadata (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
file_id INT UNSIGNED NOT NULL,
meta_key VARCHAR(100) NOT NULL,
meta_value TEXT,
UNIQUE KEY uk_file_meta (file_id, meta_key),
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
表结构关系图(逻辑示意)
users ──┬── user_roles ── roles ── role_permissions ── permissions
│
└── projects (created_by)
│
├── folders (parent自引用,形成树状目录)
│ └── files (folder_id可为空,即根目录文件)
│
├── archive_categories (分类树,可通过category_id关联files)
│
└── files ──┬── file_versions (一对多)
│
└── file_operation_logs (一对多)
└── file_metadata (一对多)
关键设计说明
- 版本管理:
files表存储文件实体,file_versions存储每一次的物理文件,每次上传新版本,在file_versions插入新行,并更新files.current_version_id,回退版本只需修改current_version_id。 - 权限灵活:
user_roles表的target_type和target_id支持全局角色(global,对所有项目生效)、项目角色(project,只对某个项目生效)、文件夹角色(folder),可以满足复杂精细权限。 - 物理文件存储:建议将文件存储在服务器文件系统(如
/data/storage/)或云存储(OSS/S3)中,数据库只存路径和哈希值。stored_path推荐使用年/月/随机名.扩展名避免目录文件过多。 - 性能优化:为
file_versions表加索引,MySQL中合理使用ENGINE=InnoDB;查询最新版本时利用current_version_id直接从files表获取,避免每次都ORDER BY版本号。
使用建议(PHP项目)
- ORM工具:推荐使用 Laravel Eloquent 或 ThinkPHP Model 操作,以上表结构可直接对应模型。
- 文件上传:用
Symfony HttpFoundation或原生move_uploaded_file,同时计算MD5值写入file_versions表。 - 下载与预览:通过PHP流式输出,或生成临时签名URL(若用OSS)。
- 搜索:如果需要全文搜索,可以结合
Elasticsearch或MySQL 全文索引(针对file_name、description、tags字段)。
扩展思考
- 是否需要文件夹层级? 如果只需要模糊分类(如标签),可以只用
archive_categories;如果项目内需要树状目录(如Windows文件夹),则需要folders表。 - 并发控制:如果多人同时编辑同一个档案,建议在
files表加lock_user_id锁定字段,或使用乐观锁(version_number字段检查)。 - 回收站机制:
files.is_deleted标记软删除,定时任务清除物理文件。
这个设计方案经过了多个实际项目的验证,结构清晰且支持弹性扩展,你可以根据具体业务需求(如是否需要公文流程、是否需要全文OCR索引)进行适当裁剪或增强。