Monitor submissions I

Monitor submissions I

We needed to enable submissions on the Monitor website. We wanted writers to be able to submit their work to the site in order to have it published by Monitor.

Whilst this could have been achieved in a number of ways (email, Dropbox, etc) the neatest way would be to have a portal on the site where they could submit and we would save their submission, a cover letter and some contact details in one place which would make reading the submission easiest for the judges.


Bucket implementation

The site is hosted on Netlify so my initial thought was to use Netlify Forms which would be dead simple. But Netlify forms has a file size restriction of 8mb which was too small for our needs. We were asking people to submit pamphlets and these could easily go above 8MB even with compression. We decided against suggesting users compress their .pdfs before submitting because we didn't want to discourage less technical savvy writers - they might have the best works!

I explored a number of other options:

  • I'm currently most familiar with GCP as I work with it heavily at my day job
  • If you're uploading files and you're not considering S3 then you're doing something wrong
  • Finally, Cloudflare R2 which is their blob storage offering

I had already used GCP and S3 and blob storage being blob storage (i.e. not too technically complex) I wanted to explore more Cloudflare functionality as I am always hearing good things about their DX, most notably on Syntax.fm. DX is super important for this project because I mostly do it in my spare time and I want it to be simple and enjoyable to build.

Payment

We needed to charge for submissions (although we would allow free entries for those without the funds) to cover the costs for reading the entries which was made simple enough through setting up a Stripe checkout page. I love how simple Stripe makes things and prevents us having to worry about taking any payment details. After the users pay through Stripe they would then be redirected to the Submissions form where they could submit their work.

I did consider having the submission form completely open for the sake of simplicity and to allow for users to submit without paying. If we noticed we had many more submissions than we had payments we could cross reference the email addresses that had paid and find the ones that hadn't. However this added more work to an already stretched team (Monitor is run on a tight budget) and with the help of Claude it was trivial to add a check for payment.

The Stripe checkout can pass a session ID for an accepted payment in the query parameters to the page it redirects to. When the page loads we call a Netlify function with the param which in turn attempts to retrieve the checkout session from Stripe. If the function is able to retrieve the checkout session and confirm that this session has paid we load the submission form. Otherwise we throw an error.

Once the submission form has loaded the user is able to upload their submission (up to 75mb pdfs) and contact details. Once we have successfully processed the submission and it has landed in R2 we send them a confirmation email via Resend. They will also receive an email from Stripe after a checkout so in case there are any issues with submission they are able to contact us with a session ID and we can fix them.

Thanks to the simple approach, Netlify's fantastic serverless functions abstractions and the robustness of all of the providers used we had no issues with this process. But if users were struggling we would have been alerted by our Sentry integration.


I really enjoyed working through this feature with both Claude and Codex in the CLI and the cloud. Whereas previously it's easy to get stuck on small config snags which get in the way of shipping now this problem has been basically solved by AI coding assistants which gave me time to concentrate on the architecture, design and actual fun bits of coding. Not only was I able to ship this feature way quicker than previously before, I was able to enjoy doing it too.