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: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.jsxfiles - 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, andReadableStreamout 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
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
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
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.
| App | Local URL |
|---|---|
| Platform | https://tuturuuu.localhost |
| Calendar | https://calendar.tuturuuu.localhost |
| Chat | https://chat.tuturuuu.localhost |
| CMS | https://cms.tuturuuu.localhost |
| Drive | https://drive.tuturuuu.localhost |
| External | https://external.tuturuuu.localhost |
| Finance | https://finance.tuturuuu.localhost |
| Hive | https://hive.tuturuuu.localhost |
| Hive Realtime | https://realtime.hive.tuturuuu.localhost |
| Inventory | https://inventory.tuturuuu.localhost |
| Learn | https://learn.tuturuuu.localhost |
https://mail.tuturuuu.localhost | |
| Meet | https://meet.tuturuuu.localhost |
| Mind | https://mind.tuturuuu.localhost |
| Nova | https://nova.tuturuuu.localhost |
| Playground | https://playground.tuturuuu.localhost |
| QR | https://qr.tuturuuu.localhost |
| Rewise | https://rewise.tuturuuu.localhost |
| Shortener | https://shortener.tuturuuu.localhost |
| Tasks | https://tasks.tuturuuu.localhost |
| Teach | https://teach.tuturuuu.localhost |
| Track | https://track.tuturuuu.localhost |
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 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:
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:
Start Local Supabase Instance
To start a local supabase instance (database), run the following command:bun
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
Stop Local Supabase Instance
To stop the local supabase instance, run the following command:Better Development Experience
In case you want to run all local development servers, run the following command:bun
Running
devx will:- Stop the currently running supabase instance and save current data as backup (if there is any)
- Install all dependencies
- Start a new supabase instance (using backed up data)
- Start all Next.js apps in development mode
bun devrs instead. This will:- Stop the currently running supabase instance (if there is any)
- Install all dependencies
- Start a new supabase instance (with clean data from seed.sql)
- Start all Next.js apps in development mode
Local development
Seed accounts
There are 5 seed accounts that are already set up for local development: 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
Test
To run all tests, run the following command:bun
bun
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.