diff --git a/README.md b/README.md index 1af85e8..35896c0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Due pezzi, stesso repo: | Servizio | Stato | Funzione | |---|---|---| -| `mcp-docugen` | Design pronto, implementazione da iniziare | Genera Markdown formale da template + LLM (OpenRouter). Vedi [`docs/mcp-docugen-design.md`](docs/mcp-docugen-design.md) + [`docs/mcp-docugen-implementation.md`](docs/mcp-docugen-implementation.md). | +| `mcp-docugen` | Implementato, 68 test verde, deploy Docker via gateway Caddy (porta 8090), 6 tool MCP esposti | Genera Markdown formale da template + LLM (OpenRouter). Vedi [`docs/mcp-docugen-design.md`](docs/mcp-docugen-design.md) + [`docs/mcp-docugen-implementation.md`](docs/mcp-docugen-implementation.md). | | `mcp-convert` | Da progettare | Conversione Markdown → PDF / DOCX / HTML (pandoc/typst backend). | | `mcp-inbox` | Da progettare | Ingest da Telegram (+ STT opzionale via Whisper) verso draft inbox consumati da Claude Code desktop. | @@ -31,7 +31,9 @@ ArcaSuite/ │ └── mcp-/ # src/ tests/ pyproject.toml Dockerfile ├── scripts/ # script operativi (provisioning, backup, smoke) ├── secrets/ # chiavi, token (gitignored) -├── docker-compose.yml # stack completo (TODO: arriverà con primo MCP) +├── docker/ # base.Dockerfile condiviso multi-stage +├── gateway/ # Caddy reverse proxy (Caddyfile) +├── docker-compose.yml # stack completo (gateway + servizi MCP) ├── pyproject.toml # workspace uv + ruff + pytest root ├── .env.example # config root stack ├── .mcp.json.example # template registrazione client MCP @@ -52,12 +54,19 @@ ArcaSuite/ Servizi non-MCP (es. eventuali `inbox-service` REST) seguono [`/home/adriano/Documenti/Struttura_Progetti/2026-04-01-python-project-spec-design.md`](/home/adriano/Documenti/Struttura_Progetti/2026-04-01-python-project-spec-design.md). Gli MCP server seguono la struttura specifica descritta nei rispettivi design doc (FastMCP come root ASGI). -## Setup (quando ci sarà il primo MCP implementato) +## Setup ```bash -cp .env.example .env -cp .mcp.json.example .mcp.json # compila con URL + API key +cp .env.example .env # imposta OPENROUTER_API_KEY, DOCUGEN_API_KEY, GATEWAY_PORT +cp .mcp.json.example .mcp.json # compila con URL + API key per registrazione client uv sync --all-groups +docker compose up -d --build # avvia gateway + mcp-docugen +``` + +Smoke test: + +```bash +curl -H "Authorization: Bearer $DOCUGEN_API_KEY" http://localhost:8090/mcp-docugen/health ``` ## Remote diff --git a/services/mcp-docugen/src/mcp_docugen/main.py b/services/mcp-docugen/src/mcp_docugen/main.py index deff841..ea93641 100644 --- a/services/mcp-docugen/src/mcp_docugen/main.py +++ b/services/mcp-docugen/src/mcp_docugen/main.py @@ -74,7 +74,7 @@ async def build_app(settings: Settings | None = None) -> FastAPI: app.add_middleware( ApiKeyAuthMiddleware, api_key=settings.api_key, - exempt_paths={"/health"}, + exempt_paths={"/health", "/docs", "/redoc", "/openapi.json"}, ) app.state.settings = settings diff --git a/themes/tielogic-devnotes.css b/themes/tielogic-devnotes.css new file mode 100644 index 0000000..8db10e6 --- /dev/null +++ b/themes/tielogic-devnotes.css @@ -0,0 +1,320 @@ +/* Tielogic — A4 portrait theme (cover bianca stile offerta + DEVNOTES interno) */ + +@page { + size: A4 portrait; + margin: 22mm 22mm 22mm 22mm; +} + +html, body { + font-family: "Inter", "Segoe UI", -apple-system, BlinkMacSystemFont, sans-serif; + font-size: 10.5pt; + color: #1c2533; + line-height: 1.45; + margin: 0; + padding: 0; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; +} + +h1, h2, h3, h4 { + font-weight: 700; + color: #0d1b2a; + letter-spacing: 0.01em; + page-break-after: avoid; +} + +h2 { + font-size: 14pt; + text-transform: uppercase; + border-left: 4px solid #1f4ed8; + padding-left: 10px; + margin-top: 22px; + margin-bottom: 14px; +} + +h3 { font-size: 11.5pt; margin-top: 18px; margin-bottom: 8px; } + +p { margin: 0 0 8px 0; } + +code, pre { + font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; + font-size: 9pt; +} + +code { background: #f1f3f7; padding: 1px 5px; border-radius: 3px; } + +pre { + background: #0d1b2a; + color: #e6e9ef; + padding: 12px 14px; + border-radius: 6px; + overflow-x: auto; + page-break-inside: avoid; +} + +pre code { background: transparent; color: inherit; padding: 0; } + +table { + width: 100%; + border-collapse: collapse; + margin: 10px 0 16px 0; + font-size: 9.5pt; + page-break-inside: avoid; +} + +th { + background: #f4f6fa; + text-align: left; + font-weight: 600; + text-transform: uppercase; + font-size: 8.5pt; + letter-spacing: 0.04em; + border-bottom: 2px solid #c8d0dd; + padding: 8px 10px; + color: #0d1b2a; +} + +td { + padding: 7px 10px; + border-bottom: 1px solid #e3e7ee; + vertical-align: top; +} + +tr:nth-child(even) td { background: #fafbfd; } + +blockquote { + background: #0d1b2a; + color: #e6e9ef; + border-left: 4px solid #1f4ed8; + padding: 14px 18px; + margin: 14px 0; + border-radius: 4px; + page-break-inside: avoid; +} + +blockquote strong { color: #ffffff; } + +hr { + border: 0; + border-top: 1px solid #c8d0dd; + margin: 18px 0; +} + +/* ===== COVER stile Tielogic (bianca) ===== */ + +.cover { + margin: -22mm -22mm 0 -22mm; + padding: 35mm 22mm 22mm 22mm; + height: 297mm; + box-sizing: border-box; + page-break-after: always; + text-align: center; + background: #ffffff; +} + +.cover .brand { + font-size: 40pt; + font-weight: 800; + color: #2767d8; + letter-spacing: 0.06em; + margin: 0; + line-height: 1; +} + +.cover .brand-tagline { + font-size: 12pt; + color: #5a6478; + margin-top: 6px; + letter-spacing: 0.02em; +} + +.cover .brand-divider { + width: 80mm; + height: 1.2px; + background: #c8d0dd; + margin: 22mm auto 22mm auto; +} + +.cover .doc-title { + font-size: 26pt; + font-weight: 700; + color: #0d1b2a; + text-transform: uppercase; + letter-spacing: 0.01em; + margin: 0 0 8px 0; + line-height: 1.15; +} + +.cover .doc-product { + font-size: 14pt; + color: #2c3a52; + margin: 0 0 4px 0; +} + +.cover .doc-ref { + font-size: 10pt; + color: #6c7a92; + margin: 0 0 18mm 0; +} + +.cover .info-box { + display: flex; + background: #eef3fb; + border-radius: 4px; + padding: 14px 18px; + margin: 0 auto; + max-width: 150mm; + text-align: left; + gap: 12mm; +} + +.cover .info-box .info-col { flex: 1; font-size: 10pt; line-height: 1.55; } + +.cover .info-box .info-label { + font-size: 8.5pt; + font-weight: 700; + color: #2767d8; + text-transform: uppercase; + letter-spacing: 0.08em; + margin-bottom: 4px; +} + +.cover .info-box .info-name { font-weight: 700; color: #0d1b2a; margin-bottom: 2px; } + +.cover .doc-validity { + margin-top: 16mm; + font-size: 10pt; + color: #5a6478; + font-style: italic; +} + +/* ===== BADGES ===== */ + +.badge { + display: inline-block; + padding: 2px 8px; + border-radius: 3px; + font-size: 8.5pt; + font-weight: 700; + letter-spacing: 0.05em; + vertical-align: middle; + text-transform: uppercase; +} + +.badge-ok { background: #d4f4dd; color: #0a6b32; } +.badge-parziale { background: #fef3c7; color: #8a5a00; } +.badge-drift { background: #fde4cc; color: #9a4a00; } +.badge-fail { background: #fcd3d3; color: #9a1a1a; } +.badge-alto { background: #fcd3d3; color: #9a1a1a; } +.badge-medio { background: #fef3c7; color: #8a5a00; } +.badge-basso { background: #d4f4dd; color: #0a6b32; } +.badge-fattibile { background: #d4f4dd; color: #0a6b32; } +.badge-non-fattibile { background: #fcd3d3; color: #9a1a1a; } +.badge-fattibile-riserva { background: #fef3c7; color: #8a5a00; } + +/* ===== STATUS CARDS ===== */ + +.status-card { + border-left: 4px solid #c8d0dd; + background: #f7f9fc; + padding: 10px 14px; + margin: 8px 0; + border-radius: 0 4px 4px 0; + page-break-inside: avoid; +} + +.status-card .name { + font-weight: 700; + font-size: 10pt; + letter-spacing: 0.04em; + text-transform: uppercase; + color: #0d1b2a; + margin-bottom: 4px; +} + +.status-card.ok { border-left-color: #2aa86b; } +.status-card.parziale { border-left-color: #d99a1a; } +.status-card.drift { border-left-color: #c46b00; } +.status-card.fail { border-left-color: #c8242a; } + +/* ===== TABELLE FINANZIARIE (offerte) ===== */ + +table.financial { font-size: 10pt; } +table.financial th { background: #2767d8; color: #ffffff; } +table.financial td.num, +table.financial th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; } +table.financial tr.total-row td { + background: #eef3fb; + font-weight: 700; + color: #0d1b2a; + border-top: 2px solid #2767d8; +} + +/* H1 prodotto/servizio (apertura corpo offerta dopo cover) */ +h1 { + font-size: 22pt; + color: #0d1b2a; + margin: 6mm 0 6mm 0; + font-weight: 700; + page-break-before: avoid; +} + +/* ===== ACCETTAZIONE / FIRME (stile Tielogic) ===== */ + +.acceptance { + margin-top: 18mm; + page-break-inside: avoid; +} + +.acceptance h2.acceptance-title { + font-size: 22pt; + color: #2767d8; + text-transform: uppercase; + border-left: none; + padding-left: 0; + margin-bottom: 12px; + letter-spacing: 0.01em; +} + +.acceptance .acceptance-intro { + margin-bottom: 22mm; + font-size: 10.5pt; +} + +.signature-grid { + display: flex; + gap: 14mm; + margin-bottom: 16mm; +} + +.signature-grid .sig-col { flex: 1; font-size: 10pt; } + +.signature-grid .sig-col .sig-party { + font-weight: 700; + color: #0d1b2a; + margin-bottom: 22mm; +} + +.signature-grid .sig-col .sig-line { + border-top: 1px solid #1c2533; + padding-top: 4px; + font-size: 9pt; + color: #5a6478; +} + +.acceptance .place-date { + margin-top: 8mm; + font-size: 10pt; + color: #1c2533; +} + +.acceptance .place-date .pd-line { + display: inline-block; + border-bottom: 1px solid #1c2533; + width: 60mm; + margin: 0 8px; +} + +/* ===== PAGE BREAK ===== */ + +.page-break { page-break-after: always; }