azaharizaman/nexus-document

Framework-agnostic document management engine for Nexus ERP monorepo

Maintainers

Package info

github.com/azaharizaman/nexus-document

pkg:composer/azaharizaman/nexus-document

Statistics

Installs: 1

Dependents: 4

Suggesters: 1

Stars: 0

Open Issues: 0

v0.1.0-alpha1 2026-05-05 02:28 UTC

This package is auto-updated.

Last update: 2026-05-05 02:45:30 UTC


README

Framework-agnostic Enterprise Document Management (EDM) engine for Nexus ERP monorepo

Overview

Nexus\Document is a pure PHP, atomic package providing comprehensive document lifecycle management for the Nexus ERP ecosystem. It serves as the centralized authority for document storage, versioning, access control, integrity verification, and compliance-aware retention across all vertical packages (FieldService, Finance, HR, Procurement, etc.).

This package follows the "Logic in Packages, Implementation in Applications" principle, providing framework-agnostic contracts and services that are implemented by the consuming application (Nexus\Atomy).

Key Features

  • S3-Optimized Nested Storage: Year/month partitioned paths for millions of documents with optimal performance
  • Version Control: Complete version history with rollback capabilities and manual pruning
  • Checksum Integrity: SHA-256 verification on every download to prevent data corruption
  • Access Control: Permission-based document access (view, edit, delete, share)
  • ML Classification: Optional content processing for auto-classification and metadata extraction
  • Retention Policies: Compliance-aware retention and purging via Nexus\Compliance integration
  • Document Relationships: Link documents (amendment, supersedes, related, attachment)
  • Temporary URLs: Secure, time-limited download links for external sharing
  • Batch Operations: Efficient multi-document uploads with transaction safety
  • Audit Trail: Complete activity logging via Nexus\AuditLogger integration
  • Multi-Tenancy: Full tenant isolation via Nexus\Tenant integration

Architecture

Framework-Agnostic Design

This package contains zero Laravel dependencies. All logic is pure PHP 8.3+ code that defines:

  • Contracts (Interfaces): What the package needs from the outside world
  • Services: Business logic and orchestration
  • Value Objects: Immutable data structures
  • Exceptions: Domain-specific error handling

The consuming application (apps/Atomy) provides concrete implementations of all contracts using Laravel Eloquent, migrations, and service providers.

Package Structure

packages/Document/
├── composer.json              # Package definition with dependencies
├── LICENSE                    # MIT License
├── README.md                  # This file
└── src/
    ├── Contracts/             # REQUIRED: Interfaces
    │   ├── DocumentInterface.php
    │   ├── DocumentRepositoryInterface.php
    │   ├── DocumentVersionInterface.php
    │   ├── DocumentVersionRepositoryInterface.php
    │   ├── DocumentRelationshipInterface.php
    │   ├── DocumentRelationshipRepositoryInterface.php
    │   ├── PermissionCheckerInterface.php
    │   ├── DocumentSearchInterface.php
    │   ├── ContentProcessorInterface.php
    │   └── RetentionPolicyInterface.php
    │
    ├── Services/              # Business logic
    │   ├── DocumentManager.php
    │   ├── VersionManager.php
    │   ├── RelationshipManager.php
    │   ├── DocumentSearchService.php
    │   └── RetentionService.php
    │
    ├── Core/                  # Internal engine
    │   └── PathGenerator.php  # S3-optimized path generation
    │
    ├── ValueObjects/          # Immutable data structures
    │   ├── DocumentType.php           # Enum
    │   ├── DocumentState.php          # Enum
    │   ├── RelationshipType.php       # Enum
    │   ├── DocumentFormat.php         # Enum
    │   ├── DocumentMetadata.php
    │   ├── VersionMetadata.php
    │   └── ContentAnalysisResult.php
    │
    └── Exceptions/            # Domain exceptions
        ├── DocumentNotFoundException.php
        ├── VersionNotFoundException.php
        ├── PermissionDeniedException.php
        ├── ChecksumMismatchException.php
        ├── InvalidDocumentTypeException.php
        ├── StorageException.php
        ├── DocumentRenderingException.php
        ├── ContentAnalysisException.php
        └── RetentionPolicyViolationException.php

Core Contracts

Entity Interfaces

  • DocumentInterface: Primary document metadata (ID, tenant, owner, type, state, storage path, checksum, version)
  • DocumentVersionInterface: Version history record (version number, change description, creator, checksum)
  • DocumentRelationshipInterface: Document relationship link (source, target, type)

Repository Interfaces

  • DocumentRepositoryInterface: CRUD operations for documents
  • DocumentVersionRepositoryInterface: Version history persistence
  • DocumentRelationshipRepositoryInterface: Relationship management

Service Interfaces

  • PermissionCheckerInterface: Access control (canView, canEdit, canDelete, canShare)
  • DocumentSearchInterface: Metadata-based search (tags, type, owner, date range)
  • ContentProcessorInterface: Content transformation (PDF rendering, ML classification)
  • RetentionPolicyInterface: Compliance-aware retention rules

Value Objects

Enums (Native PHP 8.3)

enum DocumentType: string {
    case CONTRACT = 'contract';
    case INVOICE = 'invoice';
    case REPORT = 'report';
    case IMAGE = 'image';
    case SPREADSHEET = 'spreadsheet';
    case PRESENTATION = 'presentation';
    case PDF = 'pdf';
    case OTHER = 'other';
}

enum DocumentState: string {
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
    case DELETED = 'deleted';
}

enum RelationshipType: string {
    case AMENDMENT = 'amendment';
    case SUPERSEDES = 'supersedes';
    case RELATED = 'related';
    case ATTACHMENT = 'attachment';
}

enum DocumentFormat: string {
    case PDF = 'pdf';
    case HTML = 'html';
    case DOCX = 'docx';
}

Readonly Classes

  • DocumentMetadata: Original filename, MIME type, file size, checksum, tags, custom fields
  • VersionMetadata: Version number, change description, creator, timestamp
  • ContentAnalysisResult: ML predictions (type, confidence, extracted metadata, PII detection, suggested tags)

Usage Examples

1. Upload a Document

use Nexus\Document\Services\DocumentManager;
use Nexus\Document\ValueObjects\DocumentType;

$documentManager = app(DocumentManager::class);

$stream = fopen('/path/to/invoice.pdf', 'r');
$document = $documentManager->upload($stream, [
    'type' => DocumentType::INVOICE,
    'original_filename' => 'invoice-2025-001.pdf',
    'mime_type' => 'application/pdf',
    'tags' => ['finance', 'vendor-acme'],
    'custom_fields' => [
        'vendor_id' => 'VND-001',
        'invoice_number' => 'INV-2025-001',
        'amount' => 1500.00
    ]
], $ownerId);

// Document is stored at: {tenantId}/2025/11/{uuid}/v1.pdf
// Checksum calculated and verified
// Audit log created: "Document 'invoice-2025-001.pdf' uploaded"

2. Upload with Auto-Classification

$document = $documentManager->upload($stream, [
    'original_filename' => 'scanned-document.pdf',
    'mime_type' => 'application/pdf'
], $ownerId, autoAnalyze: true);

// ContentProcessorInterface::analyze() is called
// ML predicts DocumentType::INVOICE with 0.98 confidence
// Metadata automatically populated with extracted fields

3. Download with Permission Check

try {
    $stream = $documentManager->download($documentId, $userId);
    
    // Permission verified via PermissionCheckerInterface::canView()
    // Checksum verified against stored value
    // Audit log created: "User downloaded document"
    
    return response()->stream(function() use ($stream) {
        fpassthru($stream);
    });
} catch (PermissionDeniedException $e) {
    // User lacks permission
} catch (ChecksumMismatchException $e) {
    // Data corruption detected - security alert!
}

4. Generate Temporary Download URL

$url = $documentManager->getTemporaryDownloadUrl($documentId, $userId, ttl: 3600);

// Permission check performed first
// Delegates to StorageDriverInterface::getTemporaryUrl()
// Returns signed URL valid for 1 hour
// Audit log created: "Temporary URL generated"

5. Create a New Version

use Nexus\Document\Services\VersionManager;

$versionManager = app(VersionManager::class);

$newStream = fopen('/path/to/invoice-revised.pdf', 'r');
$version = $versionManager->createVersion(
    $documentId,
    $newStream,
    'Updated vendor address and payment terms',
    $userId
);

// New version created: {tenantId}/2025/11/{uuid}/v2.pdf
// Document version incremented to 2
// Version history preserved
// Audit log created: "Version 2 created by User X"

6. Batch Upload

$files = [
    ['stream' => $stream1, 'metadata' => ['original_filename' => 'photo1.jpg', ...]],
    ['stream' => $stream2, 'metadata' => ['original_filename' => 'photo2.jpg', ...]],
    ['stream' => $stream3, 'metadata' => ['original_filename' => 'photo3.jpg', ...]],
];

$documents = $documentManager->uploadBatch($files);

// All files processed sequentially
// Transaction ensures all-or-nothing persistence
// Single audit log with batch count and total size

7. Create Document Relationship

use Nexus\Document\Services\RelationshipManager;
use Nexus\Document\ValueObjects\RelationshipType;

$relationshipManager = app(RelationshipManager::class);

$relationship = $relationshipManager->createRelationship(
    $invoiceDocId,
    $receiptDocId,
    RelationshipType::RELATED,
    $userId
);

// Link created between invoice and receipt
// Permission verified on source document
// Audit log created: "Relationship created"

8. Search Documents

use Nexus\Document\Services\DocumentSearchService;
use Nexus\Document\ValueObjects\DocumentType;

$searchService = app(DocumentSearchService::class);

// Search by tags
$documents = $searchService->findByTags(['finance', 'urgent'], $userId);

// Search by type with filters
$documents = $searchService->findByType(
    DocumentType::INVOICE,
    [
        'dateFrom' => '2025-01-01',
        'dateTo' => '2025-12-31',
        'ownerId' => $userId
    ],
    $userId
);

// Search by metadata
$documents = $searchService->findByMetadata([
    'customFields.vendor_id' => 'VND-001',
    'customFields.amount' => ['>=', 1000.00]
], $userId);

// All results filtered by permissions and tenant scope

Storage Path Strategy

Nested S3-Optimized Structure

The package uses a year/month partitioned path structure for optimal object storage performance:

{tenantId}/{year}/{month}/{uuid}/v{version}.{extension}

Example:
TEN123456789/2025/11/DOC987654321/v1.pdf
TEN123456789/2025/11/DOC987654321/v2.pdf
TEN123456789/2025/12/DOC111222333/v1.jpg

Performance Benefits

  1. Hot Partition Avoidance: Distributes writes across multiple prefixes instead of all new documents going to one flat folder
  2. Lifecycle Policies: Easy to archive/delete all documents older than N years using prefix-based S3 lifecycle rules
  3. Query Performance: Object storage systems index by prefix - nested structure improves list/search operations
  4. Cost Optimization: Archive old year/month prefixes to Glacier storage class automatically

PathGenerator Service

The Core/PathGenerator service encapsulates all path logic:

use Nexus\Document\Core\PathGenerator;

$pathGenerator = app(PathGenerator::class);

$path = $pathGenerator->generateStoragePath(
    $tenantId,
    $uuid,
    $version,
    $extension
);
// Returns: "TEN123/2025/11/DOC456/v1.pdf"

$components = $pathGenerator->parseStoragePath($path);
// Returns: ['tenant' => 'TEN123', 'year' => '2025', 'month' => '11', 'uuid' => 'DOC456', 'version' => 1]

Content Processing

ContentProcessorInterface Integration

The package defines a ContentProcessorInterface for extensibility:

interface ContentProcessorInterface
{
    /**
     * Render data into a document format (e.g., Service Report to PDF)
     */
    public function render(
        string $templateName,
        array $data,
        DocumentFormat $format
    ): string;

    /**
     * Analyze document content using ML (OCR, classification, metadata extraction)
     */
    public function analyze(string $documentPath): ContentAnalysisResult;
}

Default Implementation (No-Op)

By default, Nexus\Atomy binds a NullContentProcessor that logs warnings:

// No Intelligence package configured
$result = $contentProcessor->analyze($documentPath);
// Returns: ContentAnalysisResult with null predictions and 0.0 confidence

Future Intelligence Integration

When Nexus\Intelligence is available, simply rebind in DocumentServiceProvider:

$this->app->singleton(
    ContentProcessorInterface::class,
    IntelligenceContentProcessor::class
);

// Now analyze() calls ML models for real predictions
// Now render() generates professional PDFs from templates

Integration with Applications

Atomy Implementation

The apps/Atomy application provides concrete implementations:

Models

// apps/Atomy/app/Models/Document.php
class Document extends Model implements DocumentInterface
{
    use SoftDeletes;
    
    protected $casts = [
        'metadata' => 'array',
        'type' => DocumentType::class,
        'state' => DocumentState::class
    ];
    
    // Tenant scoping applied automatically in booted()
}

Repositories

// apps/Atomy/app/Repositories/DbDocumentRepository.php
class DbDocumentRepository implements DocumentRepositoryInterface
{
    public function findById(string $id): ?DocumentInterface
    {
        return Document::find($id);
    }
    
    // ... other methods using Eloquent
}

Service Provider

// apps/Atomy/app/Providers/DocumentServiceProvider.php
class DocumentServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Bind repositories
        $this->app->singleton(
            DocumentRepositoryInterface::class,
            DbDocumentRepository::class
        );
        
        // Bind services
        $this->app->singleton(
            PermissionCheckerInterface::class,
            DocumentPermissionChecker::class
        );
        
        $this->app->singleton(
            ContentProcessorInterface::class,
            NullContentProcessor::class // Override when Intelligence available
        );
        
        // Register package services
        $this->app->singleton(DocumentManager::class);
        $this->app->singleton(VersionManager::class);
        $this->app->singleton(RelationshipManager::class);
    }
}

Dependencies

This package requires:

  • azaharizaman/nexus-storage (MANDATORY): File operations and temporary URL generation
  • azaharizaman/nexus-crypto (MANDATORY): SHA-256 checksum calculation via HasherInterface
  • azaharizaman/nexus-audit-logger (RECOMMENDED): Complete audit trail for all document operations
  • azaharizaman/nexus-tenant (RECOMMENDED): Multi-tenancy isolation and context
  • psr/log (MANDATORY): Logging interface for error/debug logging

Installation

# In the monorepo root
composer require azaharizaman/nexus-document:"*@dev"

# In apps/Atomy
composer require azaharizaman/nexus-document:"*@dev"

Requirements Coverage

This package fulfills all requirements documented in docs/REQUIREMENTS_DOCUMENT.md including:

  • Document CRUD operations with tenant isolation
  • Version control with complete history
  • Permission-based access control
  • Checksum integrity verification
  • S3-optimized storage paths
  • Batch upload operations
  • Document relationship management
  • Metadata-based search
  • Retention policy integration
  • Audit logging for compliance
  • Content processing extensibility

Documentation

Core Documentation

Implementation Details

Code Examples

Quick Links

License

MIT License - see LICENSE file for details.