-
Notifications
You must be signed in to change notification settings - Fork 430
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: rename storageKey to objectKey for Tigris object storage
also write decision doc and documentation
- Loading branch information
1 parent
128c161
commit 5075d92
Showing
13 changed files
with
191 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Title: Switch to Tigris for Image Storage | ||
|
||
Date: 2025-02-20 | ||
|
||
Status: accepted | ||
|
||
## Context | ||
|
||
The Epic Stack previously stored uploaded images directly in SQLite using binary | ||
data storage. While this approach is simple and works well for small | ||
applications, it has several limitations (as noted in the previous decision | ||
[018-images.md](docs/decisions/018-images.md)): | ||
|
||
1. Binary data in SQLite increases database size and backup complexity | ||
2. Large binary data in SQLite can impact database performance | ||
3. SQLite backups become larger and more time-consuming when including binary | ||
data | ||
4. No built-in CDN capabilities for serving images efficiently | ||
|
||
## Decision | ||
|
||
We will switch from storing images in SQLite to storing them in Tigris, an | ||
S3-compatible object storage service. This change will: | ||
|
||
1. Move binary image data out of SQLite into specialized object storage | ||
2. Maintain metadata about images in SQLite (references, ownership, etc.) | ||
3. Leverage Tigris's S3-compatible API for efficient image storage and retrieval | ||
4. Enable better scalability for applications with many image uploads | ||
|
||
To keep things lightweight, we will not be using an S3 SDK to integrate with | ||
Tigris and instead we'll manage authenticated fetch requests ourselves. | ||
|
||
## Consequences | ||
|
||
### Positive | ||
|
||
1. Reduced SQLite database size and improved backup efficiency | ||
2. Better separation of concerns (binary data vs relational data) | ||
3. Potentially better image serving performance through Tigris's infrastructure | ||
4. More scalable solution for applications with heavy image usage | ||
5. Easier to implement CDN capabilities in the future | ||
6. Simplified database maintenance and backup procedures | ||
7. Tigris storage is much cheaper than Fly volume storage | ||
|
||
### Negative | ||
|
||
1. Additional external service dependency (though Fly as built-in support and no | ||
additional account needs to be created) | ||
2. Need to manage Tigris configuration | ||
3. Slightly more complex deployment setup | ||
4. Additional complexity in image upload and retrieval logic | ||
|
||
## Implementation Notes | ||
|
||
The implementation involves: | ||
|
||
1. Setting up Tigris configuration | ||
2. Modifying image upload handlers to store files in Tigris | ||
3. Updating image retrieval routes to serve from Tigris | ||
4. Maintaining backward compatibility during migration (database migration is | ||
required as well as manual migration of existing images) | ||
5. Providing migration utilities for existing applications | ||
|
||
## References | ||
|
||
- [Tigris Documentation](https://www.tigris.com/docs) | ||
- Previous image handling: [018-images.md](docs/decisions/018-images.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Image Storage | ||
|
||
The Epic Stack uses [Tigris](https://www.tigris.com), an S3-compatible object | ||
storage service, for storing and serving uploaded images. Tigris is integrated | ||
tightly with Fly.io, so you don't need to worry about setting up an account or | ||
configuring any credentials. | ||
|
||
## Configuration | ||
|
||
To use Tigris for image storage, you need to configure the following environment | ||
variables. These are automatically set for you on Fly.io when you create storage | ||
for your app which happens when you create a new Epic Stack project. | ||
|
||
```sh | ||
AWS_ACCESS_KEY_ID="mock-access-key" | ||
AWS_SECRET_ACCESS_KEY="mock-secret-key" | ||
AWS_REGION="auto" | ||
AWS_ENDPOINT_URL_S3="https://fly.storage.tigris.dev" | ||
BUCKET_NAME="mock-bucket" | ||
``` | ||
|
||
These environment variables are set automatically in the `.env` file locally and | ||
a mock with MSW is set up so that everything works completely offline locally | ||
during development. | ||
|
||
## How It Works | ||
|
||
The Epic Stack maintains a hybrid approach to image storage: | ||
|
||
1. Image metadata (relationships, ownership, etc.) is stored in SQLite | ||
2. The actual image binary data is stored in Tigris | ||
3. Image URLs point to the local server which proxies to Tigris | ||
|
||
### Database Schema | ||
|
||
The database schema maintains references to images while the actual binary data | ||
lives in Tigris: | ||
|
||
```prisma | ||
model UserImage { | ||
id String @id @default(cuid()) | ||
userId String | ||
user User @relation(fields: [userId], references: [id], onDelete: Cascade) | ||
objectKey String // Reference to the image in Tigris | ||
contentType String | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
@@index([userId]) | ||
} | ||
model NoteImage { | ||
id String @id @default(cuid()) | ||
noteId String | ||
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade) | ||
objectKey String // Reference to the image in Tigris | ||
contentType String | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
@@index([noteId]) | ||
} | ||
``` | ||
|
||
### Image Upload Flow | ||
|
||
1. When an image is uploaded, it's first processed by the application | ||
(validation, etc.) | ||
2. The image is then streamed to Tigris | ||
3. The metadata is stored in SQLite with a reference to the Tigris object key | ||
4. The image can then be served by proxying to Tigris | ||
|
||
## Customization | ||
|
||
For more details on customization, see the source code in: | ||
|
||
- `app/utils/storage.server.ts` | ||
- `app/routes/resources+/note-images.$imageId.tsx` | ||
- `app/routes/resources+/user-images.$imageId.tsx` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.