# studio einszwovier Web Application
**FastAPI-based PDF print cost calculator** with automated ink coverage analysis, Matrix integration, and multi-service hub for studio einszwovier Maker Space.
[](https://www.docker.com/)
[](https://fastapi.tiangolo.com/)
[](https://matrix.org/)
---
## ๐ฏ Features
### Core Application
- **๐ PDF Cost Calculator**: Automated ink coverage analysis with color/B&W detection
- **๐ผ๏ธ Course Management**: Dynamic course list with image gallery and modal viewer
- **๐ Cost Estimation**: Per-page breakdown with configurable rates (โฌ/mยฒ)
- **๐ฌ Matrix Integration**: Automatic order submission to Matrix room
### Integrated Services
- **๐ BookStack Wiki**: Documentation and knowledge base (port 6875)
- **๐ค Ollama + Open WebUI**: Local LLM chatbot interface (port 8080)
- **๐จ Matrix Synapse**: Print order collection and payment tracking (port 8008)
- **๏ฟฝ Element Web**: Browser-based Matrix chat client (port 8082)
- **๏ฟฝ๐ณ Portainer**: Container management dashboard (port 9000)
- **๐ JupyterHub**: Multi-user Jupyter notebook server for drone programming (port 8001)
- **๐ฆ Forgejo**: Self-hosted Git service for code collaboration (port 3003)
- **๐ Watchtower**: Automatic container updates every 24 hours
- **๐๏ธ Autokanban**: Kollektive ToโDoโListe / Aufgabenboard (port 8000)
---
## ๐๏ธ Architecture

View Mermaid source code
```mermaid
graph TB
subgraph "studio einszwovier Web Platform"
LP[๐ Landing Page
Port 80]
About[โน๏ธ About Page
/about]
CostCalc[๐ฐ Cost Calculator
/cost]
LP --> About
LP --> CostCalc
end
subgraph "Services Accessible from Landing Page"
BookStack[๏ฟฝ BookStack
Port 6875
Wissenssammlung]
OpenWebUI[๐ค Open WebUI
Port 8080
LLM Chatbot]
JupyterHub[๏ฟฝ JupyterHub
Port 8001
Python Notebooks]
Forgejo[๐ฆ Forgejo
Port 3003
Git Server]
ElementWeb[๏ฟฝ Element Web
Port 8082
Matrix Chat]
Portainer[๏ฟฝ Portainer
Port 9000
Admin Panel]
LP -.->|Link| BookStack
LP -.->|Link| OpenWebUI
LP -.->|Link| JupyterHub
LP -.->|Link| Forgejo
LP -.->|Link| ElementWeb
LP -.->|Link| Portainer
end
subgraph "Backend Services"
Synapse[๏ฟฝ Synapse
Port 8008
Matrix Server]
Ollama[๐ฎ Ollama
Port 11434
LLM Engine]
MariaDB[(๏ฟฝ MariaDB
BookStack DB)]
ElementWeb --> Synapse
OpenWebUI --> Ollama
BookStack --> MariaDB
CostCalc --> Synapse
end
subgraph "Educational Resources"
Notebooks[๐ Drone Programming
djitellopy Package]
GitRepos[๐ฆ Code Repositories
Project Source]
Knowledge[๏ฟฝ Documentation
Guides & Tutorials]
JupyterHub --> Notebooks
Forgejo --> GitRepos
BookStack --> Knowledge
end
subgraph "Persistent Storage"
PDFUploads[๐ PDF Files
data/uploads/]
CoursesCSV[๐ Courses CSV
data/courses.csv]
MatrixData[(๐๏ธ Matrix Data
matrix/data/)]
JupyterVols[(๐พ Jupyter Volumes
User Workspaces)]
ForgejoData[(๐ Forgejo Data
forgejo/data/)]
CostCalc --> PDFUploads
About --> CoursesCSV
Synapse --> MatrixData
JupyterHub --> JupyterVols
Forgejo --> ForgejoData
end
subgraph "Infrastructure"
Watchtower[๐ Watchtower
Auto-Updates
Every 24h]
Network[๐ einszwovier_network
Docker Network]
end
classDef webapp fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef service fill:#fff3e0,stroke:#f57c00,stroke-width:2px
classDef backend fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef storage fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef edu fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef infra fill:#fafafa,stroke:#616161,stroke-width:2px
class LP,About,CostCalc webapp
class BookStack,OpenWebUI,JupyterHub,Forgejo,ElementWeb,Portainer service
class Synapse,Ollama,MariaDB backend
class PDFUploads,CoursesCSV,MatrixData,JupyterVols,ForgejoData storage
class Notebooks,GitRepos,Knowledge edu
class Watchtower,Network infra
```
---
## ๐ Quick Start
### Prerequisites
**On the host system:**
- **Docker** & **Docker Compose** installed
- **curl** - for testing and healthchecks (install: `brew install curl` on macOS)
- **Poppler** (for pdf2image - included in Docker)
- **Port availability**: 80, 3003, 6875, 8001, 8008, 8080, 8082, 9000, 11434
- **Port availability**: 80, 3003, 6875, 8000, 8001, 8008, 8080, 8082, 9000, 11434
**Note:** Python dependencies are containerized and don't need to be installed on the host.
### Installation
1. **Clone the repository:**
```bash
git clone https://github.com/arontaupe/124-webapp.git
cd 124-webapp
```
2. **Configure environment:**
```bash
cp .env.example .env
nano .env # Update SERVER_HOSTNAME and passwords
```
3. **Start the stack:**
```bash
docker compose up -d --build
```
4. **Access services:**
- Web App: (or )
- BookStack:
- Open WebUI:
- Portainer:
- Matrix:
- Element Web:
- Autokanban:
- JupyterHub:
- Forgejo:
### First-Time Setup
1. **Get Matrix Room ID:**
```bash
python get_room_id.py
```
2. **Update .env with room ID:**
```bash
MATRIX_ROOM="!YourRoomID:${SERVER_HOSTNAME}"
```
3. **Restart web container:**
```bash
docker compose restart web
```
---
## ๐ Course Management
Courses are managed via CSV file with optional images:
### Add a Course
1. **Edit `data/courses.csv`:**
```csv
title,description,dates,offen_fuer,image
My Course,Learn cool stuff,"Oct '25",Grade 10,/static/images/courses/my-course.jpg
```
2. **Add course image (optional):**
```bash
cp my-image.jpg static/images/courses/my-course.jpg
```
3. **Changes apply immediately** (no restart needed)
### Course Image Features
- **Thumbnail view**: 80x80px next to course info
- **Hover zoom**: Expands to 200x200px on hover
- **Click to enlarge**: Opens full-size modal viewer
- **Auto-cropping**: `object-fit: cover` ensures uniform display
See [data/KURSE_README.md](data/KURSE_README.md) for detailed documentation.
---
## ๐ง Configuration
### Environment Variables
Key variables in `.env`:
```bash
# Server Configuration
SERVER_HOSTNAME=your-server.com
# Print Rates (โฌ/mยฒ)
RATE_PER_M2_BLACK=4.0
RATE_PER_M2_COLOR=5.0
# Matrix Integration
MATRIX_USER="@einszwovier:${SERVER_HOSTNAME}"
MATRIX_PASS="your_password"
MATRIX_HOMESERVER="http://${SERVER_HOSTNAME}:8008"
MATRIX_ROOM="!RoomID:${SERVER_HOSTNAME}"
# Service Ports
SYNAPSE_PORT=8008
OLLAMA_PORT=11434
OPENWEBUI_PORT=8080
BOOKSTACK_PORT=6875
PORTAINER_PORT=9000
JUPYTER_PORT=8001
FORGEJO_PORT=3003
# JupyterHub Authentication
JUPYTER_PASSWORD=einszwo4
```
See [.env.example](.env.example) for full configuration.
---
## ๐ณ Docker Services
| Service | Image | Port | Purpose | Resources |
|---------|-------|------|---------|-----------|
| **web** | Custom (FastAPI) | 80 | Main application | 1 CPU, 1GB RAM |
| **synapse** | matrixdotorg/synapse | 8008 | Matrix homeserver | 2 CPU, 2GB RAM |
| **ollama** | ollama/ollama | 11434 | LLM inference | 6 CPU, 16GB RAM |
| **open-webui** | ghcr.io/open-webui/open-webui | 8080 | LLM chat UI | 2 CPU, 2GB RAM |
| **bookstack** | lscr.io/linuxserver/bookstack | 6875 | Documentation wiki | Default |
| **bookstack-mariadb** | lscr.io/linuxserver/mariadb | 3306 | Database for BookStack | Default |
| **jupyterhub** | Custom (Python 3.13) | 8001 | Multi-user Jupyter notebooks | 2 CPU, 2GB RAM |
| **forgejo** | codeberg.org/forgejo/forgejo:11 | 3003, 222 | Git service (web, SSH) | Default |
| **portainer** | portainer/portainer-ce | 9000, 9443 | Container management | Default |
| **watchtower** | containrrr/watchtower | - | Auto-updates (24h) | Default |
### Health Checks
All services have health checks configured:
- **web**: `curl http://localhost:8000/`
- **synapse**: `curl http://localhost:8008/_matrix/static/`
- **ollama**: `curl http://localhost:11434/`
- **open-webui**: `curl http://localhost:8080/`
- **bookstack**: `curl http://localhost/`
- **mariadb**: MariaDB query test
- **portainer**: API status check
- **watchtower**: Process check
---
## ๐ Documentation
- **[SECURITY.md](SECURITY.md)** - Security best practices and secrets management
- **[PORTABILITY.md](PORTABILITY.md)** - Server migration guide
- **[PRE_RELEASE_CHECKLIST.md](PRE_RELEASE_CHECKLIST.md)** - Pre-publication verification
- **[data/KURSE_README.md](data/KURSE_README.md)** - Course management guide
---
## ๐ Security
**Before deploying to production:**
1. โ
Change all passwords in `.env`
2. โ
Generate new `BOOKSTACK_APP_KEY`
3. โ
Update Matrix credentials
4. โ
Configure firewall (restrict Portainer access)
5. โ
Set up HTTPS/SSL
6. โ
Enable automated backups
See [SECURITY.md](SECURITY.md) for comprehensive security guidelines.
**Security Disclosure:** If you discover a vulnerability, email `einszwovier@gvb-gymnasium.de` instead of opening a public issue.
---
## ๐ Backup & Restore
### Backup All Data
```bash
./backup.sh
```
Creates timestamped backups of:
- BookStack database & files
- Matrix homeserver data
- PDF uploads
- Course data & images
- Environment configuration
### Restore from Backup
```bash
./restore.sh YYYYMMDD_HHMMSS
```
---
## ๏ฟฝ BookStack API (create pages programmatically)
You can automate content creation in BookStack using the HTTP API and a Personal Access Token (User Settings โ API Tokens).
Example `curl` to list books:
```bash
curl -H "Authorization: Token token=\"$BOOKSTACK_API_TOKEN\"" \
"$BOOKSTACK_APP_URL/api/books"
```
Create a page with `curl`:
```bash
curl -X POST -H "Authorization: Token token=\"$BOOKSTACK_API_TOKEN\"" \
-H "Content-Type: application/json" \
-d '{"name":"My Page","book_id":1,"html":"Hello
"}' \
"$BOOKSTACK_APP_URL/api/pages"
```
There's a small helper script in the repo: `bookstack_api_create_page.py` which demonstrates listing books and creating a page interactively.
---
## ๏ฟฝ๐ข Deployment & Portability
This application is designed to be **fully portable**. To move to a new server:
1. **On old server:**
```bash
./backup.sh
```
2. **On new server:**
```bash
git clone
cd 124-webapp
cp .env.example .env
# Update SERVER_HOSTNAME in .env
./restore.sh YYYYMMDD_HHMMSS
docker compose up -d
```
See [PORTABILITY.md](PORTABILITY.md) for detailed migration guide.
---
## ๐ ๏ธ Development
### Local Development
```bash
# Option 1: Direct Python (with auto-reload)
python run_app.py
# Option 2: Docker Compose
docker compose up --build
```
### Project Structure
```zsh
.
โโโ main.py # FastAPI application
โโโ cost_calculator.py # PDF analysis logic
โโโ mailer.py # Matrix integration
โโโ templates/ # Jinja2 templates
โ โโโ base.html
โ โโโ landing.html
โ โโโ about.html
โ โโโ cost-calculator.html
โ โโโ result.html
โโโ static/ # CSS, images, fonts
โ โโโ css/style.css
โ โโโ images/
โ โโโ fonts/
โโโ data/
โ โโโ courses.csv # Course database
โ โโโ uploads/ # PDF uploads
โโโ docker-compose.yml # Service orchestration
โโโ Dockerfile # Web app container
โโโ requirements.txt # Python dependencies
```
### Key Technologies
- **FastAPI** - Modern Python web framework
- **PyPDF2** - PDF metadata extraction
- **pdf2image** - PDF to image conversion
- **Pillow + NumPy** - Image processing & ink analysis
- **matrix-nio** - Matrix protocol client
- **Jinja2** - Template engine
- **Gunicorn + Uvicorn** - Production WSGI/ASGI servers
---
## ๐ค Contributing
Contributions are welcome! This is part of **studio einszwovier**, a collaborative Maker Space.
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
---
## ๐ License
This project is part of studio einszwovier educational initiative.
---
## ๐ Contact
**studio einszwovier**
Gabriele-von-Bรผlow-Gymnasium
Tile-Brรผgge-Weg 63, 13509 Berlin (Tegel)
- **Email**:
- **Team**: Aron Petau & Friedrich Weber
- **Hours**: Tuesday - Thursday, 11:00 - 16:00
- **Location**: Room 124
---
## ๐ Acknowledgments
- Matrix.org for the communication protocol
- Ollama team for local LLM support
- BookStack for the documentation platform
- FastAPI community
- All contributors and students of studio einszwovier
---
Made with โค๏ธ at studio einszwovier Maker Space