- Infrastructure: Adopt
dotenvx
for environment variable management.
- Web: Fix ‘View source’ functionality. Remove extraneous quotes from running
show
.
- Web: Upgrade Universal Analytics to Google Analytics 4, including script embeds.
processContent
- Log progress of tile uploads.
- Upgrade Lambda runtime from Node.js 12.x LTS to 20.x LTS.
- Upgrade
sharp
from0.30.2
to0.33.3
.
- Index
content.submitter_email
for faster querying.- Use Squeal type-safe indexes that track indexes in the type, see
ZoomHub.Storage.PostgreSQL.Schema.Schema5
.
- Use Squeal type-safe indexes that track indexes in the type, see
- Ops
- Remove legacy Ansible references.
- Web:
- Remove support for
https://zoomhub.net/https://example.com/image.jpeg
shortcut to stop having custom fork ofservant
. - Make
ZH_WEB_BASE_URI
andZH_STATIC_BASE_URI
dynamic in HTML via Snowpack.
- Remove support for
- Infrastructure:
- Upgrade
stack
LTS from 14.14 (GHC 8.6.5) to 22.6 (GHC 9.6.3) to run more seamlessly on Apple Silicon development machine. - Remove vendoring of
servant
and give up on customRawCaptureRouter
. - Port S3 POST policy from
minio-hs
toamazonka
2.0.0
. - Upgrade
amazonka
from1.6.1
to2.0.0
. - Upgrade
squeal-postgresql
from0.5.1.0
to0.9.1.3
. - Upgrade
aeson
from1.4.6.0
to2.1.2.1
. - Remove
ansible.cfg
. - Switch
DeepZoomImage
dziWidth
anddziHeight
fromInteger
toInt64
.
- Upgrade
- Ops (CI):
- Upgrade GitHub Actions runners from Ubuntu 18.04 to 22.04.
- API:
- Introduce
UPLOADS_MAX_SIZE_MEGABYTES
environment variable for controlling the maximum size for uploads. - Move internal API from
/v1
to/internal
. - Make
environment
andbaseURI
public in/internal/config
to verify environment configuration.
- Introduce
processContent
:- Introduce new environment variables:
NUM_CONCURRENT_UPLOADS
: Set maximum of concurrent uploads of tiles to S3. Default:10
.ROOT_PATH
: Set root path for where to store tiles, e.g. to leverage AWS Elastic File Storage (EFS). Default:/tmp
.TILE_SIZE
: Set tile size of Deep Zoom image pyramid. Recommended:254
or510
. Default:254
.VIPS_DISC_THRESHOLD
: Set maximum size of image that VIPS loads into memory.
- Upgrade
sharp
from 0.29.1 to 0.30.2. This should improve tiling performance. - Increase tile size from 254 pixels to 510 pixels (in development and staging)
- Time long-running operations.
- Delete temporary files after DZI upload.
- Introduce new environment variables:
- Ops (CI):
- Separate deployment of
web
andprocessContent
.
- Separate deployment of
- Explore: Add private
/explore/recent
page for viewing recent uploads.
- Embed: Ensure fullscreen background color is always black.
-
Embed: Add
background
parameterCustomize embed background to be:
none
(transparent)white
black
(default)
Useful for branding as well as avoiding background bleed through on
constrain=full
embeds. -
Disable directory listings, e.g. on
/showcase/ecommerce/
. -
Simplify
curl
example on homepage.
- View content page:
- Add ‘View source’ button for URL submissions.
- Verify page:
- Fix redirect.
- Fix link color.
- Improve mobile layout.
- View page: Add share buttons:
- Embed
- Temporarily remove source URL until we can hide it for uploads.
-
Haskell: Integrate Tailwind CSS by running Snowpack as a file watcher.
Enable autocomplete in Haskell/Lucid using Visual Studio Code Tailwind CSS extension and this configuration:
{ "tailwindCSS.includeLanguages": { "haskell": "html" }, "tailwindCSS.experimental.classRegex": ["H[.]class_ \"([^\"]*)"] }
-
Haskell: Enable fast reload using
ghcid
andZoomHub.Web.MainDevelopment
as adapted from servant-persistent.
- View page: Fix layout. Explicitly set
width
andheight
to prevent aspect ratio preservation behavior.
-
Embed: Add new features to
<script>
embeds:border=none
: Disable black border.fit=contain|cover
:contain
(default): Contain image within canvas.cover
: Cover canvas with image.
constrain=zoom|full
:zoom
: Disallow zooming out from default view.full
: Disallow zooming out as well as panning away from default view to never show black borders (as long as aspect ratio of image preserved).
Preserve image aspect ratio by setting
width
to a value andheight=auto
. This uses CSSaspect-ratio
property.Due to the lack of full screen support on Safari iOS, we need to continue offering
<script>
embeds alongside<iframe>
imports.Example
<script src="http://localhost:8000/h.js?width=100%&height=auto&border=none&constrain=full"></script>
-
Embed: Add iframe embeds for better security and faster loading (shared OpenSeadragon script).
Example (default)
<iframe width="600" height="450" src="https://zoomhub.net/h/embed" title="ZoomHub image embed" frameborder="0" allowfullscreen ></iframe>
Example (cover)
<iframe width="100%" height="450" src="https://zoomhub.net/h/embed?fit=cover" title="ZoomHub image embed" frameborder="0" allowfullscreen ></iframe>
-
OpenSeadragon: Upgrade to version 3.0.0. Use fork with custom icons.
- Set canonical URLs to direct traffic from zoom.it to zoomhub.net.
processContent
:- Clean up
/tmp
on every invocation to free up disk space. - Report disk space.
- Clean up
- Improve landing page
- Make demo mode explicit to allow for additional content below
- Add Embed section
- Add API section
- Set Safari toolbar color
- Show progress bar for uploads.
- Add GIF (
image/gif
) to list of allowed file uploads.
- Restrict uploads to JPEG, PNG, and TIFF files.
- Restore upload UI. We have observed many invalid image URL submissions as many point to non-image resources that we currently don’t support, e.g. images in HTML image galleries, document HTML pages, YouTube, etc.
- Improve colors of text inputs in dark theme.
- Make homepage more mobile friendly.
- Run full development stack via
./zh run
: ngrok, Haskell web API, and Snowpack frontend development server. - Dynamically set API base URL.
- Reduce logging in background worker to increase signal to noise ratio.
- Call AWS Lambda function alias based on
ZH_ENV
environment variable.
- Accept submissions from image URLs instead of uploads only.
- Temporarily remove upload UI until it’s ported to new frontend.
- Add frontend project using:
- React.js for interactive components
- Tailwind CSS for styling
- Snowpack for development server and production builds
- Improve homepage copy.
- Improve homepage design.
- Swap cover image for a panorama.
- Redirect on verification link if content is completed.
- Improve copy of verification email.
- Homepage: Keep upload card in view (via scrolling) when changing states.
- Use HTTPS for static and cache content URLs by default.
- Use
neat-interpolation
for cleaner multiline strings with interpolated values. zh
: Fix slow compilation due to optimization flag change by adding--fast
to match all the otherstack build
calls.
- Improve performance of
getNextUnprocessed
query using indexes oncontent
. - When resetting content, delete any associated image.
- Temporarily reduce max upload size from 100MB to 50MB due to AWS Lambda scratch disk limitations (500MB maximum).
- Improve logging for when we try to notify someone about content without a submitter email and/or verification token.
- Remove unused
TempPath
since we stopped doing image processing on web server.
- #172 Auto-rotate images based on EXIF data.
- Worker: Increase poll interval from 3 to 5 seconds.
- Add
PUT /v1/content/:id/reset
for admins to reset content, e.g. after it failed or we improved the processing pipeline. An example is for images that were incorrectly rotated but can be reprocessed after fixing that issue #172. - Ensure running and testing the app doesn’t cause a full rebuild by matching
stack
(GHC) flags.
- 🎉 MVP
- Allow uploads via homepage
- Send email verification
- Verification landing page
- Process image via AWS Lambda
- Redirect upon success
- Send submitter an email with a verification link to authenticate the upload. After verification, our background worker picks up unprocessed submissions and processes them via AWS Lambda.
- Introduce
ZH_ENV = "development" | "test" | "production"
environment variable for controlling certain actions, e.g. not sending emails during testing. - Set content version to
5
on new submissions. These are submissions that have a submitter email and verification token. - Control logging via
LOG_LEVEL
environment variable. ExtractLogLevel
module and introducelogLevel
configuration for controlling what level of logs we want to capture. - Pipe AWS logs through our own JSON logger.
- Reduce log level of many worker operations to reduce noise.
- Remove unused
S3_CACHE_BUCKET
from Haskell web server.
- Generate verification token for each new submission. This will be used to send an email verification link to the submitter.
- Require email for each submission:
/v1/content/upload?email=<email>
/v1/content?email=<email>&url=<url>
- Add AWS Lambda worker for converting content into Deep Zoom Images (DZIs)
using VIPS:
- Package and deploy code from CI.
- Add
API_USERNAME
andAPI_PASSWORD
for authenticating Lambda worker. - Add authenticated endpoint
PUT /v1/content/:id/completion
for reporting AWS Lambda worker processing completions. - Remove unused
ZoomHub.Pipeline
module.
- Introduce distinction between
JPG
andJPEG
tile formats. By default, VIPS outputs DZI tiles with.jpeg
extension. To accommodate that, we needed distinguish tiles by file extension. Ultimately, we worked around it by renaming tiles before upload to S3. - Add
amazonka
dependency for invoking AWS Lambda worker. - Development: Normalize GHC flags to avoid multiple recompilations.
- Development: Fix database setup by separating content insertions and adjustment of PostgreSQL sequences.
- Enable HTTPS.
- Uploads
- Add
/v1/content/upload
endpoint for AWS S3 presigned POST using MinIO. - Add
UPLOADS=true|false
environment variable for enabling/disabling uploads. - Add
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
,S3_CACHE_BUCKET
, andS3_SOURCES_BUCKET
environment variables for AWS/MinIO configuration.
- Add
- Add
CONTENT_BASE_URI
environment variable to replace Rackspace container based URL resolution. - Limit logging of request body to 512 bytes.
- Serving all production traffic.
- Auto-formatted Haskell code using Ormolu.
- Restore
/version
endpoint.
- Migrate hosting from Rackspace to Amazon AWS:
- Rackspace Cloud Servers → AWS Elastic Beanstalk (EC2 + ECS + ECR)
- Rackspace Cloud Files → AWS S3
- Keter bundle → Docker container
- Local SQLite file → AWS RDS PostgreSQL
- Splunk → TBD
- Remove archived files.
- Remove old SQLite development database.
- Remove Ansible based ops setup.
- Remove Rackspace Cloud Files to AWS S3s migration scripts.
- Format Markdown + HTML using Prettier.
- Add
stack.yaml.lock
file.
- To enable concurrent submissions, migrate storage engine from SQLite,
which only allows a single write operation due to a file lock, to
PostgreSQL using Squeal, a type-safe embedding of PostgreSQL in Haskell.
- Perform type-safe database migrations using
migrate-database
helper. - Set up PostgreSQL trigger for generating new content hash IDs.
- Add full test suite for ZoomHub API.
- Ops
- Add infrastructure for setting up RDS PostgreSQL instance.
- Add database migration scripts.
- Perform type-safe database migrations using
- Combine
PROCESS_EXISTING_CONTENT
andPROCESS_NEW_CONTENT
environment variables intoPROCESS_CONTENT='ProcessNoContent|ProcessExistingContent|ProcessExistingAndNewContent'
. This was done becausePROCESS_EXISTING_CONTENT=0
andPROCESS_NEW_CONTENT=1
is an invalid state. We do not spin up any workers unlessPROCESS_CONTENT=ProcessExistingContent|ProcessExistingAndNewContent
. - Upgrade Stack LTS from 12.6 to 14.14.
- Add infrastructure for background processing of existing content.
- Add
PROCESSING_WORKERS
environment variable for controlling the number of workers (green threads) that process existing content. - Track
numViews
using a sampling rate /ht @aseemk. - Order keys of log lines so
time
comes first which helps Splunk process them. - Pretty print certain
HttpException
, most notablyStatusCodeException
which previously generated very long log lines due to artificialX-Response-Body-Start
header that included entire error response body. - Simplify parsing configuration from environment variables.
- Make error handling in
Worker
more robust. - Track
worker
metadata in logs.
- Import original Zoom.it data—
ContentInfo
,ImageInfo
, andFlickrPhotoInfo
—into newzoomhub.sqlite3
database. - Fix incorrect MIME types in original data set.
- Start tracking number of views for a given content using
numViews
column. - Use new database connection for each request in an unsuccessful attempt to mitigate multi-threading issues with SQLite 3. See: IreneKnapp/direct-sqlite#61
- Add background worker for processing existing, unprocessed content. Picks
most popular content based on
numViews
data. - Introduce
ContentType
data type. - Support existing
zoomit://thumbnail/?url=
URLs asContentURI
. - Add
PROCESS_EXISTING_CONTENT
andPROCESS_NEW_CONTENT
environment variables. - Log
Config
at startup. - Introduce
RACKSPACE_CONTAINER
andRACKSPACE_CONTAINER_PATH
environment variables to run existing content (container:content
, path:dzis
) and new one (container:cache
, path:content
; backwards compatibility with Zoom.it). - Improve logging throughout the app using
Logger
andlogT
which lets you log duration of operations usingtimeItT
. - Add
type: "access"
field to request log lines to distinguish fromtype: "app"
application logs. - Adopt type-safe time units using
time-units
library. - Switch
duration
request log field into type-safe milliseconds. - Add global Warp web server exception handler using
message: "Web server exception"
. - Introduce
TEMP_PATH
to replaceDATA_PATH
. The application writes temporary data into$TEMP_PATH/temp
. - Switch static content hosting to
static.zoomhub.net
. - Improve VIPS error reporting using
readProcessWithExitCode
. - Implement DZI XML parsing using
Text.XML.Light
and add tests. - Implement DZI tile and manifest upload to CloudFiles using
putContent
. - Add retry logic to database writes and CloudFiles uploads
using
retry
library. - Make
contentMIME
type-safe. - Make
initializedAt
non-null. - Optimize output binary using GHC
-O3
flag. - Add basic support for multithreading, e.g.
getNumCapabilities
, etc., but disable it until SQLite3 multi-threading issues have been resolved or we adopt a different database.
- Initial port to Haskell.
- Add basic continuous deployment using CircleCI.
- Upgrade
coffee-script
to 1.8.0. - Use more
default
Express logger format for more detailed logs in production, incl. timestamps. - Switch from
streamline-express
toexpress-streamline
. - Use
npm start
for./zh run
. - Fix Node.js PPA version:
0.10.32-1chl1~precise1
. - Fix Redis setup:
- Upgrade PPA dependency:
2:2.8.17-1chl1~precise1
- Start Redis before web server.
- Fix path to Redis database file:
/var/lib/redis/
. - Fix path to
redis-server
executable:/usr/bin/redis-server
- Change path to log file:
/var/log/redis/redis-server.log
.
- Upgrade PPA dependency:
- Add
DZIParser
andEmbed
modules to read created DZIs and create OpenSeadragon embed JS, respectively. - Change the ZoomHub APIs to match the zoom.it APIs more closely.
- ZH-22: Persist metadata using Redis.
- Implement basic
Content
model. - Extract
Fetcher
andProcessor
from inline code. - Link to metadata from view page.
- Add support for VIPS to improve speed of generating DZIs:
- Upgrade deepzoomtools to version 0.0.4.
- Setup Ansible role.
- Improve Ansible setup and deployment:
- Separate boostrap from setup phase. Bootstrap requires
root
access to create admin user so setup can simply use admin user. - Run app on port 3000 and map it to port 80. Allows us to run the app
with an unprivileged admin user instead of
root
.
- Separate boostrap from setup phase. Bootstrap requires