Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/santiagonieto09/portafolio/llms.txt

Use this file to discover all available pages before exploring further.

The portfolio is configured entirely through environment variables. There are no configuration files to edit and no build-time constants to change — every tuneable behaviour is controlled at runtime via .env. Only GITHUB_TOKEN and CRON_SECRET are required for a hardened production deployment; the application starts and renders correctly with none of them set.

Environment Variables

GITHUB_TOKEN
string
A GitHub Personal Access Token sent as the Authorization: Bearer <token> header on every GitHub REST API request.
  • Why it matters: GitHub’s unauthenticated API allows 60 requests per hour per originating IP address. Setting this token raises that limit to 5,000 requests per hour, which is essential for any production workload.
  • Token type: Classic personal access token (PAT). Fine-grained tokens also work if you grant them read access to public repository metadata.
  • Required scopes: None. All data fetched by the portfolio (user profile, repositories, social accounts, public events) is publicly accessible without any OAuth scope.
  • Security: This variable is consumed exclusively in infrastructure/github/github-api.server.ts. The .server.ts filename convention ensures it is stripped from the client bundle at build time and never sent to the browser.
  • Legacy alias: The server module also accepts GITHUB_API_KEY as a fallback (process.env.GITHUB_TOKEN ?? process.env.GITHUB_API_KEY). GITHUB_TOKEN takes precedence; GITHUB_API_KEY is supported for backwards compatibility only. Set GITHUB_TOKEN for all new deployments.
CRON_SECRET
string
A shared secret that protects the POST /api/public/sync cache-refresh endpoint from unauthorized callers.
  • How it is verified: The endpoint reads the secret from the incoming request’s x-cron-secret header. If that header is absent, it falls back to the Authorization: Bearer <secret> header. If neither matches the configured value, the endpoint returns 503 Service Unavailable.
  • If unset: The /api/public/sync endpoint is disabled entirely and returns 503 for all callers. This is a safe default — the snapshot cache is also refreshed automatically on the next organic page load after the TTL expires.
  • Best practice: Generate a cryptographically random secret (e.g. openssl rand -hex 32) and store it as a secret in your deployment platform and your cron service.
SITE_URL
string
The canonical base URL of the deployed site, for example https://santiagonieto.dev.
  • Used in: The sitemap[.]xml.ts route to build absolute <loc> URLs, and in the <head> of the main page to populate og:url for Open Graph metadata.
  • If unset: The application derives the origin from the incoming HTTP request (request.headers.get('host')) at runtime. This is accurate for most deployments but can produce incorrect results behind reverse proxies that strip the Host header.
  • Format: Include the protocol and no trailing slash: https://santiagonieto.dev ✅, https://santiagonieto.dev/ ❌.

Creating a GitHub Token

1

Open Personal Access Token settings

Log in to GitHub and navigate to Settings → Developer settings → Personal access tokens → Tokens (classic).Direct URL: https://github.com/settings/tokens
2

Generate a new token

Click “Generate new token” and choose “Generate new token (classic)” from the dropdown.
3

Name the token

In the Note field enter a descriptive name such as portfolio-site so you can identify it later.
4

Set an expiration

Choose an expiration that fits your security policy. For a long-running production site, a 1-year expiration is common. Add a calendar reminder to rotate the token before it expires.
5

Select scopes

No scopes are required. Leave all checkboxes unchecked. GitHub allows unauthenticated-equivalent read access to public user profiles and repositories via authenticated requests — the token itself (rather than any attached scope) is what raises the rate limit.
6

Copy and store the token

Click “Generate token” and immediately copy the value — GitHub will not show it again. Add it to your local .env file:
.env
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
For production deployments, store the token as an encrypted environment variable or secret in your platform (Vercel, Cloudflare, GitHub Actions Secrets, etc.).

Cron Sync Scheduling

The snapshot cache has a one-week TTL. For a portfolio that changes infrequently this is acceptable — but if you want the cache to refresh on a predictable schedule rather than on the next organic visit after expiry, you can call POST /api/public/sync from an external cron service. The endpoint is protected by CRON_SECRET. The caller must send the secret in the x-cron-secret header. Here is a complete GitHub Actions workflow that triggers a weekly refresh every Monday at 06:00 UTC:
.github/workflows/sync.yml
name: Weekly portfolio sync
on:
  schedule:
    - cron: '0 6 * * 1'  # Every Monday at 06:00 UTC
jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger sync
        run: |
          curl -X POST ${{ secrets.SITE_URL }}/api/public/sync \
            -H "x-cron-secret: ${{ secrets.CRON_SECRET }}" \
            -H "Content-Type: application/json"
Store SITE_URL (e.g. https://santiagonieto.dev — include the protocol, no trailing slash) and CRON_SECRET as encrypted secrets in your GitHub repository settings so they are never exposed in workflow logs.
Vercel Cron Jobs cannot send custom HTTP headers. Vercel’s built-in cron feature only invokes a URL via a plain GET or POST request with no support for custom headers, making it impossible to pass the x-cron-secret value. Do not use Vercel Cron for this endpoint. Use GitHub Actions (as shown above), Upstash QStash, EasyCron, or any other cron-as-a-service that supports custom request headers.

Runtime Target

The default production build target is Vercel, configured via the Nitro preset in vite.config.ts:
vite.config.ts (excerpt)
nitro: {
  preset: 'vercel',
}
When running inside Lovable’s sandbox environment, the preset is automatically switched to cloudflare-workers to match the Workers runtime. No manual change is needed — the correct preset is injected at build time by the sandbox. The snapshot cache implementation in infrastructure/github/snapshot-cache.ts is runtime-aware:
  • Cloudflare Workers — Uses the Cloudflare Cache API (caches.default) for edge-distributed, persistent caching across all PoPs.
  • Vercel / Node.js — Falls back to an in-process Map when the Cloudflare Cache API is unavailable. This cache is local to each serverless function instance and does not persist across cold starts; the cron sync workflow keeps the cache warm to minimise cold-start fetches in production.

Build docs developers (and LLMs) love