Skip to content

Enable Cloud-Based Development with Codespaces#58

Open
collisdigital wants to merge 8 commits intohunvreus:developmentfrom
collisdigital:feat/devcontainer-setup
Open

Enable Cloud-Based Development with Codespaces#58
collisdigital wants to merge 8 commits intohunvreus:developmentfrom
collisdigital:feat/devcontainer-setup

Conversation

@collisdigital
Copy link

@collisdigital collisdigital commented Feb 6, 2026

Summary

This PR introduces full support for cloud-based development using VS Code Codespaces and local Dev Containers. It addresses the limitation where the application relies on absolute URLs which caused breakages when running behind port-forwarding proxies in the cloud.

Key Changes

1. Cloud-Native Development Infrastructure

  • Added a .devcontainer.json configuration to enable one-click setup in GitHub Codespaces or local VS Code Dev Containers.
  • Pre-configured the environment with Python 3.13, Docker-in-Docker support, GitHub CLI, and essential VS Code extensions.
  • Automated the setup process via postCreateCommand to bootstrap the data/ directory and initialize the .env file.
  • Added VS Code Launch Configurations ( .vscode/launch.json ) to support interactive debugging of the FastAPI application and background workers via debugpy (attach a Python debugger to the running app in the container).
  • Added VS Code Settings (.vscode/settings.json) for spell checking dictionary (works with the VS Code spell check extension installed via the devcontainer) ensures that README.md has no spelling errors.

2. Transition to Relative URLs

Standard url_for helpers in FastAPI/Starlette generate absolute URLs by default. In Codespaces, these URLs often point to the internal container port (e.g., http://localhost:80), which fails when accessed via the forwarded public URL.

  • Introduced a RelativeURL utility and rel_url_for template helper in app/dependencies.py to generate path-only URLs (e.g., /login).
  • Migrated all Jinja2 templates and FastAPI routers to use relative URLs for internal navigation and HTMX fragments.

3. Dynamic Base URL Resolution

For scenarios where absolute URLs are strictly required (OAuth callbacks for GitHub/Google, email magic links, and SSE logic):

  • Implemented get_app_base_url in app/utils/urls.py, which intelligently resolves the public endpoint by checking X-Forwarded-Host and X-Forwarded-Proto headers set by Codespaces and Traefik.
  • Updated authentication flows to use these dynamically resolved absolute URLs, ensuring redirections work seamlessly across local, cloud, and production environments.

4. Enhanced Security & Redirection

  • Added a safe_redirect helper in app/utils/urls.py to validate redirect targets. This prevents open-redirect vulnerabilities by ensuring next parameters are either relative or strictly same-origin.

5. Updated Documentation

  • Rewrote the "Development" section of the README.md to provide clear instructions for Codespaces usage, manual setup, and interactive debugging.

Benefits

  • Zero-Config Onboarding: New contributors can start developing in seconds with a fully configured environment in the browser.
  • Improved DX: Support for interactive debugging and consistent environments eliminates "works on my machine" issues.
  • Improved Proxy Compatibility: The transition to relative URLs and dynamic base URL resolution makes the app more resilient when deployed behind complex networking stacks.

How to Test

image
  • The first time booting the Codespace can take a few minutes (it is fast the next time as the image is cached).
  • Edit the data/.env as usual and start the app scripts/start.sh from the integrated Terminal (CMD-J).
  • You will be prompted to "Open in Browser" once the app starts, click this to launch a new tab connecting to the port-forwarded app it will look like https://glorious-cod-7vp76vvw9gpcwrvv-80.app.github.dev/auth/login or similar (this is the same as a local http://localhost:80/auth/login
  • Note you may have to wait a few minutes the first time for everything to start working after running start.sh

Note: This PR involves widespread changes to templates and routers to ensure consistent URL handling throughout the codebase.

collisdigital and others added 8 commits February 4, 2026 10:23
* refactor: use relative URLs for internal links and redirects

Updates the application to use relative URLs for internal navigation and redirects, fixing issues with dynamic hostnames in environments like GitHub Codespaces.
- Introduced `RelativeURL` wrapper and `rel_url_for` helper.
- Introduced `get_app_base_url` for resolving absolute URLs using `X-Forwarded-Host`.
- Refactored templates to use `rel_url_for`.
- Refactored routers to use relative URLs for redirects and `get_app_base_url` for emails/OAuth.
- Introduced `get_absolute_url` helper to reduce duplication.
- Introduced `get_email_logo_url` helper.
- Updated routers to use the new helpers.
- Updated `get_app_base_url`, `get_absolute_url`, and `get_email_logo_url` to accept an optional `client_origin` argument.
- Implemented logic to prioritize `client_origin` (from frontend) when `APP_HOSTNAME` is a localhost variant, ensuring correct links in development environments like Codespaces.
- Updated authentication, user settings (email change), and team settings (add member) routers to pass the `client_origin` from the form data to the URL generation helpers.
- This ensures email links point to the correct external domain (e.g. the Codespaces proxy URL) rather than the internal container hostname.

* fix: handle missing oauth configuration gracefully

- Added checks for `oauth_client` being `None` in `app/routers/google.py`, `app/routers/github.py`, and `app/routers/auth.py` before accessing attributes.
- This prevents `AttributeError: 'NoneType' object has no attribute 'google'` (or 'github') when the respective OAuth provider is not configured.
- This ensures the application starts and handles missing configuration correctly, redirecting or showing an error message instead of crashing.

* Update README and lib.sh to clarify Codespaces setup and dev mode

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: collisdigital <14041600+collisdigital@users.noreply.github.com>
* Fix Google OAuth redirect URI for dynamic hostnames (e.g. Codespaces)

Pass `client_origin` from frontend to backend during Google OAuth initiation.
Store `client_origin` in session and use it to construct the correct `redirect_uri` for both authorization and token exchange.
This resolves issues where `localhost` was used instead of the dynamic public URL.

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: collisdigital <14041600+collisdigital@users.noreply.github.com>
* feat: implement interactive Python debugging for 'app' service

- Modify `compose/override.dev.yml` to expose port 5678 for the `app` service.
- Update `docker/entrypoint.app.dev.sh` to conditionally run `debugpy` if `DEBUG=true`.
- Create `.vscode/launch.json` with "Python: Remote Attach" configuration.
- Update `.devcontainer.json` to install `ms-python.debugpy` and forward ports 5678 and 8000.
- Update `README.md` with instructions on how to use debugging.

* Fix Google Auth bug - redirect was set to invalid URL (missing '/user/') and callback code was wrong (reverted previous change)

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: collisdigital <14041600+collisdigital@users.noreply.github.com>
* fix(auth): support dynamic origin for GitHub OAuth

Update GitHub OAuth flow to support client-side origin resolution, enabling correct redirect URIs when running in environments like GitHub Codespaces.

- Update `github_authorize` to accept and store `client_origin`.
- Update frontend templates to pass `client_origin` via `onclick` handler in GitHub Connect buttons.
- Use `get_absolute_url` for consistent URL generation.

---------

Co-authored-by: collisdigital <14041600+collisdigital@users.noreply.github.com>
Removed redundant steps in the debugging instructions for clarity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant