Bỏ qua, đến nội dung

Câu hỏi thường gặp (FAQ) — File Manager

Sử dụng

Làm sao đổi nơi lưu trữ từ local sang S3?

  1. Vào Settings → File Storage
  2. Nhấn Add storage → chọn loại S3
  3. Điền thông tin kết nối (region, bucket, credentials)
  4. Đánh dấu Default nếu muốn storage mới là mặc định

TIP

File cũ vẫn nằm trên local. Chỉ file mới sẽ được lưu vào S3. Nếu cần di chuyển file cũ, cần thực hiện migration thủ công.

Giới hạn kích thước file?

Giới hạn phụ thuộc vào nhiều tầng:

TầngCấu hìnhMặc định
PluginRules trong storage configTheo storage
Nginxclient_max_body_size1m (cần tăng!)
Node.jsMemory limitPhụ thuộc --max-old-space-size
Cloud storageGiới hạn của providerThường 5GB/file

Để upload file lớn, cần tăng giới hạn ở tất cả các tầng.

Có thể giới hạn loại file cho phép upload không?

Có. Cấu hình MIME type filter trong storage rules:

  • image/* — chỉ ảnh (JPEG, PNG, GIF, WebP, v.v.)
  • application/pdf — chỉ PDF
  • image/*,application/pdf,application/msword — ảnh, PDF, Word

Làm sao lấy URL truy cập file?

URL được tạo tự động khi truy vấn attachment. Plugin hook vào afterFind và tính URL dựa trên:

  • baseUrl + path + filename
  • Với ảnh: thêm thumbnailRule cho URL preview

File có bị xóa khi xóa record không?

, trừ khi storage có cấu hình paranoid: true. Khi bật paranoid:

  • Record trong database bị xóa
  • File trên storage không bị xóa
  • Hữu ích khi cần giữ file backup

Có thể dùng MinIO thay S3 không?

Có. MinIO tương thích S3 API. Cấu hình storage loại s3 với custom Endpoint trỏ đến MinIO server:

Endpoint: https://minio.your-domain.com
Region: us-east-1
Bucket: my-bucket
Access Key: minioadmin
Secret Key: minioadmin

Cấu hình

Credentials nên lưu ở đâu?

Khuyến nghị: Lưu trong Environment Variables plugin:

S3_ACCESS_KEY=AKIA...
S3_SECRET_KEY=secret...
S3_BUCKET=my-uploads

Trong cấu hình storage, sử dụng template:

text
Access Key: $env.S3_ACCESS_KEY
Secret Key: $env.S3_SECRET_KEY

Sử dụng cú pháp {{$env.TÊN_BIẾN}} để tham chiếu biến môi trường.

Có thể cấu hình nhiều storage cùng lúc không?

Có. Tạo nhiều storage backend, mỗi cái với tên riêng. Trong collection, chỉ định storage cho trường attachment:

typescript
// Collection sử dụng storage cụ thể
{
  template: 'file',
  storage: 'my-s3-storage',  // tên storage
}

Thumbnail rule là gì?

Thumbnail rule là hậu tố URL cho ảnh preview, do cloud storage provider hỗ trợ:

ProviderVí dụ thumbnail rule
Alibaba OSS?x-oss-process=image/resize,w_200
Tencent COS?imageMogr2/thumbnail/200x
AWS S3Cần CloudFront + Lambda@Edge

Lỗi thường gặp

Upload thất bại với file lớn?

Kiểm tra theo thứ tự:

  1. Nginx: Tăng client_max_body_size (ví dụ: 100m)
  2. Plugin: Kiểm tra rules giới hạn kích thước
  3. Cloud storage: Kiểm tra quota/limit của provider
  4. Timeout: Tăng timeout cho upload request

Lỗi "no linked or default storage provided"?

Không có storage nào được cấu hình hoặc storage mặc định đã bị xóa. Vào Settings → File Storage và tạo/đặt storage mặc định.

Lỗi khi xóa storage?

Không thể xóa:

  • Storage mặc định (default)
  • Storage đang được sử dụng bởi collection (có trường attachment tham chiếu)

Chuyển collection sang storage khác trước khi xóa.

File URL trả về 404?

Kiểm tra:

  1. Base URL trong storage config đúng không
  2. File thực sự tồn tại trên storage backend
  3. Quyền truy cập (bucket policy, ACL) cho phép public read
  4. Nếu dùng CDN, cache có thể chưa cập nhật

Lỗi "Failed to delete file"?

Plugin ném FileDeleteError khi không thể xóa file khỏi storage backend. Kiểm tra:

  • Credentials còn hợp lệ không
  • Bucket/container có quyền delete không
  • File có tồn tại trên storage không (có thể đã bị xóa thủ công)

Nâng cao

Có thể đăng ký storage type tùy chỉnh không?

Có. Sử dụng API registerStorageType:

typescript
import { PluginFileManagerServer } from '@digiforce-nc/plugin-file-manager';

class MyCustomStorage extends StorageType {
  make() { /* return multer engine */ }
  delete(records) { /* delete files */ }
}

const fileManager = app.pm.get<PluginFileManagerServer>('file-manager');
fileManager.registerStorageType('my-storage', MyCustomStorage);

Upload file từ server-side code?

typescript
const fileManager = app.pm.get<PluginFileManagerServer>('file-manager');

// Upload file
const data = await fileManager.uploadFile({
  filePath: '/tmp/report.pdf',
  storageName: 'my-s3-storage',
});

// Tạo file record trong collection
const record = await fileManager.createFileRecord({
  collectionName: 'attachments',
  filePath: '/tmp/report.pdf',
  storageName: 'my-s3-storage',
  values: { title: 'Báo cáo tháng 3' },
});

Lấy file stream từ storage?

typescript
const fileManager = app.pm.get<PluginFileManagerServer>('file-manager');
const { stream, contentType } = await fileManager.getFileStream(attachmentRecord);

Hữu ích khi cần xử lý file (chuyển đổi, nén, v.v.) mà không cần download qua URL.