Multi-page website for a premium furniture brand — Django REST Framework backend, Nuxt 3 storefront rendered server-side, shipped by CI to a production server as three Docker images.
Commercial project, live at ters.gallery.
The client manages the whole catalogue from the Django admin — collections, products, materials, colours, image galleries, and the copy on the About page — without touching code. The storefront reads it through a REST API and renders on the server, so product pages arrive as HTML for search engines and for a fast first paint.
Content model. Collection groups products; each Product carries
materials, colours and an ordered set of ProductImages. AboutPageSettings
makes the About page editable content rather than markup, with rich text through
CKEditor 5 and drag-and-drop ordering in the admin.
API. Read endpoints for the storefront, documented and browsable:
| Endpoint | Returns |
|---|---|
GET /collections/ |
all collections |
GET /collections/main/ |
the collection featured on the homepage |
GET /products/ |
product list |
GET /products/<id>/ |
one product with images and attributes |
GET /materials/ |
material reference |
GET /about/ |
About page content |
GET /schema/ · /schema/swagger-ui/ |
OpenAPI schema and Swagger UI |
The schema is generated by drf-spectacular from the serialisers, so the docs cannot drift from the code.
Nginx ──▶ Nuxt 3 SSR ──▶ Django REST Framework ──▶ PostgreSQL
(storefront) (API + admin, gunicorn)
Three images — frontend, backend, nginx — built in parallel by CI and composed on the server. Nginx terminates requests and serves uploaded media directly rather than through the application.
Backend · Django 5.2 · Django REST Framework · drf-spectacular · djoser · django-ckeditor-5 · django-admin-sortable2 · gunicorn · Python 3.13
Frontend · Nuxt 3 · Vue 3 · @nuxt/image · Swiper · Sass
Infrastructure · Docker · Docker Compose · Nginx · GitHub Actions
Two chained workflows:
- Build & Push — on every push to
master, Buildx (with QEMU for cross-platform builds) builds the frontend, backend and nginx images and pushes each to Docker Hub tagged bothlatestand the commit SHA, so any deploy can be traced back to its commit. - Deploy — triggered by
workflow_runonly when the build succeeded. Copies the production compose file to the server over SCP and restarts the stack over SSH.
All hosts and credentials come from GitHub Secrets.
docker compose up -dBrings up the backend, the Nuxt dev server and PostgreSQL. Create an admin user to reach the Django admin:
docker compose exec backend python src/manage.py createsuperuserProduction uses docker-compose.prod.yml, which pulls the published images
instead of building locally.