Turbo Boilerplate

repository·main·Indexed 19 days ago

https://github.com/unfoldadmin/turbo

A monorepo boilerplate combining a Django REST API backend with a Next.js frontend. It supports multiple microsites sharing a single backend and common UI/type packages, featuring authentication via django-simplejwt and next-auth, and dependency management using uv and pnpm.

Tokens
16.6K
Snippets
52
Records
66
Agent score
64%

What's inside unfoldadmin-turbo

  1. Understand the frontend project structure

    main

    Turbo uses a monorepo structure for the frontend to support multiple microsites (apps) sharing common logic and UI components.

    frontend
    | - apps       // Available Next.js sites (e.g., 'web')
    | - packages   // Shared packages
    |   - types    // Exported types from the backend API
    |   - ui       // General UI components

    Using shared packages

    If you create a new package in packages/, you must install it into your specific website project to use it:

    docker compose exec web pnpm --filter web add @frontend/ui
  2. Quickstart Turbo boilerplate

    main

    To start using Turbo, clone the repository and use Docker Compose to handle the installation process. You must have docker compose installed and preconfigure environment files before running the containers.

    1. Clone the repository:
    git clone https://github.com/unfoldadmin/turbo.git
    cd turbo
    1. Configure environment files: Copy the templates to active .env files. You must set SECRET_KEY in the backend and NEXTAUTH_SECRET in the frontend.
    cp .env.backend.template .env.backend
    cp .env.frontend.template .env.frontend
    1. Run the stack:
    docker compose up

    Once running, the frontend is available at http://localhost:3000 and the backend at http://localhost:8000.

    git clone https://github.com/unfoldadmin/turbo.git
    cd turbo
    cp .env.backend.template .env.backend
    cp .env.frontend.template .env.frontend
    docker compose up
  3. Run the backend test suite

    main

    The backend test suite uses pytest with pytest-django and pytest-factoryboy. Tests are located in the backend/api/tests directory. You can run all tests, specific files, or individual test cases using docker compose exec to run commands inside the api container via uv.

    Key test files for configuration and data generation:

    • conftest.py: Pytest configuration.
    • factories.py: Reusable test objects using factory_boy.
    • fixtures.py: Shared pytest fixtures.
    # Run all tests in the backend/api/tests folder
    docker compose exec api uv run -- pytest .
    
    # Run tests in a specific file
    docker compose exec api uv run -- pytest api/tests/test_api.py
    
    # Run a specific test by name using the -k flag
    docker compose exec api uv run -- pytest api/tests/test_api.py -k "test_api_users_me_authorized"
  4. Develop in VS Code using Dev Containers

    main

    The project includes Dev Container configurations to allow development directly inside the project containers.

    To use this feature:

    1. Open the project in VS Code.
    2. When the popup appears, click Reopen in Container.
    3. If the popup doesn't appear, use the command Dev Containers: Reopen in Container from the command palette.
    4. To switch between the frontend and backend environments, use the Dev Containers: Switch container action.
    5. To exit the container and work in the local filesystem, use Dev Containers: Reopen Folder Locally.
  5. Add a new microsite to Docker Compose

    main

    To add a new customer-facing website, create a new project under the frontend/apps/ directory and update docker-compose.yaml with a new service definition. Ensure you assign a unique port.

    Example configuration for docker-compose.yaml:

    new_microsite:
      command: bash -c "pnpm install -r && pnpm --filter new_microsite dev"
      build:
        context: frontend
      volumes:
        - ./frontend:/app
      expose:
        - "3001"
      ports:
        - "3001:3001"
      env_file:
        - .env.frontend
      depends_on:
        - api
  6. Handle Authentication in Turbo

    main

    Authentication is handled via django-simplejwt on the backend and next-auth on the frontend. The core business logic resides in frontend/web/lib/auth.ts.

    Creating User Accounts

    1. Superuser: Required for Django Admin access. Run:
      docker compose exec api uv run -- python manage.py createsuperuser
    2. Registration: Users can register via the frontend. Note that new accounts are inactive by default and must be activated by a superuser in the Django Admin.

    Protecting Frontend Routes

    To restrict access to authenticated users, use getServerSession with the authOptions exported from @/lib/auth.

    Example: Protecting a Page

    import { getServerSession } from "next-auth";
    import { redirect } from "next/navigation";
    import { authOptions } from "@/lib/auth";
    
    const SomePageForAuthenticatedUsers = async () => {
      const session = await getServerSession(authOptions);
    
      if (session === null) {
        return redirect("/");
      }
    
      return <>content</>;
    };

    Example: Protecting a Layout (Multiple Pages)

    import { redirect } from "next/navigation";
    import { getServerSession } from "next-auth";
    import { authOptions } from "@/lib/auth";
    
    const AuthenticatedLayout = async ({ children }: { children: React.ReactNode }) => {
      const session = await getServerSession(authOptions);
    
      if (session === null) {
        return redirect("/");
      }
    
      return <>{children}</>;
    };
    
    export default AuthenticatedLayout;
    import { getServerSession } from "next-auth";
    import { redirect } from "next/navigation";
    import { authOptions } from "@/lib/auth";
    
    const session = await getServerSession(authOptions);
    if (session === null) {
      return redirect("/");
    }
  7. Configure environment variables for Turbo

    main

    Turbo uses two primary environment files loaded via Docker Compose. Variables defined here are available within the containers.

    Backend (.env.backend)

    • Set SECRET_KEY for Django security.
    • Set DEBUG=1 to enable debug mode.
    • Important: Ensure DATABASE_PASSWORD matches the credentials used in docker-compose.yaml.

    Frontend (.env.frontend)

    • Set NEXTAUTH_SECRET to a secure value. You can generate one using:
      openssl rand -base64 32
    • For advanced configurations (e.g., per-microsite variables), refer to the official Next.js documentation.
    # Generate a secret for NEXTAUTH_SECRET
    openssl rand -base64 32
  8. Configure Django environment variables

    main

    The backend API uses environment variables to configure core settings. If these are not provided, the system falls back to default values or generates random ones.

    Key environment variables:

    • SECRET_KEY: The Django secret key. If not provided, a random key is generated.
    • DEBUG: Set to "1" to enable debug mode.
    • DATABASE_USER: The PostgreSQL database username (defaults to postgres).
    • DATABASE_PASSWORD: The PostgreSQL database password (defaults to change-password).
    • DATABASE_NAME: The PostgreSQL database name (defaults to db).
    • DATABASE_HOST: The PostgreSQL database host (defaults to db).
  9. Communicate with the Backend API

    main

    Turbo uses Next.js Server Actions (located in frontend/apps/web/actions/) to communicate with the Django backend. This ensures requests are handled on the server side.

    API Client

    Communication is managed by an API client generated via openapi-typescript-codegen. Use the getApiClient function found in frontend/apps/web/lib/api.ts, which is pre-configured with authentication tokens and default options.

    Updating the TypeScript Schema

    Whenever the backend API changes (e.g., new fields in serializers), you must regenerate the frontend TypeScript definitions:

    docker compose exec web pnpm openapi:generate

    API Documentation

    • Swagger UI: Available at http://localhost:8000/api/schema/swagger-ui/.
    • Client-side requests: For requests made directly from the browser (rather than Server Actions), it is recommended to use react-query.
  10. Manage backend dependencies with uv

    main

    The Django backend uses uv for dependency management. When running via docker compose, the system automatically checks for and installs new dependencies before starting the development server.

    To manually add a new dependency to the backend, use docker compose exec api uv add <package_name>.

    Key Backend Dependencies:

    • djangorestframework: REST API support
    • djangorestframework-simplejwt: JWT authentication
    • drf-spectacular: OpenAPI schema generation
    • django-unfold: Admin theme
    docker compose exec api uv add djangorestframework
  11. Manage frontend dependencies with pnpm

    main

    Frontend dependencies are managed via pnpm and are split into global dependencies (available to all sites/packages) and project-specific dependencies.

    Install a global dependency

    Use the -w flag to add a dependency to the workspace root:

    docker compose exec web pnpm add <package_name> -w

    Install a project-specific dependency

    Use the --filter flag to target a specific app or package:

    docker compose exec web pnpm --filter <package_name> add <package_name>

    Key Frontend Dependencies:

    • next-auth: Authentication
    • react-hook-form: Form handling
    • tailwind-merge: Tailwind CSS utility
    • zod: Schema validation
    # Global dependency
    docker compose exec web pnpm add react-hook-form -w
    
    # Specific app dependency
    docker compose exec web pnpm --filter web add react-hook-form
  12. Customize the Unfold admin interface

    main

    The UNFOLD configuration dictionary allows you to customize the appearance and navigation of the Unfold admin dashboard. You can set the site header/title and define a custom sidebar with navigation items, icons, and links (using reverse_lazy).

    UNFOLD = {
        "SITE_HEADER": _("Turbo Admin"),
        "SITE_TITLE": _("Turbo Admin"),
        "SIDEBAR": {
            "show_search": True,
            "show_all_applications": True,
            "navigation": [
                {
                    "title": _("Navigation"),
                    "separator": False,
                    "items": [
                        {
                            "title": _("Users"),
                            "icon": "person",
                            "link": reverse_lazy("admin:api_user_changelist"),
                        },
                        {
                            "title": _("Groups"),
                            "icon": "label",
                            "link": reverse_lazy("admin:auth_group_changelist"),
                        },
                    ],
                },
            ],
        },
    }