PhotoFlow Documentation Help

Storage Service

Overview

The Storage Service manages cloud provider integrations, file synchronization with Google Drive, and photo storage operations.

Responsibilities

  • Cloud provider authentication (OAuth2)

  • Google Drive folder synchronization

  • File upload/download operations

  • Photo metadata management

  • Sync progress tracking and notifications

Project Structure

Storage/ ├── Storage.API/ │ ├── Controllers/ │ │ ├── FolderController.cs │ │ ├── FileController.cs │ │ └── AuthController.cs │ └── Program.cs ├── Storage.Application/ │ ├── UseCases/ │ │ ├── Folders/ │ │ ├── Files/ │ │ └── Auth/ │ ├── Commands/ │ └── Queries/ ├── Storage.Domain/ │ ├── Entities/ │ │ ├── FolderEntity.cs │ │ ├── FileEntity.cs │ │ └── CloudProviderEntity.cs │ ├── Events/ │ │ ├── StorageFolderSyncProgressEvent.cs │ │ └── StorageFolderSyncCompletedEvent.cs │ └── Services/ └── Storage.Infrastructure/ ├── Adapters/ │ └── Outbound/ │ └── Services/ │ └── FolderService.cs └── Providers/ └── Google/ └── GoogleDriveProvider.cs

Domain Entities

FolderEntity

public class FolderEntity : BaseEntity<Guid> { public string Name { get; private set; } public string ExternalId { get; private set; } // Google Drive ID public Guid ProviderId { get; private set; } public Guid? ParentFolderId { get; private set; } public string Description { get; private set; } // Contains AlbumId mapping public CloudProviderType ProviderType { get; private set; } }

FileEntity

public class FileEntity : BaseEntity<Guid> { public string Name { get; private set; } public string ExternalId { get; private set; } public Guid FolderId { get; private set; } public string MimeType { get; private set; } public long Size { get; private set; } public string ThumbnailUrl { get; private set; } public string WebViewLink { get; private set; } }

Sync Architecture

Sync Flow

Google DriveStoragePhotoflowGoogle DriveStoragePhotoflowloop[For each batch]SyncFolderToStorage(folderId)List Files in FolderFile ListGet File MetadataMetadataStore in DatabaseStorageFolderSyncProgressEventStorageFolderSyncCompletedEvent

Batch Processing

Photos are synced in batches to optimize performance:

public class StorageConfiguration { public const int ItemPerBatch = 50; // Photos per batch }

Progress Events

public record StorageFolderSyncProgressEvent : IInServiceEvent { public required string FolderExternalId { get; set; } public Guid? AlbumId { get; set; } public required int ProcessedCount { get; set; } public required int TotalCount { get; set; } public required int BatchNumber { get; set; } public required int TotalBatches { get; set; } public required bool IsComplete { get; set; } }

Google Drive Integration

OAuth2 Flow

Google OAuthStorageFrontendUserGoogle OAuthStorageFrontendUserConnect Google DriveInitiateLoginOAuth2 Authorization URLRedirect to GoogleGrant PermissionAuth CodeExchange for TokensAccess + Refresh TokenStore Tokens

Supported Operations

Operation

Description

ListFiles

List files in a folder

GetFile

Get file metadata

DownloadFile

Download file content

CreateFolder

Create a new folder

ShareFolder

Generate shareable link

GetThumbnail

Get image thumbnail URL

API Endpoints

Folder Operations

# List folders GET /api/v1/storage/folders # Get folder detail GET /api/v1/storage/folders/{id} # Sync folder from Google Drive POST /api/v1/storage/folders/{id}/sync # Get photos in folder GET /api/v1/storage/folders/{id}/photos

File Operations

# Get file detail GET /api/v1/storage/files/{id} # Get file thumbnail GET /api/v1/storage/files/{id}/thumbnail # Get download URL GET /api/v1/storage/files/{id}/download

Auth Operations

# Initiate OAuth login POST /api/v1/storage/auth/login # Handle OAuth callback POST /api/v1/storage/auth/callback # Revoke token POST /api/v1/storage/auth/revoke

Audit Logging

The Storage Service implements comprehensive audit logging using the decorator pattern:

public class AuditedFolderService : IFolderService { private readonly IFolderService _folderService; private readonly IAuditLogService _auditLogService; public async Task<bool> SyncByIdAsync(CloudProviderType provider, Guid folderId, ...) { var stopwatch = Stopwatch.StartNew(); var auditLogId = await _auditLogService.CreateAuditLogAsync(...); try { var result = await _folderService.SyncByIdAsync(provider, folderId, ...); stopwatch.Stop(); await _auditLogService.MarkCompletedAsync(auditLogId, ..., stopwatch.ElapsedMilliseconds); return result; } catch (Exception ex) { stopwatch.Stop(); await _auditLogService.MarkFailedAsync(auditLogId, ex.Message, stopwatch.ElapsedMilliseconds); throw; } } }

Performance Optimizations

Async Queue Processing

Audit logs are processed asynchronously to avoid blocking sync operations:

public class InternalAuditLogQueueService : IAuditLogService { private readonly ConcurrentQueue<AuditLogOperation> _auditLogQueue; public async Task<AuditLogEntity> CreateAuditLogAsync(...) { var operation = new AuditLogOperation { Type = Create, ... }; _auditLogQueue.Enqueue(operation); return AuditLogEntity.Create(...); // Return immediately } }

Caching

Frequently accessed data is cached using Redis:

  • Folder metadata

  • File thumbnails URLs

  • OAuth tokens (encrypted)

Error Handling

Retry Logic

Sync operations use exponential backoff for transient failures:

var retryPolicy = Policy .Handle<GoogleApiException>() .WaitAndRetryAsync( retryCount: 3, sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)) );

Error Events

Event

Description

StorageFolderSyncFailedEvent

Sync operation failed

StorageAuthFailedEvent

OAuth authentication failed

StorageQuotaExceededEvent

Google Drive quota exceeded

Last modified: 25 February 2026