Skip to main content
Prerequisite: You should have installed Node.js (version 20 or higher).

Installation

Step 1. Install bun on your machine (if you don’t already have it yet), by running the following command: macOS/Linux:
curl -fsSL https://bun.sh/install | bash
Windows:
powershell -c "irm bun.sh/install.ps1 | iex"

Why Bun?

We chose bun as our runtime and package manager based on its design goals, which align perfectly with our platform’s needs:
  • 4x Faster Startup: Bun processes start significantly faster than Node.js, improving development experience and CI/CD performance
  • Built-in TypeScript & JSX Support: No need for additional transpilation setup - bun natively executes .ts, .tsx, and .jsx files
  • All-in-One Toolkit: Combines runtime, package manager, bundler, test runner, and script runner in a single executable
  • Web Standards Compatibility: Implements modern Web APIs like fetch, WebSocket, and ReadableStream out of the box
  • Node.js Compatibility: Drop-in replacement for Node.js with full compatibility for existing projects
  • Better Performance: Powered by JavaScriptCore engine with reduced memory usage and faster execution
These benefits make bun an ideal choice for our monorepo architecture and development workflow. Step 2. Configure Tiptap Pro Registry:
This step is no longer needed.
Step 3. After configuring Tiptap Pro registry, you can install all dependencies by running the following command:
bun install
This repository’s Bun configuration enforces a minimum release age of 1 day for new npm package versions. If Bun skips a just-published release during install, wait for the package to age past the gate or choose an older published version. To complete the initial setup, please restart your IDE so that it can recognize the newly installed dependencies. Additionally, some recommended VS Code Extensions may only work after restarting your IDE.
If you’re using VS Code, you can install following the recommended extensions that will help you with the development process: ESLint, Prettier, Vitest, Tailwind CSS IntelliSense, Version Lens, Error Lens, Pretty TypeScript Errors, Material Icon Theme.

Zed

This monorepo tracks project-level Zed settings in .zed/settings.json. Opening the repository root in Zed can otherwise trigger expensive scans across generated output and local dependency trees, especially node_modules, .turbo, .next, package dist directories, Flutter build output, Rust target, and Python virtualenv/cache folders. Keep large generated directories in file_scan_exclusions. Zed’s file_scan_exclusions setting replaces the default list instead of extending it, so include Zed’s default VCS/system exclusions whenever adding project exclusions. The project also uses a single TypeScript language server path for TypeScript, TSX, and JavaScript; avoid enabling both tsgo and vtsls for the same language unless you are deliberately comparing language server behavior.

Development

Start Next.js apps

To develop all apps and packages (without requiring a local setup), run the following command:
bun
bun dev
This command will start all Next.js apps in development mode. You can access the platform app by visiting the following URL: https://tuturuuu.localhost
Local app development uses Portless, so each app gets a stable Tuturuuu subdomain instead of relying on its fallback port. The app package dev scripts run the repo’s Portless-safe wrapper, and the underlying framework command remains available through dev:app for direct port-based debugging. The wrapper only removes stale static aliases for the same app when their default backend port is closed, then starts Portless with the original app config. This fixes old worktree aliases such as zalo-qr-chat-setup.tuturuuu.localhost without cleaning certificates, deleting unrelated routes, or touching other apps’ active aliases. Package-local bun dev --force delegates to portless run --name <app> --force so Portless can take over a live route when you explicitly request it. Root app-specific commands such as bun dev:chat, bun dev:calendar, and bun dev:edu reuse app servers that are already running. The launcher checks active Portless routes first, then the app’s default localhost port; if it finds a direct localhost listener, it tries to register a matching Portless alias so cross-app auth can still use the *.tuturuuu.localhost URL. Pass --force or --no-reuse when you intentionally want the command to include already-running app workspaces. Force mode starts the package dev --force path so Portless can take over the matching route instead of leaving a stale static alias in place. bun dev:chat also manages the local chat realtime sidecar. It reuses localhost:7817 when a sidecar is already running; otherwise it starts apps/chat-realtime so apps/web can proxy chat SSE traffic for apps/chat.
AppLocal URL
Platformhttps://tuturuuu.localhost
Calendarhttps://calendar.tuturuuu.localhost
Chathttps://chat.tuturuuu.localhost
CMShttps://cms.tuturuuu.localhost
Drivehttps://drive.tuturuuu.localhost
Externalhttps://external.tuturuuu.localhost
Financehttps://finance.tuturuuu.localhost
Hivehttps://hive.tuturuuu.localhost
Hive Realtimehttps://realtime.hive.tuturuuu.localhost
Inventoryhttps://inventory.tuturuuu.localhost
Learnhttps://learn.tuturuuu.localhost
Mailhttps://mail.tuturuuu.localhost
Meethttps://meet.tuturuuu.localhost
Mindhttps://mind.tuturuuu.localhost
Novahttps://nova.tuturuuu.localhost
Playgroundhttps://playground.tuturuuu.localhost
QRhttps://qr.tuturuuu.localhost
Rewisehttps://rewise.tuturuuu.localhost
Shortenerhttps://shortener.tuturuuu.localhost
Taskshttps://tasks.tuturuuu.localhost
Teachhttps://teach.tuturuuu.localhost
Trackhttps://track.tuturuuu.localhost
When debugging without Portless, run an app’s dev:app script directly. If auth redirects or absolute links must stay on the raw listener port, set BASE_URL, WEB_APP_URL, or the app-specific URL environment variable to that legacy fallback port for the direct debug session. Keep runtime defaults, auth redirects, and cross-app links on the Portless origins during local development. Use the shared local app URL helpers instead of hard-coding localhost fallbacks in satellite app constants or proxies, so a browser session that starts on tasks.tuturuuu.localhost stays under the tuturuuu.localhost namespace through login and return URLs. For a native production-mode smoke test of apps/web, run the native build and then start it through the same Portless hostname:
bun run build:web
cd apps/web
bun run start
bun run start delegates to Portless and runs the built Next.js server through start:app, so the browser URL remains https://tuturuuu.localhost while the server listens on the backend port that Portless injects through PORT. Use bun dev:edu when working on the education apps together. It starts Learn, Teach, their shared packages, and the central web app so cross-app login can complete locally. Next.js still prints the internal listener port, for example http://localhost:4803, because Portless assigns a free backend port to the app process. App dev:app scripts also print a Portless URL: line from the PORTLESS_URL environment variable; use that URL in the browser:
Portless URL: https://tuturuuu.localhost
If Turbo cannot prompt for the Portless sudo password while starting app dev scripts, run the Portless setup helper first:
bun portless:setup
The helper starts the Portless HTTPS proxy on port 443 before Turbo launches package dev scripts. It no-ops when the proxy is already responding and skips in non-interactive shells or CI. bun setup runs this helper after dependency installation so fresh local checkouts are ready before the build step, then invokes Turborepo through the repo-local turbo:local helper instead of any globally installed Turbo binary. To install Portless as an OS startup service instead of only starting the current proxy daemon, run:
bun portless:setup -- --service

Start Local Supabase Instance

To start a local supabase instance (database), run the following command:
bun
bun sb:start
This command will start a local supabase instance on your machine. You can access the supabase instance by visiting the following URL: http://localhost:8003
You need to have Docker installed and running on your machine to start a local supabase instance.

Stop Local Supabase Instance

To stop the local supabase instance, run the following command:
bun sb:stop

Better Development Experience

In case you want to run all local development servers, run the following command:
bun
bun devx
Running devx will:
  1. Stop the currently running supabase instance and save current data as backup (if there is any)
  2. Install all dependencies
  3. Start a new supabase instance (using backed up data)
  4. Start all Next.js apps in development mode
If you want to have the same procedure without the backup, you can run bun devrs instead. This will:
  1. Stop the currently running supabase instance (if there is any)
  2. Install all dependencies
  3. Start a new supabase instance (with clean data from seed.sql)
  4. Start all Next.js apps in development mode
In case you don’t want to run a local supabase instance, you can run bun dev instead.

Local development

Seed accounts

There are 5 seed accounts that are already set up for local development:
  1. local@tuturuuu.com
  2. user1@tuturuuu.com
  3. user2@tuturuuu.com
  4. user3@tuturuuu.com
  5. user4@tuturuuu.com
You can use any of these accounts to log in to the app and quickly test the functionality of the app, since they are already set up with the necessary data.

Authentication

A local mail server (InBucket) is automatically set up by Supabase to handle authentication emails.
You can access the mail server by visiting the following URL: http://localhost:8004

Build

To build all apps and packages, run the following command:
bun
bun run build

Test

To run all tests, run the following command:
bun
bun run test
To run the Flutter mobile quality gate, use:
bun
bun check:mobile
bun check:mobile runs Dart format, Flutter analyze, and Flutter tests for apps/mobile. Flutter test output is streamed by default so slow suites still show progress instead of appearing stuck.
Tests are still a work in progress. We’re currently working on adding tests to all packages to ensure the best quality possible.

Git Conventions

Tuturuuu uses standardized conventions for Git commits and branch naming. For more information, see the Git Conventions guide to learn how to format your commits and branch names to align with our workflow.