simplecontent

package
v0.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 3, 2026 License: MIT Imports: 11 Imported by: 3

README

Simple Content Library

A reusable Go library for content management with a unified API that simplifies content operations while providing pluggable storage backends and repository implementations.

Overview

The simplecontent package provides a clean, pluggable architecture for content management systems with a content-focused API design. It separates concerns between:

  • Domain types: Content, Object, metadata types
  • Unified Service Interface: Content-focused operations that hide storage implementation details
  • Advanced StorageService Interface: Object-level operations for advanced users
  • Repository & Storage: Memory, PostgreSQL, S3, filesystem backends

Quick Start

package main

import (
    "context"
    "log"
    "strings"

    "github.com/google/uuid"
    "github.com/tendant/simple-content/pkg/simplecontent"
    "github.com/tendant/simple-content/pkg/simplecontent/config"
)

func main() {
    // Configure service using config system
    cfg, err := config.Load(
        config.WithDatabaseType("memory"),
        config.WithStorageBackend("memory", map[string]interface{}{}),
    )
    if err != nil {
        log.Fatal(err)
    }

    svc, err := cfg.BuildService()
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // Upload content with data in one operation (NEW!)
    content, err := svc.UploadContent(ctx, simplecontent.UploadContentRequest{
        OwnerID:      uuid.New(),
        TenantID:     uuid.New(),
        Name:         "My Document",
        Description:  "A sample document",
        DocumentType: "text/plain",
        Reader:       strings.NewReader("Hello, World!"),
        FileName:     "hello.txt",
        Tags:         []string{"sample", "document"},
    })
    if err != nil {
        log.Fatal(err)
    }

    // Download content data directly
    reader, err := svc.DownloadContent(ctx, content.ID)
    if err != nil {
        log.Fatal(err)
    }
    defer reader.Close()

    // Get all content information in one call
    details, err := svc.GetContentDetails(ctx, content.ID)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Content: %s (%s)\\n", details.FileName, details.MimeType)
    fmt.Printf("Download URL: %s\\n", details.Download)
}
Manual Construction (Advanced)
// For advanced users who need custom configuration
repo := memory.New()
store := memorystorage.New()

svc, err := simplecontent.New(
    simplecontent.WithRepository(repo),
    simplecontent.WithBlobStore("memory", store),
)

// Cast to StorageService for object operations if needed
storageSvc, ok := svc.(simplecontent.StorageService)
if ok {
    // Use object-level operations
    object, err := storageSvc.CreateObject(ctx, req)
    uploadURL, err := storageSvc.GetUploadURL(ctx, object.ID)
}

Architecture

Core Interfaces
type Service interface {
    // Unified upload operations (NEW!)
    UploadContent(ctx, UploadContentRequest) (*Content, error)
    UploadDerivedContent(ctx, UploadDerivedContentRequest) (*Content, error)

    // Content data access
    DownloadContent(ctx, contentID) (io.ReadCloser, error)

    // Unified details API (NEW!)
    GetContentDetails(ctx, contentID, ...ContentDetailsOption) (*ContentDetails, error)

    // Standard content operations
    CreateContent(ctx, CreateContentRequest) (*Content, error)
    GetContent(ctx, uuid.UUID) (*Content, error)
    ListContent(ctx, ListContentRequest) ([]*Content, error)

    // Derived content operations
    ListDerivedContent(ctx, ...ListDerivedContentOption) ([]*DerivedContent, error)
}
StorageService Interface (Advanced)
type StorageService interface {
    // Object operations (for advanced users who need direct object access)
    CreateObject(ctx, CreateObjectRequest) (*Object, error)
    UploadObject(ctx, UploadObjectRequest) error
    GetUploadURL(ctx, objectID) (string, error)
    // ... other object operations
}
Backend Interfaces
  • Repository: Data persistence abstraction for contents, objects, and metadata
  • BlobStore: Storage backend abstraction for binary data
  • EventSink: Event handling for lifecycle events
  • Previewer: Content preview generation
Available Implementations
Repositories
  • repo/memory: In-memory repository (testing)
  • repo/postgres: PostgreSQL repository (production)
Storage Backends
  • storage/memory: In-memory storage (testing)
  • storage/fs: Filesystem storage
  • storage/s3: S3-compatible storage
Configuration Options

The service supports functional options for configuration:

svc, err := simplecontent.New(
    simplecontent.WithRepository(postgresRepo),
    simplecontent.WithBlobStore("s3-primary", s3Store),
    simplecontent.WithBlobStore("s3-backup", s3BackupStore),
    simplecontent.WithBlobStore("local", fsStore),
    simplecontent.WithEventSink(eventSink),
    simplecontent.WithPreviewer(previewer),
)

Features

  • Unified Content Operations: Single-call upload/download operations replace multi-step workflows
  • Content-Focused API: Work with content concepts, not storage objects
  • Interface Separation: Service interface for most users, StorageService for advanced use cases
  • Pluggable architecture: Swap repositories and storage backends easily
  • Multi-tenant: Built-in tenant isolation
  • Derived Content: Built-in support for thumbnails, previews, and transcodes
  • Metadata management: Rich metadata support with unified details API
  • Event system: Lifecycle event notifications
  • Preview generation: Extensible preview system
  • Error handling: Typed errors for better error handling

Metadata Strategy

The library uses a hybrid metadata approach:

  • First-class fields capture common, structured attributes directly on domain types (e.g., Content.Name, Content.Description, Object.ObjectType, ContentMetadata.FileName, ContentMetadata.MimeType). These fields are authoritative for their respective values.
  • Flexible JSON maps (ContentMetadata.Metadata, ObjectMetadata.Metadata) accommodate extensible, application-specific attributes. Prefer namespaced keys as needed to avoid collisions.
  • Avoid duplicating authoritative values in the JSON map. If mirroring is desired for compatibility, treat first-class fields as the source of truth and ensure the JSON copy is consistent.
  • Standard keys when present in metadata JSON: mime_type, file_name, file_size, etag, plus additional backend-provided attributes. Applications can add custom keys (e.g., category, priority).

Derived Content Typing

  • Derivation type (user-facing): stored on derived Content.DerivationType (e.g., thumbnail, preview, transcode). Omitted for originals.
  • Variant (specific): stored on the content_derived relationship (DB column variant), e.g., thumbnail_256, thumbnail_720, conversion.
  • All keyword values use lowercase to minimize typos and normalization overhead. If only variant is provided when creating derived content, the service infers derivation_type from the variant prefix.
Typed constants

For clarity and IDE hints, typed string constants are provided:

  • Content statuses: simplecontent.ContentStatus with constants like ContentStatusCreated.
  • Object statuses: simplecontent.ObjectStatus with constants like ObjectStatusUploaded.
  • Derivation:
    • Variant: simplecontent.DerivationVariant (e.g., VariantThumbnail256).

Struct fields remain string for compatibility. You can extend by declaring your own typed constants:

const VariantThumbnail1024 simplecontent.DerivationVariant = "thumbnail_1024"

API Migration Guide

Before: Multi-Step Object Workflow
// Old way (3 steps):
content := svc.CreateContent(ctx, createReq)
object := svc.CreateObject(ctx, objectReq)  // StorageService required
err := svc.UploadObject(ctx, uploadReq)     // StorageService required
After: Unified Content Workflow
// New way (1 step):
content, err := svc.UploadContent(ctx, uploadReq)

// For derived content:
thumbnail, err := svc.UploadDerivedContent(ctx, derivedReq)
When to Use Each Interface

Use Service Interface (Recommended) when:

  • Uploading content from server-side applications
  • Working with content concepts (documents, images, videos)
  • Need simplified workflow with minimal complexity
  • Files under 100MB

Use StorageService Interface (Advanced) when:

  • Need direct object access for presigned URLs
  • Implementing presigned client uploads to storage
  • Large files requiring specialized upload patterns
  • Need fine-grained control over storage operations

Use Cases

  • Document management systems
  • Media asset management
  • File storage services
  • Content delivery platforms
  • Multi-tenant SaaS applications
  • Thumbnail and preview generation systems
  • Presigned client upload applications

Testing

The library includes in-memory implementations perfect for testing:

func TestMyFeature(t *testing.T) {
    cfg, err := config.Load(
        config.WithDatabaseType("memory"),
        config.WithStorageBackend("memory", map[string]interface{}{}),
    )
    require.NoError(t, err)

    svc, err := cfg.BuildService()
    require.NoError(t, err)

    // Test unified operations
    content, err := svc.UploadContent(ctx, simplecontent.UploadContentRequest{
        OwnerID:      uuid.New(),
        TenantID:     uuid.New(),
        Name:         "Test Content",
        DocumentType: "text/plain",
        Reader:       strings.NewReader("test data"),
    })
    require.NoError(t, err)

    // Test your code...
}

Documentation

Overview

Package simplecontent provides a reusable library for content and object management with pluggable repository and blob storage backends.

It exposes a single Service interface that orchestrates creation of content and objects, object upload/download, metadata management, and optional event/preview integrations. Implementations of repositories (e.g., memory, Postgres) and blob stores (e.g., memory, filesystem, S3) are provided under subpackages.

Metadata Strategy

First-class fields represent authoritative, common attributes on domain models (e.g., Content.Name, Content.Description, Object.ObjectType). Extensible attributes are stored in JSON maps (ContentMetadata.Metadata, ObjectMetadata.Metadata). Avoid duplicating authoritative values in the JSON maps; if mirroring is needed for compatibility, treat the first-class fields as the source of truth.

Index

Constants

View Source
const (
	ContentDerivationTypeOriginal = "original"
	ContentDerivationTypeDerived  = "derived"
)

Content derivation type constants

Variables

View Source
var (
	// ErrContentNotFound indicates a content was not found
	ErrContentNotFound = errors.New("content not found")

	// ErrObjectNotFound indicates an object was not found
	ErrObjectNotFound = errors.New("object not found")

	// ErrStorageBackendNotFound indicates a storage backend was not found
	ErrStorageBackendNotFound = errors.New("storage backend not found")

	// ErrInvalidContentStatus indicates an invalid content status
	ErrInvalidContentStatus = errors.New("invalid content status")

	// ErrInvalidObjectStatus indicates an invalid object status
	ErrInvalidObjectStatus = errors.New("invalid object status")

	// ErrUploadFailed indicates an upload operation failed
	ErrUploadFailed = errors.New("upload failed")

	// ErrDownloadFailed indicates a download operation failed
	ErrDownloadFailed = errors.New("download failed")

	// ErrContentNotReady indicates content is not in a state ready for download
	ErrContentNotReady = errors.New("content not ready for download")

	// ErrObjectNotReady indicates object is not in a state ready for download
	ErrObjectNotReady = errors.New("object not ready for download")

	// ErrInvalidUploadState indicates content/object cannot be uploaded in its current state
	ErrInvalidUploadState = errors.New("invalid state for upload operation")

	// ErrParentNotReady indicates parent content is not ready for creating derived content
	ErrParentNotReady = errors.New("parent content not ready for derivation")

	// ErrContentBeingProcessed indicates operation cannot proceed while content is being processed
	ErrContentBeingProcessed = errors.New("content is being processed")

	// ErrMaxDerivationDepth indicates maximum derivation depth has been exceeded
	ErrMaxDerivationDepth = errors.New("maximum derivation depth exceeded")

	// ErrNoStorageBackend indicates no storage backend is available
	ErrNoStorageBackend = errors.New("no storage backend available")

	// ErrNoObjectsFound indicates no objects were found for the content
	ErrNoObjectsFound = errors.New("no objects found for content")

	// ErrNoUploadedObjects indicates no uploaded objects were found
	ErrNoUploadedObjects = errors.New("no uploaded objects found")
)

Error types

Functions

func CountDerivedContent added in v0.1.9

func CountDerivedContent(ctx context.Context, svc Service, params ListDerivedContentParams) (int64, error)

CountDerivedContent counts derived content matching the given parameters. This is a convenience function that uses the service's ListDerivedContent method. Deprecated: Use svc.ListDerivedContent with appropriate options instead.

func DerivationTypeFromVariant added in v0.1.1

func DerivationTypeFromVariant(variant string) string

DerivationTypeFromVariant infers a derivation type from a variant by taking the prefix before the first underscore. If no underscore exists, the entire variant string is returned.

func NormalizeDerivationType added in v0.1.1

func NormalizeDerivationType(s string) string

NormalizeDerivationType lowercases a user-facing derivation type.

func ToErrorMessage added in v0.2.2

func ToErrorMessage(err error) string

ToErrorMessage converts an error to a caller-friendly message with technical details

func UploadObjectSimple added in v0.1.9

func UploadObjectSimple(ctx context.Context, svc StorageService, objectID uuid.UUID, reader io.Reader) error

UploadObjectSimple uploads an object without metadata (backward compatibility). Deprecated: Use the unified UploadContent or UploadDerivedContent instead. This function now requires a StorageService interface for object operations.

func UploadObjectWithMimeType added in v0.1.9

func UploadObjectWithMimeType(ctx context.Context, svc StorageService, objectID uuid.UUID, reader io.Reader, mimeType string) error

UploadObjectWithMimeType uploads an object with a specific MIME type. Deprecated: Use the unified UploadContent or UploadDerivedContent instead. This function now requires a StorageService interface for object operations.

Types

type AfterContentCreateHook added in v0.2.1

type AfterContentCreateHook func(hctx *HookContext, content *Content) error

AfterContentCreateHook is called after content is created

type AfterContentDeleteHook added in v0.2.1

type AfterContentDeleteHook func(hctx *HookContext, contentID uuid.UUID) error

AfterContentDeleteHook is called after content is deleted

type AfterContentDownloadHook added in v0.2.1

type AfterContentDownloadHook func(hctx *HookContext, contentID uuid.UUID, reader io.ReadCloser) (io.ReadCloser, error)

AfterContentDownloadHook is called after content is downloaded

type AfterContentUploadHook added in v0.2.1

type AfterContentUploadHook func(hctx *HookContext, contentID uuid.UUID, bytesWritten int64) error

AfterContentUploadHook is called after content data is uploaded

type AfterDerivedCreateHook added in v0.2.1

type AfterDerivedCreateHook func(hctx *HookContext, parent *Content, derived *Content) error

AfterDerivedCreateHook is called after derived content is created

type AfterMetadataSetHook added in v0.2.1

type AfterMetadataSetHook func(hctx *HookContext, metadata *ContentMetadata) error

AfterMetadataSetHook is called after metadata is set

type BasicImagePreviewer

type BasicImagePreviewer struct {
	// contains filtered or unexported fields
}

BasicImagePreviewer is a simple previewer that generates preview URLs for common image types

func (*BasicImagePreviewer) GeneratePreview

func (b *BasicImagePreviewer) GeneratePreview(ctx context.Context, object *Object, blobStore BlobStore) (*ObjectPreview, error)

GeneratePreview generates a preview for supported image types

func (*BasicImagePreviewer) SupportsContent

func (b *BasicImagePreviewer) SupportsContent(mimeType string) bool

SupportsContent returns true if the MIME type is a supported image type

type BeforeContentCreateHook added in v0.2.1

type BeforeContentCreateHook func(hctx *HookContext, req *CreateContentRequest) error

BeforeContentCreateHook is called before creating content

func ValidationHook added in v0.2.1

func ValidationHook(validator func(*CreateContentRequest) error) BeforeContentCreateHook

ValidationHook adds custom validation

type BeforeContentDeleteHook added in v0.2.1

type BeforeContentDeleteHook func(hctx *HookContext, contentID uuid.UUID) error

BeforeContentDeleteHook is called before deleting content

type BeforeContentDownloadHook added in v0.2.1

type BeforeContentDownloadHook func(hctx *HookContext, contentID uuid.UUID) error

BeforeContentDownloadHook is called before downloading content

type BeforeContentUploadHook added in v0.2.1

type BeforeContentUploadHook func(hctx *HookContext, contentID uuid.UUID, reader io.Reader) (io.Reader, error)

BeforeContentUploadHook is called before uploading content data

type BeforeDerivedCreateHook added in v0.2.1

type BeforeDerivedCreateHook func(hctx *HookContext, req *CreateDerivedContentRequest) error

BeforeDerivedCreateHook is called before creating derived content

type BeforeMetadataSetHook added in v0.2.1

type BeforeMetadataSetHook func(hctx *HookContext, req *SetContentMetadataRequest) error

BeforeMetadataSetHook is called before setting metadata

type BlobStore

type BlobStore interface {
	// GetUploadURL returns a URL for uploading content
	GetUploadURL(ctx context.Context, objectKey string) (string, error)

	// Upload uploads content directly
	Upload(ctx context.Context, objectKey string, reader io.Reader) error

	// UploadWithParams uploads content with additional parameters
	UploadWithParams(ctx context.Context, reader io.Reader, params UploadParams) error

	// GetDownloadURL returns a URL for downloading content
	GetDownloadURL(ctx context.Context, objectKey string, downloadFilename string) (string, error)

	// GetPreviewURL returns a URL for previewing content
	GetPreviewURL(ctx context.Context, objectKey string) (string, error)

	// Download downloads content directly
	Download(ctx context.Context, objectKey string) (io.ReadCloser, error)

	// Delete deletes content
	Delete(ctx context.Context, objectKey string) error

	// GetObjectMeta retrieves metadata for an object
	GetObjectMeta(ctx context.Context, objectKey string) (*ObjectMeta, error)
}

BlobStore defines the interface for storage backends

type Content

type Content struct {
	ID             uuid.UUID  `json:"id"`
	TenantID       uuid.UUID  `json:"tenant_id"`
	OwnerID        uuid.UUID  `json:"owner_id"`
	OwnerType      string     `json:"owner_type,omitempty"`
	Name           string     `json:"name,omitempty"`
	Description    string     `json:"description,omitempty"`
	DocumentType   string     `json:"document_type,omitempty"`
	Status         string     `json:"status"`
	DerivationType string     `json:"derivation_type,omitempty"`
	CreatedAt      time.Time  `json:"created_at"`
	UpdatedAt      time.Time  `json:"updated_at"`
	DeletedAt      *time.Time `json:"deleted_at,omitempty"`
}

Content represents a logical content entity.

For derived content, the DerivationType field holds the user-facing derivation type (e.g., "thumbnail", "preview"). Specific variant (e.g., "thumbnail_256") is tracked in the derived-content relationship.

type ContentCountFilters added in v0.1.15

type ContentCountFilters struct {
	TenantID        *uuid.UUID
	TenantIDs       []uuid.UUID
	OwnerID         *uuid.UUID
	OwnerIDs        []uuid.UUID
	Status          *string
	Statuses        []string
	DerivationType  *string
	DerivationTypes []string
	DocumentType    *string
	DocumentTypes   []string
	CreatedAfter    *time.Time
	CreatedBefore   *time.Time
	UpdatedAfter    *time.Time
	UpdatedBefore   *time.Time
	IncludeDeleted  bool
}

ContentCountFilters defines filtering options for counting content

type ContentDetails added in v0.1.11

type ContentDetails struct {
	ID string `json:"id"` // Content ID

	// Access URLs
	Download   string            `json:"download,omitempty"`   // Primary download URL
	Upload     string            `json:"upload,omitempty"`     // Upload URL (when WithUploadAccess option used)
	Preview    string            `json:"preview,omitempty"`    // Primary preview URL
	Thumbnail  string            `json:"thumbnail,omitempty"`  // Primary thumbnail URL
	Thumbnails map[string]string `json:"thumbnails,omitempty"` // size -> URL (256, 512, etc.)
	Previews   map[string]string `json:"previews,omitempty"`   // variant -> URL (720p, 1080p, webm, etc.)
	Transcodes map[string]string `json:"transcodes,omitempty"` // format -> URL (mp3, flac, mp4, etc.)

	// File metadata
	FileName string   `json:"file_name,omitempty"` // Original file name
	FileSize int64    `json:"file_size,omitempty"` // File size in bytes
	MimeType string   `json:"mime_type,omitempty"` // MIME type
	Tags     []string `json:"tags,omitempty"`      // Content tags
	Checksum string   `json:"checksum,omitempty"`  // File checksum

	// Status and timing
	Ready     bool       `json:"ready"`                // True when parent is uploaded AND all derived content status is uploaded/processed (Object semantics)
	ExpiresAt *time.Time `json:"expires_at,omitempty"` // When URLs expire (for presigned URLs)
	CreatedAt time.Time  `json:"created_at"`           // Content creation time
	UpdatedAt time.Time  `json:"updated_at"`           // Content last update time
}

ContentDetails represents all details for a content including URLs and metadata. This unified type provides everything clients need in a single call.

func GetContentDetails added in v0.1.11

func GetContentDetails(ctx context.Context, svc Service, contentID uuid.UUID) (*ContentDetails, error)

GetContentDetails returns all details for content in the simplest possible interface. This is the recommended way for clients to get all details for any content.

type ContentDetailsConfig added in v0.1.11

type ContentDetailsConfig struct {
	IncludeUploadURL bool
	URLExpiryTime    int // Seconds
}

ContentDetailsConfig holds configuration for content details retrieval

type ContentDetailsOption added in v0.1.11

type ContentDetailsOption func(*ContentDetailsConfig)

ContentDetailsOption provides configuration for GetContentDetails calls

func WithUploadAccess added in v0.1.11

func WithUploadAccess() ContentDetailsOption

WithUploadAccess configures GetContentDetails to include upload URLs for content that needs data

func WithUploadAccessExpiry added in v0.1.11

func WithUploadAccessExpiry(expirySeconds int) ContentDetailsOption

WithUploadAccessExpiry configures GetContentDetails to include upload URLs with custom expiry

type ContentError

type ContentError struct {
	ContentID uuid.UUID
	Op        string
	Err       error
}

ContentError represents an error related to content operations

func (*ContentError) Error

func (e *ContentError) Error() string

func (*ContentError) ErrorMessage added in v0.2.2

func (e *ContentError) ErrorMessage() string

ErrorMessage returns a caller-friendly error message with technical details

func (*ContentError) HTTPStatus added in v0.2.2

func (e *ContentError) HTTPStatus() int

HTTPStatus returns the appropriate HTTP status code for this error

func (*ContentError) Unwrap

func (e *ContentError) Unwrap() error

type ContentListFilters added in v0.1.15

type ContentListFilters struct {
	TenantID        *uuid.UUID
	TenantIDs       []uuid.UUID
	OwnerID         *uuid.UUID
	OwnerIDs        []uuid.UUID
	Status          *string
	Statuses        []string
	DerivationType  *string
	DerivationTypes []string
	DocumentType    *string
	DocumentTypes   []string
	CreatedAfter    *time.Time
	CreatedBefore   *time.Time
	UpdatedAfter    *time.Time
	UpdatedBefore   *time.Time
	Limit           *int
	Offset          *int
	SortBy          *string
	SortOrder       *string
	IncludeDeleted  bool
}

ContentListFilters defines filtering options for listing content (admin operations)

type ContentMetadata

type ContentMetadata struct {
	ContentID         uuid.UUID              `json:"content_id"`
	Tags              []string               `json:"tags,omitempty"`
	FileSize          int64                  `json:"file_size,omitempty"`
	FileName          string                 `json:"file_name,omitempty"`
	MimeType          string                 `json:"mime_type"`
	Checksum          string                 `json:"checksum,omitempty"`
	ChecksumAlgorithm string                 `json:"checksum_algorithm,omitempty"`
	Metadata          map[string]interface{} `json:"metadata"`
	CreatedAt         time.Time              `json:"created_at"`
	UpdatedAt         time.Time              `json:"updated_at"`
}

ContentMetadata represents metadata for a content

type ContentStatisticsOptions added in v0.1.15

type ContentStatisticsOptions struct {
	IncludeStatusBreakdown       bool
	IncludeTenantBreakdown       bool
	IncludeDerivationBreakdown   bool
	IncludeDocumentTypeBreakdown bool
	IncludeTimeRange             bool
}

ContentStatisticsOptions defines what statistics to include

type ContentStatisticsResult added in v0.1.15

type ContentStatisticsResult struct {
	TotalCount       int64
	ByStatus         map[string]int64
	ByTenant         map[string]int64
	ByDerivationType map[string]int64
	ByDocumentType   map[string]int64
	OldestContent    *time.Time
	NewestContent    *time.Time
}

ContentStatisticsResult contains aggregated statistics about content

type ContentStatus added in v0.1.1

type ContentStatus string

ContentStatus is the domain type for content lifecycle states.

const (
	ContentStatusCreated    ContentStatus = "created"    // Content record created, no data uploaded yet
	ContentStatusUploading  ContentStatus = "uploading"  // Upload in progress (optional intermediate state)
	ContentStatusUploaded   ContentStatus = "uploaded"   // ORIGINAL content: binary uploaded to storage (terminal state for originals)
	ContentStatusProcessing ContentStatus = "processing" // Reserved for future async processing workflows
	ContentStatusProcessed  ContentStatus = "processed"  // DERIVED content: generated output ready to serve (terminal state for derivatives)
	ContentStatusFailed     ContentStatus = "failed"     // Upload or processing failed, may need retry
	ContentStatusArchived   ContentStatus = "archived"   // Content archived for long-term storage (future use)

	// Deprecated: Soft delete is indicated by the deleted_at timestamp, not the status field.
	// This constant remains for backward compatibility with existing data.
	// New code should NOT set status to 'deleted' - only set the deleted_at timestamp.
	// The status field should remain at the last operational state (e.g., "uploaded", "processed").
	// This constant will be removed in v2.0.
	ContentStatusDeleted ContentStatus = "deleted"
)

Content status constants (typed).

func ParseContentStatus added in v0.1.19

func ParseContentStatus(s string) (ContentStatus, error)

ParseContentStatus parses a string into a ContentStatus with validation. Returns an error if the status string is not a valid ContentStatus.

func (ContentStatus) IsValid added in v0.1.19

func (s ContentStatus) IsValid() bool

IsValid checks if the ContentStatus is a valid known status.

type CreateContentRequest

type CreateContentRequest struct {
	OwnerID        uuid.UUID
	OwnerType      string
	TenantID       uuid.UUID
	Name           string
	Description    string
	DocumentType   string
	DerivationType string
}

CreateContentRequest contains parameters for creating new content

type CreateDerivedContentParams

type CreateDerivedContentParams struct {
	ParentID           uuid.UUID
	DerivedContentID   uuid.UUID
	DerivationType     string
	Variant            string // NEW: Specific variant (e.g., "thumbnail_256")
	DerivationParams   map[string]interface{}
	ProcessingMetadata map[string]interface{}
}

CreateDerivedContentParams contains parameters for creating derived content relationships

type CreateDerivedContentRequest

type CreateDerivedContentRequest struct {
	ParentID       uuid.UUID
	OwnerID        uuid.UUID
	TenantID       uuid.UUID
	DerivationType string
	Variant        string
	Metadata       map[string]interface{}
	InitialStatus  ContentStatus // Optional: defaults to "created"
	OwnerType      string
	Name           string
	FileName       string
}

CreateDerivedContentRequest contains parameters for creating derived content.

DerivationType is the user-facing derivation type stored on the derived Content (e.g., "thumbnail", "preview", "transcode"). Variant is the specific derivation (e.g., "thumbnail_256"). If Variant is provided and DerivationType is empty, the service infers DerivationType from the prefix before the first underscore in Variant.

InitialStatus allows setting a custom initial status for async workflows. If not provided, defaults to "created". Common values:

  • "created" (default): Content placeholder created, waiting for processing
  • "processing": Immediately mark as being processed (useful for queue consumers)

type CreateObjectRequest

type CreateObjectRequest struct {
	ContentID          uuid.UUID
	StorageBackendName string
	Version            int
	ObjectKey          string
	FileName           string
}

CreateObjectRequest contains parameters for creating an object

type DerivationVariant added in v0.1.1

type DerivationVariant string

DerivationVariant is the specific variant within a category (e.g., "thumbnail_256").

const (
	VariantThumbnail720 DerivationVariant = "thumbnail_720"
	VariantThumbnail480 DerivationVariant = "thumbnail_480"
	VariantThumbnail256 DerivationVariant = "thumbnail_256"
	VariantThumbnail128 DerivationVariant = "thumbnail_128"
	VariantConversion   DerivationVariant = "conversion"
)

Derivation variant constants (typed).

func NormalizeVariant added in v0.1.1

func NormalizeVariant(s string) DerivationVariant

NormalizeVariant lowercases a specific derivation variant.

type DerivedContent

type DerivedContent struct {
	// Persisted fields
	ParentID           uuid.UUID              `json:"parent_id" db:"parent_id"`
	ContentID          uuid.UUID              `json:"content_id" db:"content_id"`
	DerivationType     string                 `json:"derivation_type" db:"derivation_type"`
	Variant            string                 `json:"variant" db:"variant"` // Specific variant (persisted)
	DerivationParams   map[string]interface{} `json:"derivation_params" db:"derivation_params"`
	ProcessingMetadata map[string]interface{} `json:"processing_metadata" db:"processing_metadata"`
	CreatedAt          time.Time              `json:"created_at" db:"created_at"`
	UpdatedAt          time.Time              `json:"updated_at" db:"updated_at"`
	DocumentType       string                 `json:"document_type" db:"document_type"`

	// Computed fields (not persisted - populated from JOINs or service layer)
	Status       string `json:"status,omitempty" db:"-"` // Populated from content.status via JOIN
	DownloadURL  string `json:"download_url,omitempty" db:"-"`
	PreviewURL   string `json:"preview_url,omitempty" db:"-"`
	ThumbnailURL string `json:"thumbnail_url,omitempty" db:"-"`

	// Optional enhanced data (not persisted - populated on demand)
	Objects       []*Object        `json:"objects,omitempty" db:"-"`
	Metadata      *ContentMetadata `json:"metadata,omitempty" db:"-"`
	ParentContent *Content         `json:"parent_content,omitempty" db:"-"`
}

DerivedContent represents content derived from a parent content. DerivationType here represents the category (e.g., "thumbnail", "preview"). Variant represents the specific variant (e.g., "thumbnail_256").

Status Field: Uses Object status semantics (not Content status semantics) to track granular processing states: created, uploading, uploaded, processing, processed, failed. This allows distinguishing between "uploaded" and "ready to serve" for derived content.

func GetDerivedContentWithURLs added in v0.1.9

func GetDerivedContentWithURLs(ctx context.Context, svc Service, contentID uuid.UUID) (*DerivedContent, error)

GetDerivedContentWithURLs retrieves a single derived content with URLs populated. This is a convenience function that uses the service's GetDerivedRelationship method.

func GetRecentDerived added in v0.1.9

func GetRecentDerived(ctx context.Context, svc Service, parentID uuid.UUID, since time.Time) ([]*DerivedContent, error)

GetRecentDerived retrieves derived content created after a specific time. This is a convenience function that uses the service's ListDerivedContent method.

func GetThumbnailsBySize added in v0.1.9

func GetThumbnailsBySize(ctx context.Context, svc Service, parentID uuid.UUID, sizes []string) ([]*DerivedContent, error)

GetThumbnailsBySize retrieves thumbnails of specific sizes for a parent content. This is a convenience function that uses the service's ListDerivedContent method.

func ListDerivedByTypeAndVariant added in v0.1.9

func ListDerivedByTypeAndVariant(ctx context.Context, svc Service, parentID uuid.UUID, derivationType, variant string) ([]*DerivedContent, error)

ListDerivedByTypeAndVariant retrieves derived content by specific type and variant. This is a convenience function that uses the service's ListDerivedContent method.

func ListDerivedByVariants added in v0.1.9

func ListDerivedByVariants(ctx context.Context, svc Service, parentID uuid.UUID, variants []string) ([]*DerivedContent, error)

ListDerivedByVariants retrieves derived content by specific variants. This is a convenience function that uses the service's ListDerivedContent method.

func ListDerivedContentWithURLs added in v0.1.9

func ListDerivedContentWithURLs(ctx context.Context, svc Service, params ListDerivedContentParams) ([]*DerivedContent, error)

ListDerivedContentWithURLs retrieves derived content with URLs populated. This is a convenience function that uses the service's ListDerivedContent method. Deprecated: Use svc.ListDerivedContent with WithURLs() option instead.

type ErrorHook added in v0.2.1

type ErrorHook func(hctx *HookContext, operation string, err error)

ErrorHook is called when an error occurs

type EventSink

type EventSink interface {
	// ContentCreated is fired when content is created
	ContentCreated(ctx context.Context, content *Content) error

	// ContentUpdated is fired when content is updated
	ContentUpdated(ctx context.Context, content *Content) error

	// ContentDeleted is fired when content is deleted
	ContentDeleted(ctx context.Context, contentID uuid.UUID) error

	// ObjectCreated is fired when an object is created
	ObjectCreated(ctx context.Context, object *Object) error

	// ObjectUploaded is fired when an object is uploaded
	ObjectUploaded(ctx context.Context, object *Object) error

	// ObjectDeleted is fired when an object is deleted
	ObjectDeleted(ctx context.Context, objectID uuid.UUID) error

	// ContentStatusChanged is fired when content status changes
	ContentStatusChanged(ctx context.Context, contentID uuid.UUID, oldStatus, newStatus string) error

	// ObjectStatusChanged is fired when object status changes
	ObjectStatusChanged(ctx context.Context, objectID uuid.UUID, oldStatus, newStatus string) error
}

EventSink defines the interface for event handling

func NewLoggingEventSink

func NewLoggingEventSink(logger Logger) EventSink

NewLoggingEventSink creates a new logging event sink

func NewNoopEventSink

func NewNoopEventSink() EventSink

NewNoopEventSink creates a new no-operation event sink

type HookContext added in v0.2.1

type HookContext struct {
	Context   context.Context
	Metadata  map[string]interface{} // Custom metadata passed between hooks
	StopChain bool                   // Set to true to stop processing remaining hooks
}

Hook context carries information through the hook chain

func NewHookContext added in v0.2.1

func NewHookContext(ctx context.Context) *HookContext

NewHookContext creates a new hook context

type Hooks added in v0.2.1

type Hooks struct {
	// Content lifecycle hooks
	BeforeContentCreate   []BeforeContentCreateHook
	AfterContentCreate    []AfterContentCreateHook
	BeforeContentUpload   []BeforeContentUploadHook
	AfterContentUpload    []AfterContentUploadHook
	BeforeContentDownload []BeforeContentDownloadHook
	AfterContentDownload  []AfterContentDownloadHook
	BeforeContentDelete   []BeforeContentDeleteHook
	AfterContentDelete    []AfterContentDeleteHook

	// Derived content hooks
	BeforeDerivedCreate []BeforeDerivedCreateHook
	AfterDerivedCreate  []AfterDerivedCreateHook

	// Metadata hooks
	BeforeMetadataSet []BeforeMetadataSetHook
	AfterMetadataSet  []AfterMetadataSetHook

	// Status change hooks
	OnStatusChange []StatusChangeHook

	// Error hooks
	OnError []ErrorHook
}

Hooks defines all available lifecycle hooks

func LoggingHook added in v0.2.1

func LoggingHook(logger func(format string, args ...interface{})) *Hooks

LoggingHook logs all operations

func MetricsHook added in v0.2.1

func MetricsHook(metrics interface {
	IncrementCounter(name string)
	RecordDuration(name string, duration int64)
}) *Hooks

MetricsHook tracks metrics

type ListContentRequest

type ListContentRequest struct {
	OwnerID  uuid.UUID
	TenantID uuid.UUID
}

ListContentRequest contains parameters for listing content

type ListDerivedContentOption added in v0.1.9

type ListDerivedContentOption func(*ListDerivedContentParams)

ListDerivedContentOption represents a functional option for listing derived content

func WithContentStatus added in v0.1.9

func WithContentStatus(status string) ListDerivedContentOption

WithContentStatus sets the content status to filter by

func WithCreatedAfter added in v0.1.9

func WithCreatedAfter(t time.Time) ListDerivedContentOption

WithCreatedAfter sets the created after time filter

func WithCreatedBefore added in v0.1.9

func WithCreatedBefore(t time.Time) ListDerivedContentOption

WithCreatedBefore sets the created before time filter

func WithDerivationType added in v0.1.9

func WithDerivationType(derivationType string) ListDerivedContentOption

WithDerivationType sets the derivation type to filter by

func WithDerivationTypes added in v0.1.9

func WithDerivationTypes(derivationTypes ...string) ListDerivedContentOption

WithDerivationTypes sets multiple derivation types to filter by

func WithLimit added in v0.1.9

func WithLimit(limit int) ListDerivedContentOption

WithLimit sets the maximum number of results

func WithMetadata added in v0.1.9

func WithMetadata() ListDerivedContentOption

WithMetadata includes metadata in the response

func WithObjects added in v0.1.9

func WithObjects() ListDerivedContentOption

WithObjects includes object details in the response

func WithOffset added in v0.1.9

func WithOffset(offset int) ListDerivedContentOption

WithOffset sets the offset for pagination

func WithPagination added in v0.1.9

func WithPagination(limit, offset int) ListDerivedContentOption

WithPagination sets both limit and offset for pagination

func WithParentID added in v0.1.9

func WithParentID(parentID uuid.UUID) ListDerivedContentOption

WithParentID sets the parent ID to filter by

func WithParentIDs added in v0.1.9

func WithParentIDs(parentIDs ...uuid.UUID) ListDerivedContentOption

WithParentIDs sets multiple parent IDs to filter by

func WithSortBy added in v0.1.9

func WithSortBy(sortBy string) ListDerivedContentOption

WithSortBy sets the sort field and order

func WithTypeVariantPairs added in v0.1.9

func WithTypeVariantPairs(pairs ...TypeVariantPair) ListDerivedContentOption

WithTypeVariantPairs sets type-variant pairs to filter by

func WithURLs added in v0.1.9

func WithURLs() ListDerivedContentOption

WithURLs includes URLs in the response (DownloadURL, PreviewURL, ThumbnailURL)

func WithVariant added in v0.1.9

func WithVariant(variant string) ListDerivedContentOption

WithVariant sets the variant to filter by

func WithVariants added in v0.1.9

func WithVariants(variants ...string) ListDerivedContentOption

WithVariants sets multiple variants to filter by

type ListDerivedContentParams

type ListDerivedContentParams struct {
	// Existing fields (no breaking changes)
	ParentID       *uuid.UUID `json:"parent_id,omitempty"`
	DerivationType *string    `json:"derivation_type,omitempty"`
	Limit          *int       `json:"limit,omitempty"`
	Offset         *int       `json:"offset,omitempty"`

	// NEW: Advanced filtering fields
	ParentIDs        []uuid.UUID       `json:"parent_ids,omitempty"`
	DerivationTypes  []string          `json:"derivation_types,omitempty"`
	Variant          *string           `json:"variant,omitempty"`
	Variants         []string          `json:"variants,omitempty"`
	TypeVariantPairs []TypeVariantPair `json:"type_variant_pairs,omitempty"`
	ContentStatus    *string           `json:"content_status,omitempty"`
	CreatedAfter     *time.Time        `json:"created_after,omitempty"`
	CreatedBefore    *time.Time        `json:"created_before,omitempty"`
	SortBy           *string           `json:"sort_by,omitempty"`

	// NEW: URL and metadata inclusion options
	IncludeURLs     bool `json:"include_urls"`
	IncludeObjects  bool `json:"include_objects"`
	IncludeMetadata bool `json:"include_metadata"`
}

ListDerivedContentParams contains parameters for listing derived content

type Logger

type Logger interface {
	Infof(format string, args ...interface{})
	Errorf(format string, args ...interface{})
}

Logger interface for logging events

type LoggingEventSink

type LoggingEventSink struct {
	// contains filtered or unexported fields
}

LoggingEventSink is an event sink that logs events but takes no other action Useful for development and debugging

func (*LoggingEventSink) ContentCreated

func (l *LoggingEventSink) ContentCreated(ctx context.Context, content *Content) error

ContentCreated logs the content creation event

func (*LoggingEventSink) ContentDeleted

func (l *LoggingEventSink) ContentDeleted(ctx context.Context, contentID uuid.UUID) error

ContentDeleted logs the content deletion event

func (*LoggingEventSink) ContentStatusChanged added in v0.1.19

func (l *LoggingEventSink) ContentStatusChanged(ctx context.Context, contentID uuid.UUID, oldStatus, newStatus string) error

ContentStatusChanged logs the content status change event

func (*LoggingEventSink) ContentUpdated

func (l *LoggingEventSink) ContentUpdated(ctx context.Context, content *Content) error

ContentUpdated logs the content update event

func (*LoggingEventSink) ObjectCreated

func (l *LoggingEventSink) ObjectCreated(ctx context.Context, object *Object) error

ObjectCreated logs the object creation event

func (*LoggingEventSink) ObjectDeleted

func (l *LoggingEventSink) ObjectDeleted(ctx context.Context, objectID uuid.UUID) error

ObjectDeleted logs the object deletion event

func (*LoggingEventSink) ObjectStatusChanged added in v0.1.19

func (l *LoggingEventSink) ObjectStatusChanged(ctx context.Context, objectID uuid.UUID, oldStatus, newStatus string) error

ObjectStatusChanged logs the object status change event

func (*LoggingEventSink) ObjectUploaded

func (l *LoggingEventSink) ObjectUploaded(ctx context.Context, object *Object) error

ObjectUploaded logs the object upload event

type NoopEventSink

type NoopEventSink struct{}

NoopEventSink is a no-operation implementation of EventSink Useful for production when you don't need event handling or for testing

func (*NoopEventSink) ContentCreated

func (n *NoopEventSink) ContentCreated(ctx context.Context, content *Content) error

ContentCreated does nothing and returns nil

func (*NoopEventSink) ContentDeleted

func (n *NoopEventSink) ContentDeleted(ctx context.Context, contentID uuid.UUID) error

ContentDeleted does nothing and returns nil

func (*NoopEventSink) ContentStatusChanged added in v0.1.19

func (n *NoopEventSink) ContentStatusChanged(ctx context.Context, contentID uuid.UUID, oldStatus, newStatus string) error

ContentStatusChanged does nothing and returns nil

func (*NoopEventSink) ContentUpdated

func (n *NoopEventSink) ContentUpdated(ctx context.Context, content *Content) error

ContentUpdated does nothing and returns nil

func (*NoopEventSink) ObjectCreated

func (n *NoopEventSink) ObjectCreated(ctx context.Context, object *Object) error

ObjectCreated does nothing and returns nil

func (*NoopEventSink) ObjectDeleted

func (n *NoopEventSink) ObjectDeleted(ctx context.Context, objectID uuid.UUID) error

ObjectDeleted does nothing and returns nil

func (*NoopEventSink) ObjectStatusChanged added in v0.1.19

func (n *NoopEventSink) ObjectStatusChanged(ctx context.Context, objectID uuid.UUID, oldStatus, newStatus string) error

ObjectStatusChanged does nothing and returns nil

func (*NoopEventSink) ObjectUploaded

func (n *NoopEventSink) ObjectUploaded(ctx context.Context, object *Object) error

ObjectUploaded does nothing and returns nil

type NoopPreviewer

type NoopPreviewer struct{}

NoopPreviewer is a no-operation implementation of Previewer Always returns nil (no preview generated) and supports no content types

func (*NoopPreviewer) GeneratePreview

func (n *NoopPreviewer) GeneratePreview(ctx context.Context, object *Object, blobStore BlobStore) (*ObjectPreview, error)

GeneratePreview always returns nil (no preview generated)

func (*NoopPreviewer) SupportsContent

func (n *NoopPreviewer) SupportsContent(mimeType string) bool

SupportsContent always returns false (supports no content types)

type Object

type Object struct {
	ID                 uuid.UUID  `json:"id"`
	ContentID          uuid.UUID  `json:"content_id"`
	StorageBackendName string     `json:"storage_backend_name"`
	StorageClass       string     `json:"storage_class,omitempty"`
	ObjectKey          string     `json:"object_key"`
	FileName           string     `json:"file_name,omitempty"`
	Version            int        `json:"version"`
	ObjectType         string     `json:"object_type,omitempty"`
	Status             string     `json:"status"`
	CreatedAt          time.Time  `json:"created_at"`
	UpdatedAt          time.Time  `json:"updated_at"`
	DeletedAt          *time.Time `json:"deleted_at,omitempty"`
}

Object represents a physical object stored in a storage backend

type ObjectError

type ObjectError struct {
	ObjectID uuid.UUID
	Op       string
	Err      error
}

ObjectError represents an error related to object operations

func (*ObjectError) Error

func (e *ObjectError) Error() string

func (*ObjectError) ErrorMessage added in v0.2.2

func (e *ObjectError) ErrorMessage() string

ErrorMessage returns a caller-friendly error message with technical details

func (*ObjectError) HTTPStatus added in v0.2.2

func (e *ObjectError) HTTPStatus() int

HTTPStatus returns the appropriate HTTP status code for this error

func (*ObjectError) Unwrap

func (e *ObjectError) Unwrap() error

type ObjectMeta

type ObjectMeta struct {
	Key         string
	Size        int64
	ContentType string
	UpdatedAt   time.Time
	ETag        string
	Metadata    map[string]string
}

ObjectMeta contains metadata about an object in storage

type ObjectMetadata

type ObjectMetadata struct {
	ObjectID  uuid.UUID              `json:"object_id"`
	SizeBytes int64                  `json:"size_bytes"`
	MimeType  string                 `json:"mime_type"`
	ETag      string                 `json:"etag,omitempty"`
	Metadata  map[string]interface{} `json:"metadata"`
	CreatedAt time.Time              `json:"created_at"`
	UpdatedAt time.Time              `json:"updated_at"`
}

ObjectMetadata represents metadata about an object

type ObjectPreview

type ObjectPreview struct {
	ID          uuid.UUID `json:"id"`
	ObjectID    uuid.UUID `json:"object_id"`
	PreviewType string    `json:"preview_type"`
	Status      string    `json:"status"`
	PreviewURL  string    `json:"preview_url"`
	CreatedAt   time.Time `json:"created_at"`
}

ObjectPreview represents a preview generated from an object

type ObjectStatus added in v0.1.1

type ObjectStatus string

ObjectStatus is the domain type for object lifecycle states.

const (
	ObjectStatusCreated    ObjectStatus = "created"
	ObjectStatusUploading  ObjectStatus = "uploading"
	ObjectStatusUploaded   ObjectStatus = "uploaded"
	ObjectStatusProcessing ObjectStatus = "processing"
	ObjectStatusProcessed  ObjectStatus = "processed"
	ObjectStatusFailed     ObjectStatus = "failed"

	// Deprecated: Soft delete is indicated by the deleted_at timestamp, not the status field.
	// This constant remains for backward compatibility with existing data.
	// New code should NOT set status to 'deleted' - only set the deleted_at timestamp.
	// The status field should remain at the last operational state (e.g., "uploaded", "processed").
	// This constant will be removed in v2.0.
	ObjectStatusDeleted ObjectStatus = "deleted"
)

Object status constants (typed).

func ParseObjectStatus added in v0.1.19

func ParseObjectStatus(s string) (ObjectStatus, error)

ParseObjectStatus parses a string into an ObjectStatus with validation. Returns an error if the status string is not a valid ObjectStatus.

func (ObjectStatus) IsValid added in v0.1.19

func (s ObjectStatus) IsValid() bool

IsValid checks if the ObjectStatus is a valid known status.

type Option

type Option func(*service)

Option represents a functional option for configuring the service

func WithBlobStore

func WithBlobStore(name string, store BlobStore) Option

WithBlobStore adds a blob storage backend

func WithEventSink

func WithEventSink(sink EventSink) Option

WithEventSink sets the event sink for the service

func WithObjectKeyGenerator added in v0.1.12

func WithObjectKeyGenerator(generator objectkey.Generator) Option

WithObjectKeyGenerator sets the object key generator for the service

func WithPreviewer

func WithPreviewer(previewer Previewer) Option

WithPreviewer sets the previewer for the service

func WithRepository

func WithRepository(repo Repository) Option

WithRepository sets the repository for the service

func WithURLStrategy added in v0.1.13

func WithURLStrategy(strategy urlstrategy.URLStrategy) Option

WithURLStrategy sets the URL generation strategy for the service

type Previewer

type Previewer interface {
	// GeneratePreview generates a preview for the given object
	GeneratePreview(ctx context.Context, object *Object, blobStore BlobStore) (*ObjectPreview, error)

	// SupportsContent returns true if the previewer supports the given content type
	SupportsContent(mimeType string) bool
}

Previewer defines the interface for content preview generation

func NewBasicImagePreviewer

func NewBasicImagePreviewer() Previewer

NewBasicImagePreviewer creates a new basic image previewer

func NewNoopPreviewer

func NewNoopPreviewer() Previewer

NewNoopPreviewer creates a new no-operation previewer

type Repository

type Repository interface {
	// Content operations
	CreateContent(ctx context.Context, content *Content) error
	GetContent(ctx context.Context, id uuid.UUID) (*Content, error)
	GetContentsByIDs(ctx context.Context, ids []uuid.UUID) ([]*Content, error)
	UpdateContent(ctx context.Context, content *Content) error
	DeleteContent(ctx context.Context, id uuid.UUID) error
	ListContent(ctx context.Context, ownerID, tenantID uuid.UUID) ([]*Content, error)

	// Content metadata operations
	SetContentMetadata(ctx context.Context, metadata *ContentMetadata) error
	GetContentMetadata(ctx context.Context, contentID uuid.UUID) (*ContentMetadata, error)
	GetContentMetadataByContentIDs(ctx context.Context, contentIDs []uuid.UUID) (map[uuid.UUID]*ContentMetadata, error)

	// Status query operations
	GetContentByStatus(ctx context.Context, status string) ([]*Content, error)
	GetObjectsByStatus(ctx context.Context, status string) ([]*Object, error)

	// Derived content operations
	CreateDerivedContentRelationship(ctx context.Context, params CreateDerivedContentParams) (*DerivedContent, error)
	ListDerivedContent(ctx context.Context, params ListDerivedContentParams) ([]*DerivedContent, error)
	// GetDerivedRelationshipByContentID returns the derived-content relationship for a given derived content ID
	GetDerivedRelationshipByContentID(ctx context.Context, contentID uuid.UUID) (*DerivedContent, error)

	// Object operations
	CreateObject(ctx context.Context, object *Object) error
	GetObject(ctx context.Context, id uuid.UUID) (*Object, error)
	GetObjectsByContentID(ctx context.Context, contentID uuid.UUID) ([]*Object, error)
	GetObjectsByContentIDs(ctx context.Context, contentIDs []uuid.UUID) (map[uuid.UUID][]*Object, error)
	GetObjectByObjectKeyAndStorageBackendName(ctx context.Context, objectKey, storageBackendName string) (*Object, error)
	UpdateObject(ctx context.Context, object *Object) error
	DeleteObject(ctx context.Context, id uuid.UUID) error

	// Object metadata operations
	SetObjectMetadata(ctx context.Context, metadata *ObjectMetadata) error
	GetObjectMetadata(ctx context.Context, objectID uuid.UUID) (*ObjectMetadata, error)
	GetObjectMetadataByObjectIDs(ctx context.Context, objectIDs []uuid.UUID) (map[uuid.UUID]*ObjectMetadata, error)

	// Admin operations - for administrative tasks without owner/tenant restrictions
	ListContentWithFilters(ctx context.Context, filters ContentListFilters) ([]*Content, error)
	CountContentWithFilters(ctx context.Context, filters ContentCountFilters) (int64, error)
	GetContentStatistics(ctx context.Context, filters ContentCountFilters, options ContentStatisticsOptions) (*ContentStatisticsResult, error)
}

Repository defines the interface for content and object persistence

type Service

type Service interface {
	// Content operations
	CreateContent(ctx context.Context, req CreateContentRequest) (*Content, error)
	GetContent(ctx context.Context, id uuid.UUID) (*Content, error)
	UpdateContent(ctx context.Context, req UpdateContentRequest) error
	DeleteContent(ctx context.Context, id uuid.UUID) error
	ListContent(ctx context.Context, req ListContentRequest) ([]*Content, error)

	// Unified content upload operations (replaces object-based workflow)
	UploadContent(ctx context.Context, req UploadContentRequest) (*Content, error)
	UploadDerivedContent(ctx context.Context, req UploadDerivedContentRequest) (*Content, error)

	// Async workflow support: upload object for existing content
	UploadObjectForContent(ctx context.Context, req UploadObjectForContentRequest) (*Object, error)

	// Content data access
	DownloadContent(ctx context.Context, contentID uuid.UUID) (io.ReadCloser, error)

	// Content metadata operations
	SetContentMetadata(ctx context.Context, req SetContentMetadataRequest) error
	GetContentMetadata(ctx context.Context, contentID uuid.UUID) (*ContentMetadata, error)

	// Status management operations
	UpdateContentStatus(ctx context.Context, id uuid.UUID, newStatus ContentStatus) error
	UpdateObjectStatus(ctx context.Context, id uuid.UUID, newStatus ObjectStatus) error
	GetContentByStatus(ctx context.Context, status ContentStatus) ([]*Content, error)
	GetObjectsByStatus(ctx context.Context, status ObjectStatus) ([]*Object, error)

	// Object query operations
	GetObjectsByContentID(ctx context.Context, contentID uuid.UUID) ([]*Object, error)

	// Storage backend operations
	RegisterBackend(name string, backend BlobStore)
	GetBackend(name string) (BlobStore, error)

	// Derived content operations
	CreateDerivedContent(ctx context.Context, req CreateDerivedContentRequest) (*Content, error)
	GetDerivedRelationship(ctx context.Context, contentID uuid.UUID) (*DerivedContent, error)
	ListDerivedContent(ctx context.Context, options ...ListDerivedContentOption) ([]*DerivedContent, error)

	// Content details operations (unified interface for clients)
	GetContentDetails(ctx context.Context, contentID uuid.UUID, options ...ContentDetailsOption) (*ContentDetails, error)
	GetContentDetailsBatch(ctx context.Context, contentIDs []uuid.UUID, options ...ContentDetailsOption) ([]*ContentDetails, error)
}

Service defines the main interface for the simple-content library. This interface focuses on content operations and hides storage implementation details.

func New

func New(options ...Option) (Service, error)

New creates a new service instance with the given options

type SetContentMetadataRequest

type SetContentMetadataRequest struct {
	ContentID      uuid.UUID
	ContentType    string
	Title          string
	Description    string
	Tags           []string
	FileName       string
	FileSize       int64
	CreatedBy      string
	CustomMetadata map[string]interface{}
}

SetContentMetadataRequest contains parameters for setting content metadata

type StatusChangeHook added in v0.2.1

type StatusChangeHook func(hctx *HookContext, contentID uuid.UUID, oldStatus, newStatus ContentStatus) error

StatusChangeHook is called when content status changes

type StorageBackend

type StorageBackend struct {
	Name      string                 `json:"name"`
	Type      string                 `json:"type"`
	Config    map[string]interface{} `json:"config"`
	IsActive  bool                   `json:"is_active"`
	CreatedAt time.Time              `json:"created_at"`
	UpdatedAt time.Time              `json:"updated_at"`
}

StorageBackend represents a configurable storage backend

type StorageError

type StorageError struct {
	Backend string
	Key     string
	Op      string
	Err     error
}

StorageError represents an error related to storage operations

func (*StorageError) Error

func (e *StorageError) Error() string

func (*StorageError) ErrorMessage added in v0.2.2

func (e *StorageError) ErrorMessage() string

ErrorMessage returns a caller-friendly error message with technical details

func (*StorageError) HTTPStatus added in v0.2.2

func (e *StorageError) HTTPStatus() int

HTTPStatus returns the appropriate HTTP status code for this error

func (*StorageError) Unwrap

func (e *StorageError) Unwrap() error

type StorageService added in v0.1.11

type StorageService interface {
	// Object operations (internal use only)
	CreateObject(ctx context.Context, req CreateObjectRequest) (*Object, error)
	GetObject(ctx context.Context, id uuid.UUID) (*Object, error)
	GetObjectsByContentID(ctx context.Context, contentID uuid.UUID) ([]*Object, error)
	UpdateObject(ctx context.Context, object *Object) error
	DeleteObject(ctx context.Context, id uuid.UUID) error

	// Object upload/download operations (internal use only)
	UploadObject(ctx context.Context, req UploadObjectRequest) error
	DownloadObject(ctx context.Context, objectID uuid.UUID) (io.ReadCloser, error)
	GetUploadURL(ctx context.Context, objectID uuid.UUID) (string, error)
	GetDownloadURL(ctx context.Context, objectID uuid.UUID) (string, error)
	GetPreviewURL(ctx context.Context, objectID uuid.UUID) (string, error)

	// Object metadata operations (internal use only)
	SetObjectMetadata(ctx context.Context, objectID uuid.UUID, metadata map[string]interface{}) error
	GetObjectMetadata(ctx context.Context, objectID uuid.UUID) (map[string]interface{}, error)
	UpdateObjectMetaFromStorage(ctx context.Context, objectID uuid.UUID) (*ObjectMetadata, error)
}

StorageService defines operations for advanced users who need direct object access. This is an internal interface for storage implementation details.

func NewStorageService added in v0.1.11

func NewStorageService(options ...Option) (StorageService, error)

NewStorageService creates a new service instance that implements StorageService for advanced object operations

type TypeVariantPair added in v0.1.8

type TypeVariantPair struct {
	DerivationType string `json:"derivation_type"`
	Variant        string `json:"variant"`
}

TypeVariantPair represents a specific derivation type and variant combination

type UpdateContentRequest

type UpdateContentRequest struct {
	Content *Content
}

UpdateContentRequest contains parameters for updating content

type UploadContentRequest added in v0.1.11

type UploadContentRequest struct {
	OwnerID            uuid.UUID
	TenantID           uuid.UUID
	Name               string
	Description        string
	DocumentType       string
	StorageBackendName string // Optional - uses default if empty
	Reader             io.Reader
	FileName           string                 // Optional - for metadata
	FileSize           int64                  // Optional - for metadata
	Tags               []string               // Optional - for metadata
	CustomMetadata     map[string]interface{} // Optional - additional metadata
}

UploadContentRequest contains parameters for uploading content with data. This replaces the multi-step workflow of CreateContent + CreateObject + UploadObject.

type UploadDerivedContentRequest added in v0.1.11

type UploadDerivedContentRequest struct {
	ParentID           uuid.UUID
	OwnerID            uuid.UUID
	TenantID           uuid.UUID
	DerivationType     string
	Variant            string
	StorageBackendName string // Optional - uses default if empty
	Reader             io.Reader
	FileName           string                 // Optional - for metadata
	FileSize           int64                  // Optional - for metadata
	Tags               []string               // Optional - for metadata
	Metadata           map[string]interface{} // Derivation metadata
}

UploadDerivedContentRequest contains parameters for uploading derived content. This replaces the workflow of CreateDerivedContent + CreateObject + UploadObject.

type UploadObjectForContentRequest added in v0.1.23

type UploadObjectForContentRequest struct {
	ContentID          uuid.UUID
	StorageBackendName string // Optional - uses default if empty
	Reader             io.Reader
	FileName           string // Optional - for metadata
	MimeType           string // Optional - for metadata
}

UploadObjectForContentRequest contains parameters for uploading an object to existing content. This is used for async workflows where content is created first, then data uploaded later.

Example async workflow:

  1. CreateDerivedContent() with InitialStatus="processing"
  2. Worker generates thumbnail
  3. UploadObjectForContent() with thumbnail data
  4. UpdateContentStatus() to "processed"

type UploadObjectRequest added in v0.1.9

type UploadObjectRequest struct {
	ObjectID uuid.UUID
	Reader   io.Reader
	MimeType string // Optional - for metadata
}

UploadObjectRequest contains parameters for uploading an object

type UploadParams

type UploadParams struct {
	ObjectKey string
	MimeType  string
	FileName  string // Original filename for Content-Disposition header
}

UploadParams contains parameters for uploading an object

Directories

Path Synopsis
Package presigned provides HMAC-based authentication for presigned upload URLs.
Package presigned provides HMAC-based authentication for presigned upload URLs.
repo
storage
fs
s3

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL