feat(mcp-docugen): tema CSS Tielogic, Swagger pubblico, README aggiornato
- themes/tielogic-devnotes.css: stile DEVNOTES + offerta Tielogic per md-to-pdf (cover bianca con logo+box FORNITORE/CLIENTE, tabelle finanziarie, badge, status-card, sezione ACCETTAZIONE con firme, A4 portrait) - main.py: exempt_paths estesi a /docs /redoc /openapi.json (Swagger UI accessibile senza Bearer per esplorazione interattiva) - README: stato mcp-docugen aggiornato, layout docker/gateway, setup completo con docker compose + smoke test Template runtime (offerta, report-analisi) vivono nel volume Docker docugen-data, non versionati nel repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ Due pezzi, stesso repo:
|
|||||||
|
|
||||||
| Servizio | Stato | Funzione |
|
| 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-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. |
|
| `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-<nome>/ # src/ tests/ pyproject.toml Dockerfile
|
│ └── mcp-<nome>/ # src/ tests/ pyproject.toml Dockerfile
|
||||||
├── scripts/ # script operativi (provisioning, backup, smoke)
|
├── scripts/ # script operativi (provisioning, backup, smoke)
|
||||||
├── secrets/ # chiavi, token (gitignored)
|
├── 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
|
├── pyproject.toml # workspace uv + ruff + pytest root
|
||||||
├── .env.example # config root stack
|
├── .env.example # config root stack
|
||||||
├── .mcp.json.example # template registrazione client MCP
|
├── .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).
|
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
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env # imposta OPENROUTER_API_KEY, DOCUGEN_API_KEY, GATEWAY_PORT
|
||||||
cp .mcp.json.example .mcp.json # compila con URL + API key
|
cp .mcp.json.example .mcp.json # compila con URL + API key per registrazione client
|
||||||
uv sync --all-groups
|
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
|
## Remote
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ async def build_app(settings: Settings | None = None) -> FastAPI:
|
|||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
ApiKeyAuthMiddleware,
|
ApiKeyAuthMiddleware,
|
||||||
api_key=settings.api_key,
|
api_key=settings.api_key,
|
||||||
exempt_paths={"/health"},
|
exempt_paths={"/health", "/docs", "/redoc", "/openapi.json"},
|
||||||
)
|
)
|
||||||
|
|
||||||
app.state.settings = settings
|
app.state.settings = settings
|
||||||
|
|||||||
@@ -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; }
|
||||||
Reference in New Issue
Block a user