Files: - STACK.md - FEATURES.md - ARCHITECTURE.md - PITFALLS.md - SUMMARY.md Key findings: - Stack: FastAPI 0.135.1 + React 19 + Vite 7 + Tailwind v4, single-container deploy - Architecture: FastAPI serves React SPA via catch-all, file-based storage (Docker volume), LLMService with retry/backoff - Critical pitfall: All 9 pitfalls map to Phase 1 — Italian prompts, Canva field constants, UTF-8 BOM, root_path config, per-item bulk isolation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
345 lines
26 KiB
Markdown
345 lines
26 KiB
Markdown
# Pitfalls Research
|
|
|
|
**Domain:** LLM-powered bulk content generation / CSV output for design tools
|
|
**Project:** PostGenerator — Instagram carousel bulk generation for B2B Italian SME marketing
|
|
**Researched:** 2026-03-07
|
|
**Confidence:** HIGH (most pitfalls verified against official docs or multiple confirmed sources)
|
|
|
|
---
|
|
|
|
## Critical Pitfalls
|
|
|
|
### Pitfall 1: LLM Output That "Looks Valid" But Isn't (Soft Failures)
|
|
|
|
**What goes wrong:**
|
|
Claude returns HTTP 200 with a valid response, JSON parses successfully, but the content is wrong: truncated mid-sentence, repeated slide text, missing slides in a carousel, or Italian that reads as translated-from-English. These "soft failures" never trigger error handling logic because there is no exception — only bad output silently written to files.
|
|
|
|
**Why it happens:**
|
|
Developers test the happy path, see valid JSON, and assume correctness. Validation is wired only for parse errors, not for semantic/structural correctness. In bulk mode, one bad generation gets buried in a batch of 20 and is only caught by the end user.
|
|
|
|
**How to avoid:**
|
|
- Implement a two-level validation layer: (1) JSON schema validation via Pydantic on parse, (2) business rule validation on content — check slide count matches requested count, each slide has non-empty text fields, text lengths are within Canva field limits, no repeated content across slides.
|
|
- Log structured validation failures separately from API errors so you can track quality drift.
|
|
- For Italian content: detect obvious English leakage by checking for common English stop words ("the", "and", "of") in output fields that should be Italian.
|
|
|
|
**Warning signs:**
|
|
- Output carousels where multiple slides have identical or near-identical text.
|
|
- Generated `titolo` fields that are suspiciously short (< 5 chars) or over Canva limits.
|
|
- CSV rows where some cells are empty when the schema required content.
|
|
- User reports "Canva mappa un campo ma c'e' testo mancante".
|
|
|
|
**Phase to address:** Phase 1 (Core generation pipeline) — build validation alongside the first API call, not as a later addition.
|
|
|
|
---
|
|
|
|
### Pitfall 2: Canva Bulk Create CSV — Column Names Must Exactly Match Template Placeholders
|
|
|
|
**What goes wrong:**
|
|
Canva Bulk Create requires CSV column headers to exactly match the placeholder names defined in the Canva template design. A mismatch (case, space, accent, or encoding difference) causes the field to silently fail to map — the placeholder stays empty in the generated design. There is no error message; the design just looks incomplete.
|
|
|
|
**Why it happens:**
|
|
Developers generate CSV column names programmatically from the content schema, but the Canva template was built manually with slightly different placeholder names. The user then has to manually re-map every field in the Canva UI, defeating the automation benefit.
|
|
|
|
**How to avoid:**
|
|
- Define placeholder names as a project-level constant (e.g. `CANVA_FIELDS = ["titolo", "sottotitolo", "testo_1", ...]`) that is shared between the template documentation and the CSV generator code.
|
|
- Include a "validate against template" step in the generation pipeline: before writing the CSV, verify every column name matches the expected constant list.
|
|
- Document exact Canva placeholder names in the project (e.g., in a `CANVA_TEMPLATE.md` or in the prompt templates themselves).
|
|
|
|
**Warning signs:**
|
|
- User says "Canva non collega automaticamente i campi, devo farlo a mano ogni volta".
|
|
- CSV preview in the application shows correct data but Canva designs come out blank.
|
|
- After a prompt template change, the column name changes and existing Canva templates break.
|
|
|
|
**Phase to address:** Phase 1 — define and lock the Canva field schema before writing any generation code.
|
|
|
|
---
|
|
|
|
### Pitfall 3: CSV UTF-8 BOM Encoding Breaks Canva / Excel Import
|
|
|
|
**What goes wrong:**
|
|
The CSV is correctly UTF-8 encoded, but Canva or the user's spreadsheet tool misinterprets it because a BOM (Byte Order Mark) is present or absent. Italian accented characters (à, è, é, ì, ò, ù) appear as `à `, `è` etc. in the design. Alternatively, the file is generated without BOM, and when the user opens it in Excel on Windows before uploading to Canva, Excel re-encodes it to Windows-1252, corrupting the accented characters before they reach Canva.
|
|
|
|
**Why it happens:**
|
|
Python's `csv` module with `encoding='utf-8'` produces UTF-8 without BOM. Excel on Windows expects UTF-8 with BOM (`utf-8-sig`) to auto-detect encoding. Canva itself expects plain UTF-8. This creates a two-failure-mode trap: BOM for Excel users, no-BOM for Canva direct upload.
|
|
|
|
**How to avoid:**
|
|
- Generate CSV with `encoding='utf-8-sig'` (UTF-8 with BOM). Canva ignores the BOM; Excel on Windows correctly reads it. This is the "safe default" for this use case.
|
|
- Always include a charset declaration in the HTTP response header when serving the download: `Content-Type: text/csv; charset=utf-8`.
|
|
- Test the download with actual Italian content containing `àèéìòù` before declaring the feature complete.
|
|
- Add a note in the UI: "Apri il CSV in Google Sheets, non in Excel, per evitare problemi di encoding".
|
|
|
|
**Warning signs:**
|
|
- Any accented character appearing as multiple garbled characters in Canva designs.
|
|
- User reports "i caratteri speciali sono sbagliati".
|
|
- CSV looks fine in a code editor but breaks when opened in Excel.
|
|
|
|
**Phase to address:** Phase 1 — encoding must be correct from the first CSV output, not retrofitted later.
|
|
|
|
---
|
|
|
|
### Pitfall 4: FastAPI `root_path` Double-Path Bug Behind Nginx Subpath Proxy
|
|
|
|
**What goes wrong:**
|
|
FastAPI deployed at `lab.mlhub.it/postgenerator/` requires `root_path` configuration to generate correct OpenAPI/Swagger URLs. However, if `root_path` is set both in `FastAPI()` constructor AND in Uvicorn, the prefix is applied twice, producing paths like `/postgenerator/postgenerator/openapi.json` which returns 404. The API may work correctly while the docs are broken, masking the configuration error.
|
|
|
|
**Why it happens:**
|
|
The FastAPI `root_path` mechanism is designed for "stripping path proxies" that remove the prefix before forwarding. If the nginx config forwards the full path (including `/postgenerator/`), FastAPI needs root_path to know its prefix but must NOT double-apply it. The interaction between FastAPI app-level root_path and Uvicorn-level root_path is a confirmed multi-year bug with many GitHub issues.
|
|
|
|
**How to avoid:**
|
|
- Set `root_path` only via Uvicorn (`--root-path /postgenerator`) or as an environment variable, NOT in the `FastAPI()` constructor.
|
|
- Configure nginx to strip the prefix before forwarding to the container: `proxy_pass http://container:8000/;` (note trailing slash — nginx strips the location prefix).
|
|
- Test OpenAPI docs at `lab.mlhub.it/postgenerator/docs` explicitly during initial deploy, not just API calls.
|
|
- Use `X-Forwarded-Prefix` header instead of root_path if nginx stripping is not feasible.
|
|
|
|
**Warning signs:**
|
|
- Swagger UI loads but API calls from the docs return 404.
|
|
- `/openapi.json` returns 404 while direct API endpoint calls work.
|
|
- Browser network tab shows requests to `../postgenerator/postgenerator/...`.
|
|
|
|
**Phase to address:** Phase 1 (deployment scaffolding) — verify proxy configuration before any feature work.
|
|
|
|
---
|
|
|
|
### Pitfall 5: Bulk Generation Without Per-Item State — All-or-Nothing Failure
|
|
|
|
**What goes wrong:**
|
|
A user requests 20 carousels. The backend loops through 20 API calls sequentially. The 15th call hits a rate limit or network timeout. The entire batch fails, the partial results are lost, and the user must start over from scratch.
|
|
|
|
**Why it happens:**
|
|
Simple sequential loop with a try/except at the top level. No intermediate state is persisted. This is acceptable for a single-item generation but catastrophic for bulk operations where each item has real API cost.
|
|
|
|
**How to avoid:**
|
|
- Implement per-item status tracking: each carousel gets a status record (pending / processing / success / failed) stored in the file system or an in-memory dict with a job ID.
|
|
- On failure, mark the item as `failed` and continue processing the rest. Allow retry of only failed items.
|
|
- Return partial results: if 15/20 succeed, deliver those 15 in the CSV.
|
|
- Persist the job state to disk (JSON file per job) so that server restart does not lose progress.
|
|
|
|
**Warning signs:**
|
|
- Bulk requests timeout and the user sees no output.
|
|
- Backend logs show one exception that kills the loop.
|
|
- User has to re-enter all 20 topics to retry because no intermediate state exists.
|
|
|
|
**Phase to address:** Phase 1 for basic per-item error isolation; Phase 2+ for full job persistence and retry UI.
|
|
|
|
---
|
|
|
|
### Pitfall 6: Rate Limit Errors Treated as Generic Errors — No Backoff
|
|
|
|
**What goes wrong:**
|
|
Claude API returns HTTP 429 (rate limit exceeded). The backend catches `Exception`, logs "generation failed", and either retries immediately (hammering the API) or returns an error to the user. In Tier 1 (50 RPM, 8,000 OTPM for Sonnet), a bulk batch of 10-20 carousels can easily hit the OTPM ceiling.
|
|
|
|
**Why it happens:**
|
|
Developers test with 1-2 items and never hit rate limits. Error handling is added generically. The `retry-after` header in the 429 response — which tells you exactly how long to wait — is ignored.
|
|
|
|
**How to avoid:**
|
|
- Implement specific 429 handling that reads the `retry-after` response header and waits that exact duration before retrying.
|
|
- Use exponential backoff with jitter for other transient errors (5xx), but honor `retry-after` precisely for 429.
|
|
- For bulk jobs: add a configurable delay between consecutive API calls (e.g. 2-3 seconds) to stay within OTPM limits even in Tier 1.
|
|
- Monitor `anthropic-ratelimit-output-tokens-remaining` response header to throttle proactively.
|
|
- Consider the Batches API (50% cheaper, separate rate limits) for non-interactive bulk generation.
|
|
|
|
**Warning signs:**
|
|
- Backend logs full of 429 errors during any batch larger than 5 items.
|
|
- Generation speed suddenly drops to zero mid-batch.
|
|
- Costs appear lower than expected (actually requests are failing, not succeeding).
|
|
|
|
**Phase to address:** Phase 1 — implement from the first API integration, not as a later optimization.
|
|
|
|
---
|
|
|
|
### Pitfall 7: Prompt Templates With Hard-Coded Assumptions That Break Silently
|
|
|
|
**What goes wrong:**
|
|
The prompt template instructs Claude to "generate 5 slides". Later, the user configures 7 slides per carousel. The template still says 5, but the schema expects 7. Claude generates 5 slides. The schema validator accepts it (minimum not enforced). CSV has 5 slide columns with data and 2 empty. Canva design has 2 blank slides.
|
|
|
|
**Why it happens:**
|
|
Prompt template is written with specific numbers embedded as literals rather than as injected variables. When configuration changes, only the schema/code is updated, not the template. File-based prompt management makes this disconnect invisible — there is no compile-time check.
|
|
|
|
**How to avoid:**
|
|
- Make all variable parameters injectable: `Genera {{num_slides}} slide`, not "Genera 5 slide".
|
|
- Implement a template validation step at startup: parse all templates, identify all `{{variable}}` placeholders, and verify every placeholder has a corresponding runtime value.
|
|
- Use a template rendering test in CI: render each template with test values and verify output matches expected format.
|
|
- Keep a `TEMPLATE_VARIABLES.md` that documents every variable each template expects.
|
|
|
|
**Warning signs:**
|
|
- Generated carousels have inconsistent slide counts.
|
|
- Template file was last modified weeks ago but configuration was changed last week.
|
|
- New team member added a config option but forgot to update the prompt template.
|
|
|
|
**Phase to address:** Phase 1 (prompt system foundation) — variable injection must be architectural, not an afterthought.
|
|
|
|
---
|
|
|
|
### Pitfall 8: Italian Language — Prompts Written in English Produce "Translated" Italian
|
|
|
|
**What goes wrong:**
|
|
The system prompt is written in English and asks Claude to "generate content in Italian". Claude generates Italian that is grammatically correct but sounds translated: unnatural phrasing, English idioms translated literally, formal register too stiff for SME B2B social media, or UK English business vocabulary instead of Italian business vocabulary.
|
|
|
|
**Why it happens:**
|
|
Claude is primarily English-trained. When given English instructions to produce Italian output, it "thinks in English and translates". The result passes spell-check but fails the native speaker smell test. B2B content for Italian entrepreneurs has specific vocabulary and register expectations (professional but not academic, action-oriented, concrete benefits).
|
|
|
|
**How to avoid:**
|
|
- Write the system prompt IN Italian (not "write in Italian" from an English prompt). Italian-language instructions produce more natural Italian output.
|
|
- Provide Italian examples in the few-shot section: show Claude an example carousel with the exact tone, vocabulary, and structure you want.
|
|
- Define explicit tone guidelines in Italian: e.g. "Usa il tu, sii diretto, parla di benefici concreti, evita il jargon tecnico".
|
|
- Include a list of Italian B2B vocabulary to use/avoid.
|
|
- Note: Italian prompts cost ~2x more tokens than English equivalents — factor this into cost estimates.
|
|
|
|
**Warning signs:**
|
|
- Generated Italian text uses "fare business" when native would say "fare affari".
|
|
- Carousel titles that sound like SEO headlines rather than Instagram hooks.
|
|
- Formality that oscillates randomly (tu/lei mixed, formal/informal register).
|
|
- User feedback: "sembra scritto con Google Translate".
|
|
|
|
**Phase to address:** Phase 1 — prompt language and tone are foundational decisions, hard to fix post-deployment without regenerating all content.
|
|
|
|
---
|
|
|
|
### Pitfall 9: React Frontend API URL Hardcoded to Absolute Path — Breaks Behind Subpath Proxy
|
|
|
|
**What goes wrong:**
|
|
React frontend makes API calls to `/api/generate`. Behind nginx at `lab.mlhub.it/postgenerator/`, the actual path is `lab.mlhub.it/postgenerator/api/generate`. The frontend sends requests to `lab.mlhub.it/api/generate` which is a different nginx location (or 404). Works in local development, breaks immediately in production.
|
|
|
|
**Why it happens:**
|
|
Developers use Create React App / Vite proxy in development where `/api` works fine. In production, the subpath prefix is not accounted for. `REACT_APP_API_URL` environment variable is set to `/api` (absolute) instead of a relative or base-path-aware URL.
|
|
|
|
**How to avoid:**
|
|
- Use the Vite/CRA `VITE_API_BASE_URL` env var set to an empty string for development (proxy handles it) and `/postgenerator/api` for production builds.
|
|
- Alternatively: serve the React app and FastAPI from the same container with nginx internal routing — browser sees single origin, no CORS, no subpath math.
|
|
- Test the production build (not dev server) against the nginx proxy during Phase 1 deployment, before any feature work.
|
|
- In nginx config, ensure `/postgenerator/api/` proxies to FastAPI and `/postgenerator/` serves the React static files.
|
|
|
|
**Warning signs:**
|
|
- API calls return 404 or hit the wrong service in production but work in `npm run dev`.
|
|
- Browser network tab shows requests to `/api/generate` without the `/postgenerator` prefix.
|
|
- CORS errors in production (requests going to wrong origin because URL resolution failed).
|
|
|
|
**Phase to address:** Phase 1 deployment scaffolding — must be tested before any other development.
|
|
|
|
---
|
|
|
|
## Technical Debt Patterns
|
|
|
|
| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable |
|
|
|----------|-------------------|----------------|-----------------|
|
|
| Store all files in flat directory without job subdirectories | Simple to implement | Hundreds of files mixed together, no cleanup possible | Never — use job-scoped directories from day 1 |
|
|
| Hardcode slide count (5) in prompt template | Fast to write | Config changes break output silently | Never — always inject as variable |
|
|
| Single try/except around entire generation loop | Simple error handling | One failure kills entire batch | Never for bulk — per-item isolation is required |
|
|
| Write CSV as UTF-8 without BOM | Python default | Italian accents corrupt in Excel | Never — use `utf-8-sig` always |
|
|
| Set `root_path` in both FastAPI and Uvicorn | Seems comprehensive | Double-path 404 bug in docs and some calls | Never — set in one place only |
|
|
| Generate all carousels before validating any | Defers complexity | User waits for all, then gets bulk failure | Acceptable in MVP if per-item failure isolation exists |
|
|
| English-language system prompt with "write in Italian" | Easier to write | Translated-sounding Italian output | Never for public-facing product |
|
|
|
|
---
|
|
|
|
## Integration Gotchas
|
|
|
|
| Integration | Common Mistake | Correct Approach |
|
|
|-------------|----------------|------------------|
|
|
| Claude API structured outputs | Using schema with `minimum`/`maximum` constraints and expecting them to be enforced | Constraints are stripped from schema sent to Claude; use Pydantic validation post-response to enforce ranges |
|
|
| Claude API rate limits | Treating 429 as generic error, retrying immediately | Read `retry-after` header; honor exactly; add inter-request delay for bulk jobs |
|
|
| Canva Bulk Create | Column names generated from code schema diverge from template placeholders | Lock column names as constants shared between code and Canva template documentation |
|
|
| Canva Bulk Create | Uploading CSV with row count > 300 | Canva Bulk Create supports max 300 rows per upload batch; split large batches |
|
|
| Claude API OTPM | Generating 20 carousels at full speed in Tier 1 (8,000 OTPM) | Add configurable delay between calls; consider Batches API for non-interactive generation |
|
|
| FastAPI + nginx subpath | Setting `root_path` in FastAPI constructor when nginx does NOT strip prefix | Set root_path only in Uvicorn; configure nginx to strip prefix OR forward full path but not both |
|
|
| React + FastAPI in same Docker container | CORS configuration in FastAPI needed even for same-origin | Use nginx internal routing so browser sees single origin; CORS becomes irrelevant |
|
|
|
|
---
|
|
|
|
## Performance Traps
|
|
|
|
| Trap | Symptoms | Prevention | When It Breaks |
|
|
|------|----------|------------|----------------|
|
|
| Sequential API calls for bulk | 20 carousels take 20x single time; UI shows "loading" with no feedback | Add progress tracking per item; consider async generation with status polling | Any bulk request > 3 items |
|
|
| No prompt caching for repeated system prompt | Each call sends full system prompt, consuming ITPM quota | Use `cache_control: ephemeral` on system prompt; same prompt cached for ~5 min | At Tier 1 OTPM limits with 5+ items in batch |
|
|
| CSV generated in memory for large batches | Memory spike, potential OOM in 256MB container | Stream CSV rows to disk as each carousel is generated | Batches > 50 carousels |
|
|
| File storage without cleanup | Disk fills up on VPS over time | Implement TTL-based cleanup for generated files (e.g., delete after 24h) | After ~1000 generation jobs depending on file size |
|
|
|
|
---
|
|
|
|
## Security Mistakes
|
|
|
|
| Mistake | Risk | Prevention |
|
|
|---------|------|------------|
|
|
| Exposing Claude API key in frontend environment variables | Key leaked via browser DevTools, used for unauthorized API calls | Keep API key server-side only; frontend never sees it |
|
|
| No validation of user-provided topic/industry input before injecting into prompt | Prompt injection: user crafts input that overrides system prompt instructions | Sanitize and length-limit user inputs; wrap user content in explicit delimiters in prompt |
|
|
| Storing generated CSV files accessible at predictable URLs | Users can download others' generated content | Use UUID-based job IDs for file paths; validate job ownership before serving |
|
|
| No API rate limiting on the FastAPI endpoint | Unlimited calls = unlimited Claude API cost | Implement per-IP or per-session rate limiting on the generation endpoint |
|
|
|
|
---
|
|
|
|
## UX Pitfalls
|
|
|
|
| Pitfall | User Impact | Better Approach |
|
|
|---------|-------------|-----------------|
|
|
| No progress feedback during bulk generation | User sees spinner for 60+ seconds, assumes crash, refreshes, loses job | Show per-carousel progress (item 3/10 completed) with estimated time remaining |
|
|
| "Generation failed" error with no actionable info | User does not know if it was their input, the API, or a bug | Distinguish: "API limit reached, retry in X seconds" vs "Input too long" vs "Unexpected error (ID: xxx)" |
|
|
| CSV download triggers browser "open with" dialog | User opens CSV in Excel, encoding corrupts Italian text, blames the tool | Set `Content-Disposition: attachment; filename="carousels.csv"` and add note about Google Sheets |
|
|
| Generated content not previewable before CSV download | User discovers quality issues only after importing to Canva | Show a text preview of at least the first carousel before offering CSV download |
|
|
| No way to regenerate a single carousel | User must redo entire batch to fix one bad result | Allow per-item regeneration from the results view |
|
|
|
|
---
|
|
|
|
## "Looks Done But Isn't" Checklist
|
|
|
|
- [ ] **CSV encoding:** Contains actual Italian accented characters (àèéìòù) — verify download in both browser and Excel, not just code editor
|
|
- [ ] **Canva field mapping:** Test actual Canva import with the generated CSV, not just "the columns look right"
|
|
- [ ] **Rate limit handling:** Test with a batch of 10+ items to trigger actual rate limits in Tier 1
|
|
- [ ] **Subpath routing:** Test production build (Docker container) at nginx subpath, not local `npm run dev`
|
|
- [ ] **FastAPI docs:** Verify Swagger UI at `/postgenerator/docs` works AND API calls from within Swagger work
|
|
- [ ] **Italian quality:** Have a native Italian speaker review generated content, not just verify it is grammatically Italian
|
|
- [ ] **Partial failure:** Kill the process mid-batch and verify partial results are not lost
|
|
- [ ] **Large batch:** Test with 20 carousels (near Tier 1 limits) for both correctness and timing
|
|
- [ ] **Prompt variable injection:** Change slide count in config, verify prompt template reflects the change, verify output slide count matches
|
|
|
|
---
|
|
|
|
## Recovery Strategies
|
|
|
|
| Pitfall | Recovery Cost | Recovery Steps |
|
|
|---------|---------------|----------------|
|
|
| CSV encoding corruption | LOW | Change Python writer to `utf-8-sig`, regenerate affected CSVs |
|
|
| Canva field name mismatch | MEDIUM | Redefine constant, update all templates referencing old names, regenerate |
|
|
| FastAPI double root_path | LOW | Remove `root_path` from FastAPI constructor, set only in Uvicorn, redeploy |
|
|
| Italian quality issues in prompt | HIGH | Rewrite system prompt in Italian, add few-shot examples, re-evaluate all previously generated content |
|
|
| Bulk pipeline data loss (no per-item state) | HIGH | Requires architectural change to generation loop; cannot fix without refactor |
|
|
| Prompt template variable mismatch | MEDIUM | Add validation step, fix template, test all templates in sequence |
|
|
|
|
---
|
|
|
|
## Pitfall-to-Phase Mapping
|
|
|
|
| Pitfall | Prevention Phase | Verification |
|
|
|---------|------------------|--------------|
|
|
| Soft failures in LLM output (Pitfall 1) | Phase 1: Generation pipeline | Validation rejects malformed output in unit tests |
|
|
| Canva column name mismatch (Pitfall 2) | Phase 1: Define Canva field constants | Manual Canva import test with generated CSV |
|
|
| CSV UTF-8 BOM encoding (Pitfall 3) | Phase 1: First CSV output | Open downloaded CSV in Excel on Windows — no garbled chars |
|
|
| FastAPI root_path double bug (Pitfall 4) | Phase 1: Deployment scaffolding | Swagger UI works at `/postgenerator/docs` in Docker |
|
|
| Bulk batch all-or-nothing failure (Pitfall 5) | Phase 1: Per-item error isolation | Force mid-batch failure, verify partial results saved |
|
|
| Rate limit no-backoff (Pitfall 6) | Phase 1: API client layer | Batch of 10 items completes without 429 crashing the job |
|
|
| Prompt template hardcoded values (Pitfall 7) | Phase 1: Prompt template system | Change slide count config, verify template output changes |
|
|
| Italian quality / translated-sounding (Pitfall 8) | Phase 1: Prompt engineering | Native Italian speaker review before any user testing |
|
|
| React API URL subpath bug (Pitfall 9) | Phase 1: Deployment scaffolding | Production build test at nginx subpath URL |
|
|
|
|
---
|
|
|
|
## Sources
|
|
|
|
- [Claude API Rate Limits — official documentation](https://platform.claude.com/docs/en/api/rate-limits) (HIGH confidence — official, accessed 2026-03-07)
|
|
- [Claude Structured Outputs — official documentation](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) (HIGH confidence — official, accessed 2026-03-07)
|
|
- [Canva Bulk Create — Help Center](https://www.canva.com/help/bulk-create/) (MEDIUM confidence — official product page, row/column limits confirmed)
|
|
- [Canva Bulk Create Data Autofill — Help Center](https://www.canva.com/help/bulk-create-data-autofill/) (MEDIUM confidence — 150 field limit confirmed)
|
|
- [FastAPI Behind a Proxy — official docs](https://fastapi.tiangolo.com/advanced/behind-a-proxy/) (HIGH confidence — official)
|
|
- [FastAPI root_path double-path issue — GitHub Discussion #9018](https://github.com/fastapi/fastapi/discussions/9018) (HIGH confidence — confirmed bug with multiple occurrences)
|
|
- [FastAPI Incorrect root_path duplicated prefixes — GitHub Discussion #11977](https://github.com/fastapi/fastapi/discussions/11977) (HIGH confidence)
|
|
- [Building Reliable LLM Pipelines: Error Handling Patterns — ilovedevops](https://ilovedevops.substack.com/p/building-reliable-llm-pipelines-error) (MEDIUM confidence — community, corroborates official rate limit docs)
|
|
- [Retries, fallbacks, circuit breakers in LLM apps — Portkey](https://portkey.ai/blog/retries-fallbacks-and-circuit-breakers-in-llm-apps/) (MEDIUM confidence — practitioner guide)
|
|
- [Non-English Languages Prompt Engineering Trade-offs — LinkedIn](https://www.linkedin.com/pulse/non-english-languages-prompt-engineering-trade-offs-giorgio-robino) (MEDIUM confidence — Italian token cost 2x confirmed)
|
|
- [Evalita-LLM: Benchmarking LLMs on Italian — arXiv](https://arxiv.org/html/2502.02289v1) (MEDIUM confidence — research confirming Italian LLM quality issues)
|
|
- [Canva CSV upload tips — Create Stimulate](https://createstimulate.com/blogs/news/canva-tips-for-uploading-csv-files-using-bulk-create) (LOW confidence — community blog, limited technical detail)
|
|
- [Opening CSV UTF-8 files in Excel — Microsoft Support](https://support.microsoft.com/en-us/office/opening-csv-utf-8-files-correctly-in-excel-8a935af5-3416-4edd-ba7e-3dfd2bc4a032) (HIGH confidence — official Microsoft, confirms BOM requirement)
|
|
|
|
---
|
|
*Pitfalls research for: PostGenerator — LLM-powered Instagram carousel bulk generation (B2B Italian SME)*
|
|
*Researched: 2026-03-07*
|