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
Reduce storage cost without affecting UX.
Automatically move inactivity-based attachments from hot → warm → cold.
Provide seamless access from Angular, regardless of tier.
Add compression, encryption and checksum validation for cold tier.
Provide versioning support, audit logs and access tracing.
Support multi-cloud: Azure, AWS, GCP, on-premises.
Load tier configuration from database.
Make it extensible for future tiers.
Overall Architecture
The architecture has four major layers:
Angular client
.NET Attachment Service API
Storage Processor (background worker or hosted service)
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
)

Join the conversation! Your thoughts help the community grow.