docs: complete project research

Adds STACK, FEATURES, ARCHITECTURE, PITFALLS, and SUMMARY research files
covering the full ImpTune technology stack, feature set, architecture
patterns, and critical pitfalls for the printer deployment package generator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 10:34:25 +02:00
co-authored by Claude Sonnet 4.6
parent 67a54673e2
commit 59c384ed13
4 changed files with 1026 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
# Stack Research
**Domain:** Self-hosted single-container internal tool — Windows printer deployment package generator
**Researched:** 2026-04-10
**Confidence:** HIGH (core stack), MEDIUM (.intunewin reimplementation specifics)
---
## Recommended Stack
### Core Technologies
| Technology | Version | Purpose | Why Recommended |
|------------|---------|---------|-----------------|
| Python | 3.12 | Runtime | LTS-stable, broad library support, zipfile/cryptography stdlib covers .intunewin needs without C extensions. 3.13 is fine too; avoid 3.11 and below (FastAPI 0.130+ requires 3.10+ but 3.12 is the sweet spot for Docker image size vs feature parity). |
| FastAPI | 0.115.x (latest stable) | HTTP framework + API | De-facto standard for Python internal tools in 2025. Async-capable, Pydantic validation built-in, native file upload/download support, StreamingResponse for generated archives. Simpler than Django for this scope; more structured than Flask. |
| Uvicorn | 0.30.x | ASGI server | FastAPI's recommended server. Handles subprocess management internally — Gunicorn is not needed for a single-container internal tool with no concurrency requirements. |
| Jinja2 | 3.1.x | Server-side HTML templating | Ships with FastAPI's template support. No build step, no Node. HTMX+Jinja2 renders the full UI from the server. |
| HTMX | 2.0.x (CDN) | Dynamic UI without JavaScript SPA | Handles partial page updates (form submissions, driver list refresh, package generation progress) with zero build tooling. Ideal for CRUD-heavy internal tools. Single `<script>` tag. |
| Alpine.js | 3.x (CDN) | Client-side UI state | Complements HTMX: dropdowns, modals, toggle states, file-input previews. Replaces React/Vue for this scope. No npm, no bundler. |
| SQLite (stdlib) | 3.x (bundled) | Persistence: driver records, printer configs | No external database process. Python's built-in `sqlite3` module is sufficient for sync operations. Single-writer model is not a concern for a single-user internal tool. Mount via Docker named volume. |
| Tailwind CSS | 4.x (CDN Play) | Utility-first CSS | For an internal tool with no public users, the CDN Play script is acceptable. It avoids a Node.js build step inside the Docker image. If CSS size ever matters, switch to the standalone Tailwind CLI binary (no Node required). |
### Supporting Libraries
| Library | Version | Purpose | When to Use |
|---------|---------|---------|-------------|
| `python-multipart` | 0.0.9 | Multipart file upload parsing | Required by FastAPI for `UploadFile`. Always install alongside FastAPI when handling file uploads. |
| `pycryptodome` | 3.20.x | AES-256-CBC + HMAC-SHA256 for .intunewin encryption | The .intunewin inner package is encrypted with AES-256-CBC; the HMAC-SHA256 digest is written to Detection.xml. Use pycryptodome (not the deprecated pycrypto). |
| `lxml` or `xml.etree.ElementTree` (stdlib) | stdlib | Generate Detection.xml metadata | Detection.xml is simple enough for stdlib ElementTree. Only reach for lxml if namespaces become complex. |
| `aiofiles` | 23.x | Async file I/O | Used with FastAPI's StreamingResponse when streaming generated ZIPs to the browser without loading the full archive into memory. |
| `python-dotenv` | 1.0.x | Environment-based configuration | Allows Docker-level config overrides (data directory, port, base URL) without rebuilding the image. |
| `peewee` | 3.17.x | ORM for SQLite | Lightweight sync ORM — perfectly matched to SQLite's single-writer model. Avoids the async overhead of SQLModel/aiosqlite, which provides no benefit with SQLite. Use only if raw `sqlite3` becomes unwieldy across multiple tables. |
### Development Tools
| Tool | Purpose | Notes |
|------|---------|-------|
| Docker (python:3.12-slim-bookworm) | Container base image | Slim variant keeps image under 200 MB. Bookworm (Debian 12) has modern glibc. Do NOT use Alpine Linux — pycryptodome and other C-extension wheels often lack musl-compatible builds, causing silent failures. |
| `uvicorn --reload` | Dev server with hot reload | Run locally during development. In Docker, use `CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]` without `--reload`. |
| Docker named volume | Driver + SQLite persistence | Mount `/data` as a named volume. Store driver ZIPs and the SQLite file there. Never store state in the container filesystem. |
---
## Installation
```bash
# Core runtime
pip install fastapi==0.115.* uvicorn[standard]==0.30.* jinja2==3.1.* python-multipart==0.0.9
# File generation and encryption
pip install pycryptodome==3.20.* aiofiles==23.*
# Configuration + optional ORM
pip install python-dotenv==1.0.* peewee==3.17.*
# Dev only
pip install httpx pytest pytest-asyncio
```
Tailwind CSS and HTMX are loaded from CDN in templates — no npm install.
---
## Alternatives Considered
| Recommended | Alternative | When to Use Alternative |
|-------------|-------------|-------------------------|
| FastAPI + Jinja2 + HTMX | Django + django-htmx | If the project grows to need Django admin, multi-tenant auth, or complex ORM migrations. Overkill for this scope. |
| FastAPI + Jinja2 + HTMX | FastAPI + React/Vue SPA | If the UI needs real-time collaborative editing or complex client-side state (drag-and-drop ordering, offline mode). Not needed here. |
| Python (FastAPI) | Go (Gin/Chi) | If single binary with no runtime dependency is the top priority. Go produces a smaller Docker image but adds complexity for the .intunewin crypto/zip logic that Python stdlib already handles. |
| pycryptodome | cryptography (PyCA) | `cryptography` is fine too and arguably better maintained. Either works for AES-CBC. Prefer `cryptography` if you want FIPS-like assurance; pycryptodome is simpler to use for this exact pattern (CBC + HMAC). |
| SQLite (builtin / peewee) | PostgreSQL | If multi-user write concurrency is ever needed. Not the case here. |
| Tailwind CDN | Tailwind standalone CLI | Use the standalone CLI binary (no Node) if you want purged, production-sized CSS. Drop the `tailwindcss` binary into the Docker image at build time. Adds ~10 MB to the image but removes CDN dependency. |
| python:3.12-slim-bookworm | python:3.12-alpine | Alpine breaks C-extension wheels. Slim Debian is the correct base for any project using pycryptodome or similar. |
---
## What NOT to Use
| Avoid | Why | Use Instead |
|-------|-----|-------------|
| IntuneWinAppUtil.exe inside Docker | It is a Windows PE binary. It will not run in a Linux container. Even Wine would add hundreds of MB and introduce instability. | Reimplement the format in Python: `zipfile` (stdlib) for inner ZIP with `ZIP_STORED`, `pycryptodome` for AES-256-CBC encryption, `xml.etree.ElementTree` for Detection.xml. The format is fully documented by reverse engineering (svrooij.io). |
| Alpine Linux base image | musl libc breaks pre-built wheels for pycryptodome and other C-extension packages, causing pip to fall back to source builds or fail silently. | `python:3.12-slim-bookworm` — Debian-based, glibc, pre-built wheels always work. |
| Celery / Redis / task queue | Massively overengineered for a single-user internal tool. .intunewin generation takes < 5 seconds per package. | FastAPI `BackgroundTasks` is sufficient for post-response cleanup; synchronous generation on the request thread is fine. |
| SQLAlchemy async (aiosqlite) | Async gives zero throughput benefit with SQLite (single-writer lock). Adds complexity for no gain. | Synchronous `sqlite3` stdlib or `peewee`. Run database calls synchronously inside `asyncio.run_in_executor` if truly needed. |
| React / Vue / Next.js | Requires a Node.js build pipeline in the Docker image, a separate frontend build stage, and a JS bundle. Unnecessary complexity for an internal CRUD tool. | HTMX + Alpine.js served from Jinja2 templates. No build step. |
| PyCrypto (original) | Unmaintained since 2012. Known vulnerabilities. | `pycryptodome` — a maintained drop-in replacement. |
---
## Stack Patterns by Variant
**If .intunewin generation needs to stay on the request thread (simplest path):**
- Generate the .intunewin file synchronously, stream it with `FileResponse` or `StreamingResponse`, then delete the temp file with `BackgroundTasks`.
- No async file I/O needed for packages under ~500 MB.
**If driver ZIPs are very large (>500 MB) and upload times block Uvicorn:**
- Use `aiofiles` for async reads during upload processing.
- Uvicorn is single-threaded by default in development; add `--workers 2` in production Dockerfile if needed (though unlikely for an internal tool).
**If Tailwind CDN becomes a problem (slow intranet, offline use):**
- Download the Tailwind standalone CLI (`tailwindcss-linux-x64`) into the Docker image during build.
- Run `tailwindcss -i input.css -o static/output.css --minify` as a Dockerfile `RUN` step.
- Serve the generated CSS as a static file. Zero Node.js required.
---
## .intunewin Reimplementation (Critical Detail)
The official `IntuneWinAppUtil.exe` is Windows-only. The format is well-documented through reverse engineering:
1. **Inner ZIP** — compress source folder using `zipfile.ZipFile(..., compression=ZIP_DEFLATED)` (note: unlike the outer ZIP, the inner package uses DEFLATE not STORED)
2. **Encrypt** — AES-256-CBC with a random 32-byte key and 32-byte IV; prepend HMAC-SHA256 (32 bytes) then IV (32 bytes) to the ciphertext
3. **Detection.xml** — XML file with base64-encoded EncryptionKey, InitializationVector, Mac (HMAC), FileDigest (SHA256 of plaintext), FileDigestAlgorithm ("SHA256"), and ProfileIdentifier ("ProfileVersion1")
4. **Outer ZIP** — ZIP_STORED containing `IntuneWinPackage/Contents/IntunePackage.intunewin` (the encrypted blob) and `IntuneWinPackage/Metadata/Detection.xml`
Reference implementation: [svrooij.io — Creating IntuneWin files with C#](https://svrooij.io/2023/10/24/create-intunewin-file/) — the logic is language-agnostic and Python stdlib + pycryptodome covers all requirements. **Confidence: MEDIUM** (based on reverse-engineering documentation; validate against a real Intune upload during Phase 1).
---
## Version Compatibility
| Package | Compatible With | Notes |
|---------|-----------------|-------|
| fastapi 0.115.x | pydantic 2.x | FastAPI 0.115+ requires Pydantic v2. Do not mix with Pydantic v1. |
| pycryptodome 3.20.x | Python 3.12, 3.13 | Use `pycryptodome` not `pycryptodomex` (different package name, same code, different import path). Import as `from Crypto.Cipher import AES`. |
| uvicorn 0.30.x | fastapi 0.115.x | Compatible. Use `uvicorn[standard]` to include `uvloop` and `httptools` for better performance. |
| peewee 3.17.x | Python 3.12 | Sync only. Does not conflict with FastAPI's async model — call peewee from sync functions or `run_in_executor`. |
| Tailwind CDN v4 | Any browser | Play CDN is development-only per Tailwind docs. For production isolation, use standalone CLI instead. |
---
## Sources
- [FastAPI Deployment with Docker — Official Docs](https://fastapi.tiangolo.com/deployment/docker/) — Docker patterns, Uvicorn configuration
- [FastAPI Templates — Official Docs](https://fastapi.tiangolo.com/advanced/templates/) — Jinja2 integration
- [svrooij.io — Creating IntuneWin files with C#](https://svrooij.io/2023/10/24/create-intunewin-file/) — .intunewin format reference (MEDIUM confidence, reverse-engineered)
- [svrooij.io — Decrypting intunewin files](https://svrooij.io/2023/10/09/decrypting-intunewin-files/) — Encryption structure validation
- [SvRooij.ContentPrep on NuGet](https://www.nuget.org/packages/SvRooij.ContentPrep) — Cross-platform C# reference implementation, last updated 2025-10-03
- [PyCryptodome docs](https://pycryptodome.readthedocs.io/en/latest/src/examples.html) — AES-CBC usage
- [Python zipfile docs](https://docs.python.org/3/library/zipfile.html) — ZIP_STORED / ZIP_DEFLATED constants
- [HTMX + FastAPI patterns 2025](https://johal.in/htmx-fastapi-patterns-hypermedia-driven-single-page-applications-2025/) — HTMX suitability for internal tools
- [Python 2025 Web Stack — Medium](https://medium.com/@hadiyolworld007/pythons-2025-web-stack-fastapi-sqlmodel-and-htmx-changed-everything-58cc2da1cf14) — FastAPI + HTMX ecosystem confirmation
- [Tailwind Play CDN docs](https://tailwindcss.com/docs/installation/play-cdn) — CDN limitations for production
- [Docker Volumes for SQLite](https://dev.to/behainguyen/python-docker-volumes-where-is-my-sqlite-database-file-48fd) — Named volume pattern
- WebSearch (multiple queries, 2026-04-10) — ecosystem verification
---
*Stack research for: ImpTune — printer deployment package generator*
*Researched: 2026-04-10*