A couple months ago I was approached by a friend and designer that asked if I was interested in building a custom web app for a local coach/consultant. The client needed a secure way to share information with their customers, manage access to resources they have created and curated while reducing the amount of work compared to using a traditional file-sharing service.
Given these requirements and a need to keep labor costs down, I chose to use a familiar framework, Django. The app would be hosted on Heroku and use AWS services for the database and file storage. Because the app will not be used heavily and doesn’t hold much state information outside of session variables, there is no need for replication or a shared cache. These options allowed me to iterate quickly and efficiently.
Instead of taking the time to design a custom user interface, we decided to make small changes to Dashkit, a Bootstrap-based dashboard template. All the changes were to match the styles of the client’s website.
I created custom authentication, profile, and error pages so that the client’s customers won’t have to interact with any of the default Django admin pages (which were left unmodified).
The Django app is straightforward. This could’ve been integrated into the client’s website if resources were not client specific. Because of that requirement, the only advanced feature I used was a many-to-one and one-to-one references between data model items.
One of the more difficult areas of the project was extending Django’s built-in user model and getting everything working correctly in the admin panel. I ended up learning a lot about this process and it will be a breeze next time.
To keep things simple, the app is served by Gunicorn and static files by Whitenoise. I also used Sentry for errors, Timber for logging, and SendGrid for any emails. These integrations were chosen for ease of setup and use.
The single biggest problem I had to solve was handling file uploads. Because the app was running on Heroku I didn’t have a persistent file system to use Django’s built-in media folder. I ended up finding a great library called django-s3direct that did the heavy lifting for me. I spend a lot of time figuring out how to get the CORS headers working with my development environment.
Doing it again, I would have spent more time on the client side, picking a more minimalist CSS library and optimizing load times.
Complete source code and demo available upon request.