Skip to main content

Backend

The Documents module handles file upload, metadata, label tagging, file download/preview, and CRUD within the project context, with a filterable global index.

File Structure

app/
├── Http/
│ ├── Controllers/Documents/
│ │ └── DocumentController.php
│ └── Requests/Documents/
│ ├── StoreDocumentRequest.php
│ └── UpdateDocumentRequest.php
├── Models/
│ └── Document.php
├── Queries/Documents/
│ ├── DocumentIndexQuery.php
│ └── DocumentStatsQuery.php
└── Services/Documents/
└── DocumentService.php

Routes

MethodURIActionDescription
GET/documentsindexGlobal paginated document list with filters
POST/projects/{project}/documentsstoreUpload new document to the project
PUT/projects/{project}/documents/{document}updateUpdate document metadata/labels
DELETE/projects/{project}/documents/{document}destroyDelete document and file
GET/projects/{project}/documents/{document}/downloaddownloadFile download
GET/projects/{project}/documents/{document}/previewpreviewInline file preview

Controller

The DocumentController orchestrates the flow and delegates storage logic to DocumentService.

Methods

  • index() - Uses DocumentIndexQuery for paginated list and DocumentStatsQuery for statistics cards
  • store() - Validates with StoreDocumentRequest, delegates upload to DocumentService::upload() and redirects to projects.show?tab=documents
  • update() - Validates with UpdateDocumentRequest, delegates update to DocumentService::update()
  • destroy() - Delegates deletion to DocumentService::delete()
  • download() - Delegates file download to DocumentService::download()
  • preview() - Delegates inline preview to DocumentService::preview()

Service

DocumentService encapsulates the module's file-system logic.

Main Responsibilities

  • upload() - generates a unique filename, saves file to local/documents disk, creates document record, and syncs labels
  • update() - updates only metadata (name, notes) and syncs labels
  • delete() - deletes physical file (if present) then the DB record
  • download() - verifies file existence and returns a download response with the document name
  • preview() - verifies file existence, determines mime-type, and returns an inline response with secure headers

Model

The Document model is located in app/Models/Document.php.

Features

  • project relationship - each document belongs to a project
  • labels relationship - many-to-many with Label via document_label pivot
  • Scopes - forProject(), withLabel(), search(), recent()
  • File helpers - file_size (accessor), file_extension (accessor)
  • URL helpers - getDownloadUrl(), getPreviewUrl(), getDeleteUrl(), getUpdateUrl()
  • toFormPayload() - edit payload (id + editable fields + label_ids)

Form Requests

Validation handled by:

  • StoreDocumentRequest - document creation/upload
  • UpdateDocumentRequest - document metadata update

Required Fields (store)

  • name - document name
  • file - required file (mimes:pdf,jpg,jpeg,png, max 10MB)

Required Fields (update)

  • name - document name

Optional Fields

  • label_ids - label array (exists:labels,id)
  • notes - notes (max:1000)

Query Classes

The module uses Query Classes to keep query logic out of the controller.

DocumentIndexQuery

Manages the global document list with:

  • eager loading project, labels
  • filter by label (label_id)
  • text search (search) on document/project name
  • recent sorting (uploaded_at desc via recent() scope)
  • pagination (20)

DocumentStatsQuery

Calculates statistics for the index:

  • this_month - documents uploaded in the current month
  • by_label - top labels by document count (max 5)