From b65035719433f2ee4c56d8c25d646ad7fca68d97 Mon Sep 17 00:00:00 2001 From: AppFactory Bot Date: Thu, 16 Jul 2026 09:48:36 +0000 Subject: [PATCH] Initial PPL CPL API --- .gitignore | 176 +++++++++++++++++++++++ AGENTS.md | 353 +++++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 12 ++ README.md | 3 + app.yml | 7 + app/main.py | 25 ++++ requirements.txt | 2 + 7 files changed, 578 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 app.yml create mode 100644 app/main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36b13f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,176 @@ +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ad89362 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,353 @@ +# AGENTS.md + +Tento repozitář obsahuje aplikaci běžící v AppFactory. + +Tento soubor je určený pro AI asistenty, vývojáře a automatizované nástroje, které budou aplikaci upravovat. + +## Kontext AppFactory + +Aplikace běží jako Docker container spravovaný AppFactory. + +AppFactory zajišťuje: + +- vytvoření Gitea repozitáře +- webhook z Gitea do AppFactory +- build Docker image +- deploy containeru +- reverse proxy přes Caddy +- runtime variables a secrets přes environment variables +- monitoring přes health endpoint + +Aplikační repozitář nemá měnit infrastrukturu AppFactory. + +## Veřejná URL a reverse proxy + +Aplikace neběží v rootu domény. + +Veřejná URL aplikace má tvar: + +```text +https://services.csbot.cz/apps/ +``` + +Příklady: + +```text +https://services.csbot.cz/apps/test-dotnet-api +https://services.csbot.cz/apps/microsoft-365-service +``` + +Aplikace musí počítat s tím, že běží za reverse proxy. + +Nikdy nehardcoduj veřejnou doménu. + +Nikdy nehardcoduj `/apps/` do business logiky, pokud framework nabízí lepší mechanismus, například: + +- `ROOT_PATH` +- `PathBase` +- `basePath` +- OpenAPI `servers` +- Swagger route prefix +- framework-specific proxy/base URL nastavení + +## Caddy routing + +AppFactory Caddy routuje aplikace přes: + +```text +/apps/ +``` + +Typicky platí: + +```text +veřejný request: +GET /apps//contacts + +aplikace uvnitř containeru často vidí: +GET /contacts +``` + +Důvodem je použití reverse proxy route typu `handle_path`, která prefix `/apps/` odstraní před předáním do containeru. + +Aplikace proto musí být napsaná tak, aby: + +- správně obsloužila interní routy +- správně generovala dokumentaci pro veřejnou proxy cestu +- Swagger UI testování používalo veřejnou cestu s `/apps/` + +## Povinné endpointy + +Každá služba musí poskytovat: + +```text +GET /health +GET /docs +``` + +Z veřejné URL musí být dostupné jako: + +```text +GET /apps//health +GET /apps//docs +``` + +`/health` musí vracet HTTP 200, pokud je aplikace schopná přijímat provoz. + +`/docs` musí poskytovat Swagger/OpenAPI dokumentaci nebo obdobnou interaktivní dokumentaci API. + +Pokud služba není HTTP API, musí i tak poskytovat minimální HTTP health endpoint. + +## Swagger / OpenAPI pravidla + +Swagger UI a OpenAPI definice musí respektovat AppFactory reverse proxy prefix. + +Pokud aplikace běží veřejně na: + +```text +https://services.csbot.cz/apps/ +``` + +pak Swagger UI musí při testování endpointů volat stejný prefix. + +Špatně: + +```text +GET https://services.csbot.cz/contacts +``` + +Správně: + +```text +GET https://services.csbot.cz/apps//contacts +``` + +Po každé úpravě API je povinné ověřit: + +1. `/health` funguje +2. `/docs` funguje +3. Swagger UI se načte +4. Swagger UI `Try it out` volá endpointy přes `/apps/` +5. OpenAPI JSON obsahuje správný server/base path +6. Nově přidané endpointy jsou ve Swagger dokumentaci + +Pokud framework generuje OpenAPI `servers`, musí obsahovat proxy prefix. + +Příklad: + +```json +{ + "servers": [ + { + "url": "/apps/" + } + ] +} +``` + +Nesmí vzniknout stav, kdy Swagger UI vypadá správně, ale tlačítko `Try it out` volá endpointy bez `/apps/`. + +## ROOT_PATH / PathBase + +AppFactory může aplikaci předávat environment variable: + +```text +ROOT_PATH=/apps/ +``` + +Použití závisí na frameworku. + +### .NET + +V ASP.NET Core použij `UsePathBase`, pokud template nebo aplikace používá `ROOT_PATH`. + +Typicky: + +```csharp +var rootPath = Environment.GetEnvironmentVariable("ROOT_PATH"); + +if (!string.IsNullOrWhiteSpace(rootPath)) +{ + app.UsePathBase(rootPath); +} +``` + +Swagger/OpenAPI ale musí být nakonfigurovaný tak, aby `servers` odpovídaly proxy prefixu. + +Nestačí pouze přidat endpoint `/docs`. + +Je nutné ověřit i Swagger `Try it out`. + +### Python / FastAPI + +FastAPI typicky používá `root_path`. + +Aplikace musí zajistit, že dokumentace a OpenAPI schema respektují proxy prefix. + +### Node.js / Express + +Express aplikace musí počítat s reverse proxy prefixem. + +Pokud se používá Swagger UI, musí být OpenAPI `servers` nebo Swagger konfigurace nastavené tak, aby testovací requesty šly přes `/apps/`. + +## Variables a secrets + +AppFactory spravuje variables a secrets přes portál. + +Portál ukládá hodnoty do DB a generuje runtime `.env` soubor aplikace. + +Aplikace je čte jako environment variables. + +Příklady: + +### .NET + +```csharp +var value = Environment.GetEnvironmentVariable("MY_VARIABLE"); +var optionalValue = builder.Configuration["OPTIONAL_VARIABLE"] ?? "default"; +``` + +### Python + +```python +import os + +value = os.getenv("MY_VARIABLE") +``` + +### Node.js + +```js +const value = process.env.MY_VARIABLE; +``` + +Secrets se nikdy nesmí: + +- commitovat do repository +- zapisovat do README +- vypisovat do logu +- vracet z běžných endpointů +- zobrazovat ve Swagger příkladech +- ukládat do zdrojového kódu +- hardcodovat + +Testovací endpointy, které vrací variables nebo secrets, se smí používat pouze dočasně pro ověření a musí být odstraněny před produkčním použitím. + +## Docker a port + +Aplikace musí poslouchat na portu definovaném AppFactory šablonou nebo metadaty aplikace. + +Port neměň bez odpovídající úpravy AppFactory konfigurace. + +Aplikace musí poslouchat na všech rozhraních containeru: + +```text +0.0.0.0 +``` + +Ne pouze na: + +```text +localhost +``` + +Dockerfile musí být deterministický a nesmí vyžadovat ruční zásahy v containeru. + +Ruční změny provedené přímo v běžícím containeru nejsou trvalé. + +## Co AI nesmí měnit v aplikačním repozitáři + +AI nesmí z aplikačního repozitáře měnit: + +- AppFactory deploy mechanismus +- Caddy konfiguraci +- Gitea webhooky +- Registry konfiguraci +- Backup/restore skripty +- Secrets storage +- Systémové soubory serveru +- AppFactory core služby +- AppFactory tools skripty + +Pokud je potřeba změnit infrastrukturu, musí se to řešit v příslušném AppFactory repozitáři, ne v repozitáři konkrétní aplikace. + +## Pravidla pro úpravy aplikace + +Před úpravou si vždy přečti: + +- `README.md` +- `AGENTS.md` +- `Dockerfile` +- hlavní vstupní soubor aplikace +- existující konfiguraci Swagger/OpenAPI +- způsob práce s environment variables + +Po úpravě ověř minimálně: + +- `/health` +- `/docs` +- upravovaný endpoint +- Swagger UI +- Swagger `Try it out` přes `/apps/` +- že container stále startuje +- že se nezměnil port bez úpravy metadat +- že secrets nejsou v logu ani ve zdrojovém kódu +- ideálně průběžně generuj dokumentaci .md do složky documentation v hlavním adresáři projektu. + +Každá změna musí zachovat kompatibilitu s AppFactory reverse proxy. + +Pokud přidáváš nový endpoint, dokumentace se musí aktualizovat současně. + +Pokud upravuješ request/response modely, Swagger/OpenAPI musí odpovídat skutečnému chování aplikace. + +## Secrets v parametrech +- Variables jako ClientId apod., které by neměly jít přes normální requesty se budou předávat jako X-ClientId v hlavičce. Nezapomeň takové přidat do swagger dokumentace, když budou nutné. + - pokud se bude předávat jinak, např. jako vnitřní secret, není potřeba. Vždy se na to programátora zeptej. + + +## Zakázané zkratky + +Nedělej tyto věci: + +- nepřidávej endpoint, který funguje jen lokálně, ale ne přes `/apps/` +- neopravuj Swagger tak, že bude fungovat pouze na root doméně +- nevypínej Swagger kvůli proxy problému +- nevypínej health check +- nevypínej validaci secrets tím, že je začneš logovat +- nepřepisuj Dockerfile na jiný port bez úpravy AppFactory metadat +- nepřidávej hardcoded URL produkční domény do business logiky + +## Doporučený postup po změně + +Po změně aplikace ověř veřejně: + +```text +GET https://services.csbot.cz/apps//health +GET https://services.csbot.cz/apps//docs +``` + +A přes Swagger UI ověř, že testování endpointů volá URL ve tvaru: + +```text +https://services.csbot.cz/apps// +``` + +ne: + +```text +https://services.csbot.cz/ +``` + +## Shrnutí pro AI + +Nejdůležitější pravidla: + +- aplikace běží za `/apps/` +- `/health` je povinný +- `/docs` se Swaggerem je povinný +- Swagger `Try it out` musí používat `/apps/` +- OpenAPI musí mít správný base path/server +- secrets nikdy nelogovat ani necommitovat +- konfiguraci číst z environment variables +- neměnit AppFactory infrastrukturu z aplikačního repozitáře +- po každé úpravě ověř reverse proxy chování diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f1dc70a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app ./app + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..eeae16c --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# PPL CPL API + +Generated by AppFactory. diff --git a/app.yml b/app.yml new file mode 100644 index 0000000..15f4b5f --- /dev/null +++ b/app.yml @@ -0,0 +1,7 @@ +id: pplcplapi +name: PPL CPL API +language: python +version: 1.0.0 +base_path: /apps/pplcplapi +port: 8000 +status: development diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..0287072 --- /dev/null +++ b/app/main.py @@ -0,0 +1,25 @@ +import os +from fastapi import FastAPI + +APP_NAME = os.getenv("APP_NAME", "PPL CPL API") +APP_VERSION = os.getenv("APP_VERSION", "1.0.0") +ROOT_PATH = os.getenv("ROOT_PATH", "") + +app = FastAPI( + title=APP_NAME, + version=APP_VERSION, + root_path=ROOT_PATH +) + +@app.get("/health") +def health(): + return {"status": "ok"} + +@app.get("/version") +def version(): + return { + "app": APP_NAME, + "version": APP_VERSION, + "language": "python", + "root_path": ROOT_PATH + } diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..364e2ee --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +fastapi +uvicorn[standard]