# CloudCLI UI Nginx subpath deployment template.
#
# Purpose:
#   Serve CloudCLI UI from a path prefix such as:
#     http://localhost/ai/
#     https://example.com/ai/
#
# CloudCLI itself still runs at the root of its own HTTP server, for example:
#     http://127.0.0.1:3001/
#
# Nginx receives public requests under /ai, strips that prefix, and forwards the
# remaining path to CloudCLI. For example:
#     /ai/                  ->  /
#     /ai/session/abc       ->  /session/abc
#     /ai/assets/index.js   ->  /assets/index.js
#
# Important Nginx limitation:
#   Nginx does not allow variables in `location` matchers or `rewrite` regexes.
#   The configurable variables below are still useful for proxy/filter values,
#   but if you change /ai to a different subpath, also update every line marked:
#     [SUBPATH LITERAL]
#
# To use a different subpath, replace these literal matchers:
#     location = /ai
#     location ^~ /ai/
#     rewrite ^/ai(?<cloudcli_path>/.*)$ ...
#
# Recommended deployment shape:
#   CloudCLI is the only app using /ai, while root paths /api, /ws, and /shell
#   are also proxied because the current frontend still calls those endpoints
#   with root-relative URLs.

worker_processes 1;

events {
    # Maximum simultaneous connections handled by each worker process.
    # The default is enough for local testing and small self-hosted deployments.
    worker_connections 1024;
}

http {
    # WebSocket requests include an Upgrade header. Normal HTTP requests do not.
    # This map gives us the right Connection header for both cases:
    #   Upgrade present -> "upgrade"
    #   Upgrade absent  -> "close"
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    server {
        # For HTTPS deployments, replace this with `listen 443 ssl http2;` and
        # add ssl_certificate / ssl_certificate_key lines.
        listen 80 default_server;

        # Use your real hostname in production, for example:
        #   server_name cloudcli.example.com;
        server_name localhost 127.0.0.1;

        # ---- User settings -------------------------------------------------
        #
        # Public path prefix where users access CloudCLI.
        # Do not add a trailing slash.
        #
        # This variable can be used in redirects and response rewrites. It
        # cannot be used in `location` matchers, so update the [SUBPATH LITERAL]
        # lines too if you change it.
        set $cloudcli_subpath /ai;

        # Private upstream URL where the CloudCLI server is listening.
        # For a default local server this is usually http://127.0.0.1:3001.
        set $cloudcli_upstream http://127.0.0.1:3001;

        # Allow larger file uploads through the code editor/project file APIs.
        client_max_body_size 200m;

        # Redirect /ai to /ai/ so relative browser URL resolution is stable.
        # [SUBPATH LITERAL] Change `/ai` if you change $cloudcli_subpath.
        location = /ai {
            return 301 $cloudcli_subpath/;
        }

        # Main prefixed CloudCLI UI route.
        #
        # [SUBPATH LITERAL] Change `/ai/` and the `^/ai` rewrite if you change
        # $cloudcli_subpath.
        location ^~ /ai/ {
            # Strip the public subpath before proxying. CloudCLI expects to see
            # root paths such as /, /session/:id, /assets/..., /manifest.json.
            rewrite ^/ai(?<cloudcli_path>/.*)$ $cloudcli_path break;

            # Forward the rewritten request to the private CloudCLI server.
            proxy_pass $cloudcli_upstream;

            # Use HTTP/1.1 so WebSocket upgrade requests can pass through if a
            # browser reaches a socket endpoint under the subpath.
            proxy_http_version 1.1;

            # Preserve useful request metadata for logs and future app support.
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Prefix $cloudcli_subpath;

            # WebSocket upgrade headers. Harmless for normal HTTP requests.
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            # Long-running agent and terminal sessions can stay open for a long
            # time, so avoid closing idle proxied connections too aggressively.
            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;

            # Disable gzip from the upstream response so sub_filter can inspect
            # and rewrite HTML/JSON/JS response bodies.
            proxy_set_header Accept-Encoding "";

            # Rewrite browser-visible root-relative URLs so the runtime can
            # discover that the app is mounted under the subpath.
            #
            # Examples:
            #   href="/manifest.json" -> href="/ai/manifest.json"
            #   src="/assets/app.js"  -> src="/ai/assets/app.js"
            #
            # These rewrites are important for React Router basename detection.
            sub_filter_once off;
            sub_filter_types
                application/json
                application/manifest+json
                application/javascript
                text/javascript;

            sub_filter 'href="/' 'href="$cloudcli_subpath/';
            sub_filter 'src="/' 'src="$cloudcli_subpath/';

            # The production HTML and JS register the service worker at /sw.js.
            # Rewrite that registration so the worker is served from /ai/sw.js.
            sub_filter "register('/sw.js')" "register('$cloudcli_subpath/sw.js')";
            sub_filter 'register("/sw.js")' 'register("$cloudcli_subpath/sw.js")';

            # The manifest and service worker contain root-relative paths too.
            # Rewriting them keeps PWA metadata and cached manifest requests
            # under the same public subpath.
            sub_filter '"start_url": "/"' '"start_url": "$cloudcli_subpath/"';
            sub_filter '"scope": "/"' '"scope": "$cloudcli_subpath/"';
            sub_filter '"src": "/' '"src": "$cloudcli_subpath/';
            sub_filter "'/manifest.json'" "'$cloudcli_subpath/manifest.json'";
            sub_filter '"/manifest.json"' '"$cloudcli_subpath/manifest.json"';
        }

        # Root API proxy.
        #
        # The current CloudCLI frontend calls APIs with root-relative URLs such
        # as /api/auth/login. Keep this location unless the frontend becomes
        # fully prefix-aware for API requests.
        location ^~ /api/ {
            proxy_pass $cloudcli_upstream;

            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Prefix $cloudcli_subpath;

            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;
        }

        # Main app WebSocket proxy.
        #
        # The frontend opens /ws for realtime chat/session/task updates.
        location /ws {
            proxy_pass $cloudcli_upstream;

            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Prefix $cloudcli_subpath;

            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;
        }

        # Shell WebSocket proxy.
        #
        # The browser terminal uses /shell. It requires the same WebSocket
        # upgrade handling as /ws.
        location /shell {
            proxy_pass $cloudcli_upstream;

            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Prefix $cloudcli_subpath;

            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;
        }

        # Optional health endpoint proxy used by the frontend version checker.
        location = /health {
            proxy_pass $cloudcli_upstream;

            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Prefix $cloudcli_subpath;
        }
    }
}
