This is an example application for:
- Learning basics of how modern web applications are built with HTML, CSS, JavaScript, servers, and databases.
- Deploying something a little more advanced than a Hello world! page or unconfigured nginx server.
- Deploying a minimal production like application.
To run the application on your machine, you will need Docker Compose. You can either install it manually or by using Docker Desktop (see also Installing Docker).
To start the application, run docker compose up -d
. This will build the container images and start the containers in the background. The application should be soon available in http://localhost:8080. The API container will create two demo forms, which are available in /thumbs and /weather paths.
docker compose up -d
If you want to inspect the admin panel, print out the content of /var/feedback/initial_admin_password
in the api
container with docker compose exec
for the initial admin account password. Admin panel is available in http://localhost:8080/admin and the username for the admin account is admin
.
docker compose exec api cat /var/feedback/initial_admin_password
For a more production like deployment, there is an OpenTofu/Terraform configuration example in iac/tf directory.
The application is built using a three-tier architecture. I.e., the application consists of presentation tier, application tier and a data tier.
flowchart LR
subgraph d [Data tier]
db["Database<br>_(Postgres)_"]
end
subgraph a ["Application tier<br>_(Gunicorn server)_"]
a_whitespace:::hidden
admin[Admin interface]
API["API<br>_(Django application)_"]
static_build[Static files]
end
subgraph p ["Presentation tier<br>_(Nginx server)_"]
p_whitespace:::hidden
root["/ _(Svelte application)_"]
api_proxy["/api"]
admin_proxy["/admin"]
static["/static"]
end
Browser--Static web page-->root
Browser--Dynamic web page-->admin_proxy
Browser-.->api_proxy
Browser-.->static
admin_proxy--proxy_pass-->admin
api_proxy--proxy_pass-->API
static -.docker build.- static_build
admin-->db
API-->db
classDef hidden display: none;
The end-user facing user interface (UI) of the application is implemented as Svelte application in front-end directory. Svelte is a JavaScript user-interface (UI) framework used to build the HTML, JavaScript, and CSS files that the browser renders and runs on the users machine.
The HTML, JavaScript, and CSS files that implement the user UI are delivered to the end-users browser by an static file server. This application uses nginx which, in addition to hosting the static files, acts as a reverse proxy towards the application layer: when the user interacts with the application, the browser contacts the presentation tier which then proxies the requests to application tier.
The presentation tier of an web application can be implemented either as a static or a dynamic web page. This application provides example for both of these: the end-user facing application is a static web page and the admin panel is a dynamic web page.
The word static in static web page means that the files served to the browser are always the same regardless of the user or status of the server. This does not mean that the web page could not be interactive. Many static web pages include JavaScript logic that can change the content of the page from within the web browser by utilizing, for example, calls to a API of a web application.
To summarize, the initial page load will be the same for all users, but the page might use client side logic and API calls to add interaction and to personalize the content visible to the user.
Dynamic web pages, on the other hand, are created dynamically by the web server varying on, for example, the user making requesting the page or the status of the server. Thus, the content returned to the browser when loading the page will already be personalized on the server side.
Dynamic web pages often also utilize static content, such as stylesheets and images, to make the page load more efficient. The static content is usually served to the end-user by a static file server instead of the application server. In this application, the static filed required by the admin panel are copied to the nginx server during the Docker build process and served to the end-user from under /static
path of the server.
The application tier of the application is implemented with Django in back-end directory. Django is a Python web framework that could be used to implement both presentation and the application tiers as well as managing the data tier. In this project it implements the application programming interface (API), handles interaction with the database, and provides an administrator panel for managing the data stored in the database.
The Django application is exposed using a Gunicorn server that handles incoming connections using multiple worker threads. I.e., Gunicorn implements a production ready webserver where as the Django application is responsible for implementing the application logic behind the server. Gunicorn server communicates with the Django application using WSGI, a standardized interface for connecting web servers to applications.
The data tier of the application is provided by Postgres SQL database.