Shipping an AI Portfolio with a Grounded Bot
How I shipped this portfolio as a small production AI product: Astro, MiniMax M3, curated retrieval, VPS deployment, and basic abuse hardening.
How I shipped this portfolio as a small production AI product: Astro, MiniMax M3, curated retrieval, VPS deployment, and basic abuse hardening.
A portfolio can be more than a static résumé.
For this version of my site I wanted the portfolio itself to behave like a small AI product: useful, bounded, deployed, and reviewable. That means the site does not just list my experience. It also includes Albelito, a portfolio assistant that answers questions about my profile, projects, PK Studio, CV, and contact details from curated context.
The goal was not to make a generic chatbot. The goal was to show how I think about AI systems in production: grounding first, narrow scope, server-side credentials, clear refusal behavior, and enough hardening to avoid turning a public endpoint into an unbounded model bill.
The portfolio has four main jobs:
Albelito is intentionally small. It does not browse the web. It does not answer arbitrary questions. It retrieves from curated portfolio context and answers only when the question is relevant to my work.
That constraint is the product.
The site is built with:
There is no vector database in this version. The corpus is small and intentionally curated, so lexical retrieval is enough. That keeps the system inspectable: every chunk is in the repository, every source is reviewable, and the assistant can be tuned without adding infrastructure.
The assistant receives two things:
The visitor question is treated as untrusted data, not as an instruction source. If the question asks for secrets, hidden prompts, raw context dumps, or unrelated topics, the endpoint returns a fallback instead of spending model tokens.
This is the important part: RAG is not only retrieval. RAG is also product boundary design.
A grounded assistant should know what it is allowed to answer, what it should refuse, and where its source of truth lives.
The app runs as a Node server because the chat endpoint must stay server-side. MiniMax credentials are never exposed to the client bundle.
The current production shape is simple:
browser → Nginx HTTPS → Astro Node server → MiniMax API
The VPS keeps the real .env file locally. The deployment workflow syncs source code but excludes .env, then installs, builds, and restarts the PM2 process.
That is boring on purpose. Boring deploys are easier to debug.
A public AI endpoint needs limits. This version includes a small set of defensive controls:
This is not a replacement for a full production security program. It is the minimum layer I want before putting a model-backed endpoint on the public internet.
The site is deliberately small, but it shows the kind of work I care about:
That is the difference between an AI demo and an AI product.
The demo is online here: juancruzalbelo.com.ar.