還記得當初的開發計劃表嗎:
Phase 1: Core Infrastructure & Setup ✅ COMPLETED
Phase 2: Core API Development ⏳ NEXT
Phase 3: Role-Specific Features
Phase 4: Calendar & UI Components
Phase 5: Advanced Features & Polish
現在進行到Phase 2
由於第一階段它一次全部都跑完了,
一時有點難吸收,這次我請他調整執行各階段時,
都要一步一步來,而且要加上說明他做了什麼。
目的與原因: 為所有數據實體建立 MongoDB 架構,這是 API 數據基礎。
實施細節:
需建立的檔案:
src/main/js/models/User.js
src/main/js/models/RehabTask.js
src/main/js/models/Progress.js
src/main/js/models/Comment.js
src/main/js/models/Surgery.js
Claude生成的內容比想像中的複雜許多,我想將資料庫拆成兩天的文章來解析,
今天就先針對User 以及 RehabTask兩個Model來介紹。
此模型是整個系統的基石,專為支援三種主要角色而設計:病患、物理治療師和醫生。
bcrypt
密碼雜湊功能,確保所有密碼在儲存到資料庫前都已加密,有效防止資料外洩。fullName
會即時合併使用者的名和姓;age
會根據出生日期動態計算年齡,這些屬性都不會實際儲存在資料庫中。// Virtual for full name
userSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
// Virtual for age calculation
userSchema.virtual('age').get(function() {
if (!this.dateOfBirth) return null;
const today = new Date();
const birthDate = new Date(this.dateOfBirth);
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
});
// Pre-save middleware to hash password
userSchema.pre('save', async function(next) {
// Only hash the password if it has been modified (or is new)
if (!this.isModified('password')) return next();
try {
// Hash password with cost of 12
const saltRounds = parseInt(process.env.BCRYPT_ROUNDS) || 12;
this.password = await bcrypt.hash(this.password, saltRounds);
next();
} catch (error) {
next(error);
}
});
comparePassword
能夠安全地比對使用者輸入的密碼是否正確;generateAuthToken
則用於登入後生成 JWT token,方便身分驗證。// Instance method to compare password
userSchema.methods.comparePassword = async function(candidatePassword) {
try {
return await bcrypt.compare(candidatePassword, this.password);
} catch (error) {
throw new Error('Password comparison failed');
}
};
// Instance method to generate JWT token (to be implemented in auth service)
userSchema.methods.generateAuthToken = function() {
// This will be implemented in the auth service
return {
userId: this._id,
role: this.role,
email: this.email
};
};
findByEmail
和 findByRole
允許你透過電子郵件或角色快速查詢使用者資料,提高程式碼的簡潔性。// Static method to find user by email
userSchema.statics.findByEmail = function(email) {
return this.findOne({ email: email.toLowerCase() });
};
// Static method to find users by role
userSchema.statics.findByRole = function(role) {
return this.find({ role, isActive: true });
};
email
和 role
)建立索引,提升查詢效能。同時,在傳送資料給前端時,自動移除敏感的密碼資訊。// Index for better query performance
userSchema.index({ email: 1 });
userSchema.index({ role: 1 });
userSchema.index({ 'assignedPatients': 1 });
userSchema.index({ 'assignedProviders.providerId': 1 });
// Ensure virtual fields are serialized
userSchema.set('toJSON', {
virtuals: true,
transform: function(doc, ret) {
delete ret.password;
delete ret.__v;
return ret;
}
});
RehabTask
不僅是儲存復健任務的資料結構,它還內建多項智能功能,確保數據的完整性、效率和自動化。許多設置如同User使用的功能,以下就不列出程式碼。
required
、maxlength
和 enum
等,確保像任務標題、描述和類別等資料都符合預設格式,避免無效數據。這些屬性不會儲存在資料庫中,但能即時提供重要資訊。
completionPercentage
:動態計算任務的完成百分比。daysRemaining
:顯示任務剩餘天數。isOverdue
:判斷任務是否已過期。這些功能將常見的業務邏輯自動化,讓程式碼更簡潔。
pre-save
中介軟體:在每次儲存前,自動更新任務狀態,例如當總會話數完成時,將狀態設為「已完成」。markSessionCompleted
:這個方法會自動增加任務的完成次數,並更新依從性百分比。這些是模型層級的查詢工具,優化了數據檢索。
findActiveTasksForPatient
和 findTasksByTherapist
:提供快速且預先載入相關資訊的查詢,減少後端額外的資料庫請求,大幅提升效能。