# ASF — Guida Primi Passi: Creare il tuo primo Progetto > **ASF = Azurian Software Factory** · *SaaS Platform multi-tenant AI-native* > > **Motto**: *"From Requirement to Production — everything is contextualized, traceable and AI-accessible."* > > **Principio centrale**: ***Everything is an Artifact*** — requisiti, task, PR, commit, build, test, deploy, incidenti, analisi AI, segnalazioni di sicurezza: tutto è un Artifact ASF collegato da Relazioni semantiche. Questo permette agli agenti AI di capire **PERCHÉ** un pezzo di codice esiste (non solo **cosa** fa), tracciandone l'origine, i test, il ciclo di rilascio e gli effetti in produzione. Questa guida ti porta da **zero a primo grafo di traceability end-to-end funzionante** in 8 piccoli step, usando direttamente le API REST di ASF Core e verificando ogni risultato sul Frontend. --- ## 🧱 Stack Tecnologico (da Specifiche ASF) ASF è disegnato come "pragmatic monolith → services": **nessun microservizio prematuro** per apparenza architetturale. | Layer | Tecnologie | Stato MVP | |---|---|---| | 🎨 **Frontend** | Next.js 14 · React · TypeScript · Tailwind · shadcn/ui · TanStack Query v5 · React Flow · SSE/WebSocket realtime | ✅ attivo su :3000 | | ⚙️ **Backend Core (asf-core)** | Python 3.12 · FastAPI · Pydantic v2 · async/await | ✅ attivo su :8000 · OpenAPI `/docs` | | 🗄️ **Persistence** | **MongoDB rs0** (Motor async) · 2 nodi replica set | ✅ PRIMARY 172.19.40.102 · SEED 172.19.40.103 | | 📢 **Messaging Backbone** | **RabbitMQ** (aio_pika connect_robust) · vhost `asf` · **2 canali logici**: (1) **Async Jobs** su code DIRECT (2) **Domain Events** (requirement.created / deployment.completed) | ✅ 7 code DIRECT iscritte dal worker | | 🤖 **AI Layer (asf-ai)** | **ASF AI Gateway = ASTRAZIONE TOTALE** · Zero accoppiamento diretto a provider LLM · Supporta NVIDIA DGX Spark · OpenAI-compatibile · Custom provider. Futuri: model routing · tenant AI policies · usage metering · priority queues · cost tracking | ✅ astrazione + MockProvider (7/7 tests PASS) | | 📚 **Context Service (asf-context)** | BFS relazioni + (futuro) semantic retrieval vettoriale · Design preparato per **passare in futuro a graph DB senza re-write totale** (Mongo è source of truth MVP ma le relazioni sono disaccoppiate) | ✅ ContextEngine BFS depth=2 · 4 tests PASS | | 🧰 **Worker (asf-worker)** | Job consumer orizzontalmente scalabile · NO stato critico in memoria · Echo handler MVP | ✅ loop while-true respawn 5 jobs echo completati | | 🔌 **Osservabilità** | Structured logging JSON · correlation_id + tenant_id + project_id + job_id propagati in tutta distribuzione · OpenTelemetry-ready | ✅ logging strutturato + correlation middleware | | ⏭️ **(Futuri)** | Redis caching / pubsub · MinIO/S3 object storage · Git/CI/Docs/Observability connectors · MCP · Webhooks | ⏭️ boundary presenti, non MVP attivo | --- ## 📋 0. Prerequisiti ASF è già avviato in locale, senza Docker: verificalo con `make status`. | Comando | Descrizione | |---|---| | `make start` | Avvia ASF Core (FastAPI :8000) + ASF Web (Next.js :3000) + Worker | | `make status` | Controlla PIDs, porte, health check, ultimi log | | `make stop` | Ferma tutto in modo pulito (SIGTERM → SIGKILL fallback) | | `make lint` | pytest 5 packages + tsc strict no-emit | **Health check (Core)**: ```bash curl -s http://localhost:8000/api/v1/health | python -m json.tool ``` **Frontend**: apri `http://localhost:3000` nel browser. --- ## 🧭 Modello ASF: Multi-Tenant + Everything is an Artifact ``` ┌──────────────────────────────────────────────────────────────────┐ │ Organization (Tenant) │ ← SSO · API keys · quotas · subscriptions · billing (§8) │ └─ Team ──────────────────────────────────────────────────────┐ │ ← ⏭️ Futuro: RBAC · membership · permissioni per team │ └─ Project ─────────────────────────────────────────────┐ │ │ ← Reale già oggi. Ogni Artifact appartiene a 1 Project │ └─ Artifact (17 tipi) ←── Relationship ─→ Artifact │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` 1. **Organization = Tenant** · es. `azurian-labs` (il tuo team/cliente, **isolamento dati perimetrale**). - Futuro: SSO (OIDC / SAML) · API keys scopes · audit retention · subscription plan · metering · billing boundaries (non MVP, ma già boundary nel codice). 2. **Team** (⏭️ layer futuro incluso per compatibilità futura) · gruppi di utenti dentro Org con ruoli e permissioni RBAC (Owner / Admin / Editor / Viewer). MVP oggi salta il layer Team per semplicità ma lo include nel modello per non doverlo aggiungere dopo con migration. 3. **Project** · dentro una Org (e opzionalmente Team), es. `ASF` (il prodotto/servizio). **Ogni Artifact appartiene SEMPRE a un Project** (campo `project_id` obbligatorio nel `ArtifactCreate`). 4. **Artifact** (17 tipi, enum `ArtifactType` — unica sorgente di verità condivisa package `asf-domain`): `requirement, epic, story, task, architecture_decision, document, source_file, commit, pull_request, build, test, security_finding, deployment, release, runtime_event, incident, ai_analysis` - **Nessun modello separato per tipo** (regola §2 estensibilità). Ogni tipo è esteso col campo libero `metadata: dict[str, Any]`. 5. **Relationship** (12 predicati semantici, enum `RelationshipType` — anche questo condiviso dal package domain): `implements, implemented_by, verifies, verified_by, generated_from, documented_by, depends_on, affects, deployed_as, caused_by, supersedes, related_to` - Relazioni sono **directional** (source → target), quindi "il PR è generated_from dal TASK" e non viceversa. --- ## 🔑 Headers Dev-Trust (Importante!) In locale ASF usa una modalità "dev-trust" semplificata: **per ogni richiesta aggiungi questi 2 header** per impersonare utente e tenant. **Senza questi header** le `GET /projects` e `POST /artifacts` etc. restituiranno 401 o lista vuota. ``` X-ASF-Tenant-Id: X-ASF-User-Id: > ``` Per questa guida useremo due valori coerenti (sono accettate UUID 128-bit o fallback testuali deterministici): ``` TENANT="t-demo-003" USER="u-mario" ``` Salviamoli come **variabili ambientali** nel terminale così da non ripeterli ogni volta: ```bash export TENANT="t-demo-003" export USER="u-mario" export H="http://localhost:8000/api/v1" export H3K="http://localhost:3000/api/v1" # Alias helper (conservali nella shell corrente): auth() { echo "-H X-ASF-Tenant-Id:$TENANT -H X-ASF-User-Id:$USER"; } GET() { curl -s $(auth) "$H$1"; } POST() { curl -s -X POST $(auth) -H "Content-Type: application/json" -d @- "$H$1"; } PATCH(){ curl -s -X PATCH $(auth) -H "Content-Type: application/json" -d @- "$H$1"; } DEL() { curl -s -X DELETE $(auth) "$H$1"; } ``` > Nota: `$H3K` (:3000) è l'endpoint Next.js con **rewrites trasparenti** → `/api/v1/*` → `localhost:8000/api/v1/*`. La risposta è **byte-identica** al Core, utile per testare i rewrite del frontend. --- ## ✅ Step 1 — Crea la tua Organization (Tenant) **Payload**: `OrganizationCreate { name, slug, plan?, is_active? }` - `slug`: **min 3, max 60 caratteri**, regex `^[a-z0-9][a-z0-9\-]{1,58}[a-z0-9]$` (tutto minuscolo, trattini, inizia e finisce con alfanum). ```bash cat <<'JSON' | POST /organizations { "name": "Azurian Labs Demo", "slug": "azurian-labs-demo", "plan": "pro", "is_active": true } JSON ``` **Attesa** → HTTP 201, risposta simile a: ```json { "id": "0191f…", "name": "Azurian Labs Demo", "slug": "azurian-labs-demo", "plan": "pro", "is_active": true, "created_at": "…", "updated_at": "…" } ``` Prendi nota dell'`id` (UUID) dell'Organization: ```bash ORG_ID=$(GET /organizations | python -c 'import json,sys; print(json.load(sys.stdin)[0]["id"])') echo "ORG_ID=$ORG_ID" ``` Verifica anche la rotta `/slug`: ```bash GET /organizations/slug/azurian-labs-demo | python -m json.tool ``` --- ## ✅ Step 2 — Crea il tuo primo Project **Payload**: `ProjectCreate { name, key, description?, default_branch?, is_active? }` - `key`: **min 2, max 20** caratteri, regex `^[A-Z][A-Z0-9]{1,19}$` (maiuscolo, prima lettera, resto lettere/numeri). Utile come prefisso leggibile per i riferimenti. ```bash cat <<'JSON' | POST /projects { "name": "ASF SaaS MVP", "key": "ASF", "description": "Minimal Viable Product di ASF: dal requisito al deploy con tracciabilità end-to-end.", "default_branch": "main", "is_active": true } JSON ``` → **HTTP 201 Created**. Prendi l'`id`: ```bash PROJ_ID=$(GET /projects | python -c 'import json,sys; print(json.load(sys.stdin)[0]["id"])') echo "PROJ_ID=$PROJ_ID" ``` **Frontend check**: apri `http://localhost:3000/` (Overview Dashboard). Vedrai il nuovo project nel conteggio `projects` (nota: Overview aggrega per tenant, non per singolo progetto). --- ## ✅ Step 3 — Crea 4 Artifact Base (REQ / TASK / PR / TEST) Ora iniziamo il "ciclo di vita del software" che sarà il nostro primo grafo. **Il campo `tenant_id` NON va passato** — viene iniettato server-side dagli header. **Il campo `project_id` VA SEMPRE PASSATO** (l'Organization può avere più progetti). Creiamo 4 artifact nello stesso project: ```bash REQ=$(cat < target` - `TASK implements REQUIREMENT` - `PR generated_from TASK` - `TEST verifies PR` - Non serve passare `tenant_id`, `source_project_id`, `target_project_id` (validati server-side). ```bash # 1. TASK implements REQ (il task realizza il requisito) cat < 🎯 **Regola di design ASF §7**: lo stato **permanente** di un Job (status, result, usage, error, worker, timestamps) **vive SEMPRE su MongoDB**. > RabbitMQ viene usato **SOLO come coda di messaggi per il passaggio lavoro**, MAI come database. > Se RabbitMQ cadesse, i job non si perdono: restano `status=queued` o `running` su Mongo e possono essere risottomessi o ripresi. Il Worker scala orizzontalmente senza stato critico in memoria. ASF gestisce il lavoro asincrono con **Jobs** su code RabbitMQ DIRECT. 7 code logiche DIRECT già registrate (priorità decrescente): `asf.ai.interactive > asf.ai.background > asf.testing > asf.code_analysis > asf.devops > asf.notifications > asf.indexing` Prova con 3 job demo (echo handler integrato nel worker): ```bash # Job 1 - DevOps cat <<'JSON' | POST /jobs/submit { "queue": "devops", "job_type": "devops", "title": "deploy staging preflight", "payload": { "service": "asf-auth", "env": "staging", "mode": "preflight" }, "priority": 50 } JSON # Job 2 - Testing cat <<'JSON' | POST /jobs/submit { "queue": "testing", "job_type": "testing", "title": "regression suite auth", "payload": { "suite": "auth/google_test.py", "cases": 12, "fail-fast": true }, "priority": 70 } JSON # Job 3 - Code Analysis (smell detection) cat <<'JSON' | POST /jobs/submit { "queue": "code_analysis", "job_type": "code_analysis", "title": "ruff check src/auth", "payload": { "path": "src/auth/oauth2.py", "linters": ["ruff","pyright"], "fail_on_error": true }, "priority": 40 } JSON ``` Controlla lo stato in **Jobs List** (sidebar → **Jobs (Activity)** o vai a `http://localhost:3000/jobs`): - Auto-refresh ogni 3 secondi, 6 stat cards in alto (Running / Queued / Completed / Failed) - Clicca una riga → modale **Detail JSON** per vedere `result`, `usage` (cpu_seconds, input/output tokens, cost). - **Enqueue Modal** (top-right) per creare altri job dal frontend. Dopo 5-10s gli echo handler (`EchoHandler`) completeranno i jobs → status **COMPLETED** con body `{ echo: …, handled_by: worker_id, timestamp: … }`. ### Verifica API count_by_status: ```bash GET /jobs | python -c ' import json,sys from collections import Counter d = json.load(sys.stdin) print("Jobs totali:", len(d)) for s, c in Counter(j.get("status","?") for j in d).most_common(): print(f" {s:12s} {c}") ' ``` --- ## ✅ Step 7 — Code Analysis: Carica Source + Mark Smell come Fixed Apri `/code` (sidebar **Code Analysis**). La pagina usa **2 useQuery separate**: 1. `type=source_file` (tutti i sorgenti caricati) 2. `type=ai_analysis` filtrato client-side `metadata.kind == "code_smell"` (code smell) Carichiamo un file Python con 1 smell **ASF-SEC-203** (lo stesso della security finding), poi cliccheremo **Mark as fixed** nel frontend. ```bash SRC=$(cat < 🤖 **ASF AI Gateway: ASTRAZIONE PURA (regola §1)**. > - Frontend + Backend (asf-core) NON conoscono il provider LLM: fanno richiesta all'AI Gateway. > - Nessun accoppiamento diretto a OpenAI / Anthropic / Azure OpenAI / ecc. > - I provider configurabili (già astrazione pronta): **NVIDIA DGX Spark** (on-prem) · OpenAI-compatibili · custom provider. > - Futuri: model routing per task · AI policies per-tenant · usage metering · priority queues · cost tracking. > - Nel MVP seed attuale (nessun provider collegato) viene usato `MockProvider`/fallback text per verificare il ciclo 202 + poll + bolle. Sidebar → **Ask ASF (AI)** oppure `http://localhost:3000/ask-asf`. Scrivi nel prompt: > "Cosa causa l'incidente INC-5? Qual è il requisito a monte? Elenca i passaggi dal deploy fino al requirement." - Il frontend fa **POST /api/v1/ask-asf/query** → HTTP **202 Accepted** (ritorna job_id) - **Polling ogni 2s per max 120s** (useEffect + cleanup on rerender + cancel ref) - Quando `status == COMPLETED`: pickAnswer legge `job.result.{message,answer,summary,response,text}` (ordine fallback) - **JobMeta pills**: queue, job_type, status, timestamps (copy/clear/Enter send, Shift+Enter newline) In modalità demo (senza provider LLM collegato) l'AI handler ritorna una risposta fallback, ma il **ciclo di Job + 202 + poll + render bolle è completamente funzionale e verificato**. --- ## 🎁 Bonus: Seed Ricreabile Completo Per ricostruire TUTTO in 1 comando (contenuto demo esistente): ```bash make seed-clean ``` Questo esegue `bash scripts/seed-demo.sh --clean --jobs` che: 1. **DELETE /artifacts/{id}** di tutti gli esistenti (loop safe, bulk non esiste MVP) 2. **PATCH CANCEL** di tutti i jobs ancora QUEUED/RUNNING 3. POST degli 8 artifact demo (REQ/TASK/PR/BUILD/DEP/TEST/DOC/COMMIT/SEC/INC + 3 Source files + 3 Smells) 4. POST delle 9 relazioni demo 5. POST 5 jobs echo per code/test/devops/indexing/notifications 6. Report finale: counts artifacts by type, graph nodes/edges, jobs status counts Per rieseguire senza cancellare niente (append di un nuovo set): ```bash make seed ``` --- ## 🗂️ Quick Reference API (Cheat Sheet) | Endpoint REST | Metodo | Cosa fa | |---|---|---| | `/api/v1/organizations` | GET · POST | Lista / Crea tenant | | `/api/v1/organizations/slug/{s}` | GET | Org per slug | | `/api/v1/organizations/{id}` | GET · PATCH | Dettaglio / Aggiorna tenant | | `/api/v1/projects` | GET · POST | Lista / Crea progetto | | `/api/v1/projects/{id}` | GET · PATCH | Dettaglio / Aggiorna progetto | | `/api/v1/artifacts?type=&status=&project_id=&limit=&offset=` | GET | Lista (filtri query) | | `/api/v1/artifacts` | **POST** | Crea artifact (**required: project_id, type, title**) | | `/api/v1/artifacts/{id}` | GET · **PATCH** · DELETE | Dettaglio · Aggiorna (es. `status=fixed`) · Cancella | | `/api/v1/relationships` | **POST** | Crea edge (source/type/target) | | `/api/v1/relationships/{id}` | DELETE | Rimuovi edge | | `/api/v1/relationships/for_artifact/{aid}` | GET | Lista edge in/out di 1 artifact | | `/api/v1/relationships/outgoing/{aid}` · `/incoming/{aid}` | GET | Solo uscenti / entranti | | `/api/v1/traceability/graph?project_id=…` | GET | Nodes + edges per ReactFlow (globale) | | `/api/v1/jobs` | GET | Lista jobs by tenant | | `/api/v1/jobs/submit` | **POST** | Submit job `{queue, job_type, title, payload?, priority?}` | | `/api/v1/jobs/{id}` | GET · PATCH | Dettaglio / Cancella (status=cancelled) | | `/api/v1/overview` | GET | Metriche Dashboard | | `/api/v1/audit?limit=100` | GET | Storico eventi (newest first) | | `/api/v1/ask-asf/query` | **POST** | Submit domanda AI → job con polling 202 | --- ## 📔 Appendice A. Frontend Shell Enterprise (Bootstrap §9) ### 14 Voci di Navigazione previste (shell enterprise) | # | Route / Sidebar Label | Descrizione | Stato MVP | |---|---|---|---| | 1 | `/` Overview | Dashboard aggregata 9 cards | ✅ attiva | | 2 | `/requirements` | Requirements list + 4 filtri (project / status / type / search) | ✅ attiva · 6 artifacts demo | | 3 | `/context` Context Explorer | Picker · 5 tabs: Metadata · Relationships · Related (2-hop) · **Graph 3-anelli** · History timeline | ✅ attiva | | 4 | `/code` Code Analysis | 2 useQuery (source + ai_analysis.kind=code_smell) · 6 filters · 5 StatCards · DetailView con **Mark-as-fixed PATCH** | ✅ attiva | | 5 | `/traceability` | React Flow layered · nodes 21 · edges 9 · Inspector · refetch 5s | ✅ attiva | | 6 | **`/ask-asf` Ask ASF (AI)** | Chat UI bolle user/AI · POST /ask-asf/query 202 + poll 2s max 120 · JobMeta pills | ✅ attiva | | 7 | **`/jobs` Jobs (Activity)** | 6 stats · list · auto-refresh 3s · Modal Enqueue · Detail JSON · Progress bar | ✅ attiva | | 8 | Pipelines | CI/CD pipeline view | ⏭️ placeholder futuro | | 9 | Deployments | Deployment history, env, rollback | ⏭️ placeholder | | 10 | Quality | Quality gates, coverage, lints | ⏭️ placeholder | | 11 | Observability | Logs/metrics/traces explorer | ⏭️ placeholder | | 12 | Integrations | Git / CI / Docs / PagerDuty connectors | ⏭️ placeholder | | 13 | Usage | Tenant AI/job consumption + cost tracking | ⏭️ placeholder | | 14 | Settings | Org / Team / Project config · keys · SSO · members | ⏭️ placeholder | ### Overview Dashboard — 9 Cards specificate La home `/` aggrega metriche cross-project per tenant: | Card | Cosa misura | Stato | |---|---|---| | 1 | Project Health (%) · pesato per requirements coverage / deploy success / security backlog | ✅ attiva (94.5% demo) | | 2 | Requirements count · by status / by type (open/in-progress/done) | ✅ attiva | | 3 | Implementation Coverage · % requirements con ≥1 task linked | ✅ attiva | | 4 | Test Coverage · % PR/deploy con ≥1 test verifies collegato | ✅ attiva | | 5 | Traceability completeness · % artifacts coinvolti in catene Req→Deploy | ✅ attiva | | 6 | Deployments (last 7d) · count + success rate | ✅ attiva | | 7 | Active AI Jobs · queued/running · usage last hour | ✅ attiva | | 8 | Failed Builds (last 7d) | ✅ attiva | | 9 | Security Findings (open) · per severity (critical/high/medium/low) | ✅ attiva | --- ## 🛡️ Appendice B. Non-Functional Requirements (Bootstrap §12-16) Linee guida ufficiali del progetto ASF — rispettate in ogni parte del codice: ### 🔎 Osservabilità (§12) - **Log strutturati JSON**: ogni log include `tenant_id`, `project_id` (se presente), `correlation_id`, `job_id` (se in un job). - **Correlation ID**: propagato **per tutta la distribuzione** (REST → Rabbit → Worker → AI Gateway → risposta). Middleware di correlazione già attivo. - **OpenTelemetry-ready**: punti di hook per tracing distribuito (non MVP, boundary presenti). - **❌ VIETATO loggare**: password, token, API keys, Authorization header, cookie firma, PII (personally identifiable information). ### 🔒 Sicurezza (§14) 1. **Tenant Isolation**: *TUTTE* le query filtrano per `tenant_id` (Mongo). Mai mescolare dati tra tenant. 2. **Input Validation**: TUTTI gli endpoint usano Pydantic v2 validato server-side (body, query params, headers). 3. **Secrets SOLO in env variables**: **MAI hardcodare** URI MongoDB / Rabbit / API keys nel codice o in file di config commitati. `.env.example` documenta le variabili richieste. 4. **Authorization boundaries**: layer Org → Teams → Projects (futuro) preparati per RBAC fine-grained. 5. **Secure defaults**: no permessi wildcard default, CORS whitelist minimale, cookie HttpOnly in authn futura. 6. **Audit logging**: ogni modifica (create/update/delete) su artifacts/projects/organizations/jobs genera record in `audit_events` con `actor_id` (user) + delta + timestamp. ### 👩‍💻 Regole Ingegneristiche (§15 — ASF Engineering Rules) | Regola | Applicazione pratica | |---|---| | **SOLID ove utile** | Service in asf-core/services/* + DI pattern (no singleton globali) | | **Codice semplice > codice intelligente** | No pattern gang-of-four non necessari | | **Typed models everywhere** | Pydantic v2 per input/output endpoint | | **Componenti testabili** | In-memory fakes (FakeJobsCollection / FakeRelService / FakeRepos) invece che Mongo reale per unit test | | **NO premature optimization** | Ottimizza solo dopo misurazione | | **NO microservizi per apparenza** | Monolite pragmatico → servizi reali, non finti. asf-core / asf-context / asf-ai / asf-worker = servizi distinti ma acoplamento debole. | | **NO classi giganti / file 2000 righe** | Split su service/repo/router | | **NO stato globale nascosto** | Dependencies injection, mutable state solo in MongoDB/Rabbit/Redis (Redis non MVP) | | **NO provider logic nel domain layer** | asf-domain è package standalone puro: non importa FastAPI, Motor, Rabbit, OpenAI SDK | ### 🧪 Testing Strategy (§16) - **pytest** come framework unico (tutti i servizi hanno pytest.ini `asyncio_mode=auto` per test async). - **Test Unit = NO servizi esterni**: Mongo/Rabbit/Redis sostituiti da fakes in-memory. Oggi 40/40 tests VERDI. - **Services testati oggi**: asf-domain 12 · asf-core 6 · asf-worker 8 · asf-ai 7 · asf-context 4. - Copertura domini critica: artifact lifecycle, relationship traversal, job claim atomic, AI provider abstraction, context BFS. --- ## ❌ Errori Comuni & Soluzioni | Errore | Causa | Fix | |---|---|---| | **422 `"slug" regex mismatch`** | Org slug con maiuscole / underscore | Usa minuscolo, `-`, 3-60 caratteri, inizia/finisce alfanum | | **422 `"key" regex mismatch`** | Project key non inizia con maiuscola | `^[A-Z][A-Z0-9]{1,19}$` es. `ASF`, `PROJ2`, non `asf` o `1PROJ` | | **422 `project_id` required field missing** | Artifact POST senza `project_id` | Aggiungi `"project_id": ""` (tenant from headers, project nel body) | | **422 field `description` / `version` extra_forbidden** | `ArtifactCreate` non ha questi campi | Usa `content=` per corpo lungo, version è solo nel record (non in create) | | **422 `artifact_type invalid value` (es. code_smell)** | Enum `ArtifactType` non contiene code_smell | Usa `type: "ai_analysis"` + `metadata.kind: "code_smell"` (vedi Step 7) | | **422 `source_project_id` extra_forbidden in Relationship** | Non si passano project ids nel body | Rimuovi: validazione server-side da artifact sorgente/destinazione | | **Lista artifacts vuota** | Header `X-ASF-Tenant-Id` mancante | Aggiungi `X-ASF-Tenant-Id: t-demo-003` e `X-ASF-User-Id: u-mario` a tutte le richieste | | **Context Graph vuoto** | Relazioni 0 sul seed corrente | Ricorreggi Step 4 e assicurati di aver POSTed le relationships con gli UUID corretti | | **Jobs non completano** | Worker non in esecuzione | `make start` (--with-worker) · controlla `make status` e tail log | | **TypeScript build fallisce** | Aggiunte imports in usages wrong | `make tsc` diagnostica riga+colonna precise, correggi e rilancia | | **⚠️ Credenziali esposte in repo** | URI Mongo/Rabbit/API keys hardcodate nel codice invece che in `.env` | **MAI committare `.env` nel repo** · tutte le secrets in env variables · `.env.example` pubblico solo i nomi delle variabili | | **⚠️ Jobs status persiste male** | Developer ha salvato lo stato del job in RabbitMQ invece che in Mongo | Regola §7: **Mongo = stato permanente**. Rabbit = solo coda messaggi. Se Rabbit cade, lo stato dei job (queued/running/completed/failed) resta su Mongo. | | **⚠️ Artifacts mixati tra progetti** | Filtro GET `/artifacts` senza `project_id` query param | Aggiungi `&project_id=` per vedere solo artifact di 1 progetto specifico · il default mostra TUTTI gli artifact del tenant | --- ## ✅ Pronti! Checklist Primo Progetto Funzionale Segnando una spunta per ogni step raggiungi la parità con la demo seed: - [ ] **0. Stack running** (`make status` core=8000 / web=3000 / worker alive) - [ ] **1. Organization creata** (slug OK, API `/slug` returns 200) - [ ] **2. Project creato** (key `ASF` o simile, Lista projects restituisce 1+ rows) - [ ] **3. 4+ artifacts base** (REQ / TASK / PR / TEST) - [ ] **4. 3+ relationships** → **Context Graph** mostra 3 anelli: selected / hop1 / hop2 - [ ] **5. Traceability globale** mostra 8+/7+ node/edge (BUILD/DEP/SEC/INC aggiunti) - [ ] **6. 3+ jobs enqueued + COMPLETED** (Jobs page counter "Completed" aumenta) - [ ] **7. Code Analysis: Smell → Mark as fixed → status="fixed" in GET** - [ ] **8. Ask ASF → POST 202 → poll → bolle UI renderizzate** - [ ] **9. `make lint` passa** (40/40 pytest + tsc 0 errors) **Fine tutorial.** Da qui puoi: (a) estendere i tipi artifact con `metadata.*` libero, (b) aggiungere relazioni a piacere, (c) scrivere handlers custom nel worker per nuovi job, (d) integrare un vero provider LLM in `asf-ai`.