ASP.NET Core  

Creating a Multi-Tier Attachment Storage System (Hot, Warm, Cold Storage) Using Angular and .NET

Introduction

Modern enterprise applications handle millions of documents and attachments: invoices, reports, CAD drawings, images, compliance files, videos, product manuals and more. Storing all attachments in a single storage tier quickly becomes expensive, slow, and difficult to scale.

A realistic system must decide:

  • Which files should be stored in fast and expensive storage?

  • Which files can move to cheaper storage after some time?

  • How do we fetch the correct file tier automatically?

  • How do we track storage transitions while maintaining auditability?

  • How do we expose this functionality cleanly in Angular and .NET?

This article describes a complete, production-grade multi-tier attachment storage system with:

  • Hot storage (local disk, Azure Blob Hot Tier, AWS S3 Standard)

  • Warm storage (S3 Infrequent Access, Azure Cool Tier, cheaper NAS)

  • Cold storage (Archive storage, Glacier, compressed & offline-ready files)

The system is metadata-driven, auto-migrates attachments based on rules, integrates with Angular UI for uploads/previews, and exposes a clean .NET API.

This is a senior-level article written in simple Indian English.

System goals

  1. Reduce storage cost without affecting UX.

  2. Automatically move inactivity-based attachments from hot → warm → cold.

  3. Provide seamless access from Angular, regardless of tier.

  4. Add compression, encryption and checksum validation for cold tier.

  5. Provide versioning support, audit logs and access tracing.

  6. Support multi-cloud: Azure, AWS, GCP, on-premises.

  7. Load tier configuration from database.

  8. Make it extensible for future tiers.

Overall Architecture

The architecture has four major layers:

  1. Angular client

  2. .NET Attachment Service API

  3. Storage Processor (background worker or hosted service)

  4. Multi-tier storage backend (hot, warm, cold)

Angular → .NET API → Storage Logic → Hot/Warm/Cold Storage

Workflow Diagram (High-Level Architecture)

                    +----------------------------+
                    |        Angular App         |
                    | Upload, Preview, Download  |
                    +-------------+--------------+
                                  |
                                  v
                    +----------------------------+
                    |      .NET API Layer        |
                    | Validate → Route → Store   |
                    +-------------+--------------+
                                  |
                 +----------------+-----------------+
                 |                                  |
                 v                                  v
      +--------------------+              +---------------------+
      |   Metadata DB      | <----------> | Background Processor|
      | Tier, Status, Logs |              | Migration Scheduler |
      +--------------------+              +---------------------+
                 |
                 v
    +------------------+--------------------+------------------+
    |      Hot         |       Warm         |      Cold        |
    |  Fast Storage    |  Medium Cost       | Archive Storage  |
    +------------------+--------------------+------------------+

Flowchart: Upload to Fetch Flow

           +---------------------+
           | User uploads file   |
           +----------+----------+
                      |
                      v
           +---------------------+
           | .NET API validates  |
           +----------+----------+
                      |
                      v
         +-------------------------+
         | Decide tier = Hot Tier  |
         +------------+------------+
                      |
                      v
           +-----------------------+
           | Store file in Hot     |
           | Insert metadata in DB |
           +-----------+-----------+
                       |
                       v
           +-----------------------+
           | Angular fetches URL   |
           | Preview/Download      |
           +-----------------------+

System Design

Storage tiers

Hot tier

  • Fast

  • Direct URL access

  • Used for recent uploads

  • Preferred for real-time workflows

Examples

  • Azure Blob Hot

  • S3 Standard

  • Local SSD

Warm tier

  • Moderate cost

  • Slightly slower

  • Used for files older than configured warmThresholdDays

Examples:

  • Azure Cool

  • S3 Infrequent Access

  • Cheaper NAS

Cold tier

  • Very cheap

  • Very slow

  • Suitable for archival

  • Requires offline restoration or delayed access

Examples:

  • Azure Archive

  • S3 Glacier

  • Offline compressed storage

Database Schema

Attachment
(
    AttachmentId BIGINT PK,
    FileName NVARCHAR(255),
    ContentType NVARCHAR(100),
    SizeInBytes BIGINT,
    CurrentTier VARCHAR(10),      -- HOT, WARM, COLD
    Version INT,
    UploadDate DATETIME,
    LastAccessed DATETIME,
    ModifiedDate DATETIME,
    StoragePath NVARCHAR(MAX),
    Checksum CHAR(64),
    EncryptionKeyId INT,
    Metadata JSON
)

StorageTierConfig
(
    TierName VARCHAR(10),
    WarmThresholdDays INT,
    ColdThresholdDays INT,
    MigrationEnabled BIT
)

AttachmentAccessLog
(
    LogId BIGINT,
    AttachmentId BIGINT,
    AccessedDate DATETIME,
    UserId BIGINT
)

.NET Backend (API Layer)

Controller Structure

/api/attachments
    POST /upload
    GET /{id}
    GET /{id}/download
    GET /{id}/metadata

Upload flow

  1. Validate file size and type.

  2. Generate checksum (SHA256).

  3. Store in Hot tier.

  4. Insert metadata in DB.

Download flow

  1. Resolve tier from DB.

  2. If cold-tier and requires restoration:

    • Trigger restore workflow

    • Return 202 Accepted

  3. Otherwise return file stream or signed URL.

C#: Upload API (Simplified)

[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
    if (file == null || file.Length == 0)
        return BadRequest("Invalid file");

    var checksum = _checksumService.ComputeSHA256(file.OpenReadStream());

    var storagePath = await _hotStorage.SaveAsync(file.FileName, file.OpenReadStream());

    var attachment = new Attachment
    {
        FileName = file.FileName,
        ContentType = file.ContentType,
        SizeInBytes = file.Length,
        CurrentTier = "HOT",
        UploadDate = DateTime.UtcNow,
        LastAccessed = DateTime.UtcNow,
        StoragePath = storagePath,
        Version = 1,
        Checksum = checksum
    };

    var id = await _repo.AddAsync(attachment);

    return Ok(new { attachmentId = id });
}

C#: Fetch Logic with Tier Routing

[HttpGet("{id}/download")]
public async Task<IActionResult> Download(long id)
{
    var attachment = await _repo.Get(id);

    switch (attachment.CurrentTier)
    {
        case "HOT":
            return File(await _hotStorage.GetAsync(attachment.StoragePath),
                        attachment.ContentType,
                        attachment.FileName);

        case "WARM":
            return File(await _warmStorage.GetAsync(attachment.StoragePath),
                        attachment.ContentType,
                        attachment.FileName);

        case "COLD":
            bool ready = await _coldStorage.IsRestoredAsync(attachment.StoragePath);

            if (!ready)
            {
                await _restoreQueue.Enqueue(id);
                return Accepted(new { message = "Restoration triggered" });
            }

            return File(await _coldStorage.GetRestoredAsync(attachment.StoragePath),
                        attachment.ContentType,
                        attachment.FileName);

        default:
            return NotFound();
    }
}

Background Migration Processor

A hosted service scans all attachments daily:

  1. Check last accessed date.

  2. If > WarmThresholdDays → move to warm tier.

  3. If > ColdThresholdDays → compress, encrypt, move to cold.

  4. Update metadata in DB.

Migration Pseudocode

foreach (attachment in Attachments)
    if daysSinceLastAccess > ColdThreshold
        MoveToCold(attachment)
    else if daysSinceLastAccess > WarmThreshold
        MoveToWarm(attachment)

Angular Front-End Implementation

Upload Component

uploadFile(event: any) {
  const file = event.target.files[0];
  const formData = new FormData();
  formData.append('file', file);

  this.http.post('/api/attachments/upload', formData)
    .subscribe(res => this.loadList());
}

Preview Component

Automatically handles tier-based access using the API.

download(id: number) {
  this.http.get(`/api/attachments/${id}/download`, {
    responseType: 'blob'
  }).subscribe(blob => {
    const url = window.URL.createObjectURL(blob);
    window.open(url);
  });
}

Real-World Best Practices

1. Use signed URLs

Do not expose raw storage paths to Angular.

2. Introduce throttling on large restores

Cold-tier restores must be queued.

3. Store checksum for integrity

Must verify data corruption when restoring.

4. Allow user-driven restore requests

Users may need old documents urgently.

5. Version attachments

Never overwrite existing versions.

6. Add deletion retention periods

Accidental deletions → soft delete → permanent delete.

7. Encrypt cold-tier files

Since cold storage is long-term.

8. Store metadata in JSON

Easier to add new fields without schema changes.

9. Keep migration logs

Needed for audits and compliance.

End-to-End Walkthrough Example

Uploading a new PDF

  1. Angular uploads file

  2. API stores it in hot tier

  3. DB stores metadata

User opens file next day

  • File still in hot → served quickly

After 180 days (no access)

  • Background processor moves file to warm

After 365 days (no access)

  • File compressed

  • Encrypted

  • Moved to cold

User wants file after 2 years

  • API triggers restore

  • After restore completes, file is accessible

Security Considerations

1. Encryption keys stored in KMS

Never store keys in app config.

2. Always use HTTPS

Storage URLs must not be exposed over HTTP.

3. Audit logs for access

Track every preview and download.

4. Authentication required

JWT or Azure AD recommended.

5. Virus scanning

Mandatory for uploads.

Scalability

Horizontal scale

  • API scaling is easy since file storage is external.

  • Angular remains unaffected.

Async restore queue

  • Distributed queue (Azure Queue, SQS) recommended.

Cold storage restore batching

  • Batch operations reduce cost drastically.

Conclusion

A multi-tier attachment storage system is not a simple file upload tool. It is a complete architecture that must balance performance, cost, security, and long-term data retention.

This article provided a detailed, production-level solution integrating:

  • Angular front-end

  • .NET API

  • Hot / Warm / Cold storage

  • Auto-migration worker

  • Metadata-driven rules

You now have a blueprint to build a scalable, enterprise-level attachment handling system used in ERPs, CRMs, DMS products, aviation systems, and fintech platforms.