Initial analytics

This commit is contained in:
AppFactory Bot
2026-06-18 07:35:27 +00:00
commit 284e013753
7 changed files with 578 additions and 0 deletions
+176
View File
@@ -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
+353
View File
@@ -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/<app-id>
```
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/<app-id>` 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/<app-id>
```
Typicky platí:
```text
veřejný request:
GET /apps/<app-id>/contacts
aplikace uvnitř containeru často vidí:
GET /contacts
```
Důvodem je použití reverse proxy route typu `handle_path`, která prefix `/apps/<app-id>` 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/<app-id>`
## 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/<app-id>/health
GET /apps/<app-id>/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/<app-id>
```
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/<app-id>/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/<app-id>`
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/<app-id>"
}
]
}
```
Nesmí vzniknout stav, kdy Swagger UI vypadá správně, ale tlačítko `Try it out` volá endpointy bez `/apps/<app-id>`.
## ROOT_PATH / PathBase
AppFactory může aplikaci předávat environment variable:
```text
ROOT_PATH=/apps/<app-id>
```
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/<app-id>`.
## 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/<app-id>`
- ž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/<app-id>`
- 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/<app-id>/health
GET https://services.csbot.cz/apps/<app-id>/docs
```
A přes Swagger UI ověř, že testování endpointů volá URL ve tvaru:
```text
https://services.csbot.cz/apps/<app-id>/<endpoint>
```
ne:
```text
https://services.csbot.cz/<endpoint>
```
## Shrnutí pro AI
Nejdůležitější pravidla:
- aplikace běží za `/apps/<app-id>`
- `/health` je povinný
- `/docs` se Swaggerem je povinný
- Swagger `Try it out` musí používat `/apps/<app-id>`
- 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í
+12
View File
@@ -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"]
+3
View File
@@ -0,0 +1,3 @@
# analytics
Generated by AppFactory.
+7
View File
@@ -0,0 +1,7 @@
id: analytics
name: analytics
language: python
version: 1.0.0
base_path: /apps/analytics
port: 8000
status: development
+25
View File
@@ -0,0 +1,25 @@
import os
from fastapi import FastAPI
APP_NAME = os.getenv("APP_NAME", "analytics")
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
}
+2
View File
@@ -0,0 +1,2 @@
fastapi
uvicorn[standard]