ouorz-mono: one monorepo for a site, a headless CMS and an analytics app
A Monorepo for My ( :earth_asia: Personal Website / :microscope: Academic Profile ) and { Other Related Projects }
At a glance
- What is it?
- ouorz-mono is the monorepo behind a personal website and academic profile, and it has grown into four applications and a design system: a Next.js main app, a WordPress instance used as a headless CMS, an analytics service based on Umami, and the Twilight Toolkit component library. The README describes the stack as super opinionated and completely overkill, which is an accurate summary of a personal site with a Turborepo, Bun workspaces, WordPress in Docker and Nexment on LeanCloud for comments.
- Who is it for?
- ouorz-mono fits a developer who wants one repository to hold a personal site, the CMS behind it, the analytics that measure it and a shared component library, and who is prepared to live with a large amount of infrastructure for a small site.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A personal site that grew into four applications
The repository is described as a monorepo for a personal website, an academic profile and other related projects, and the README says it is the source code and Docker image that power lipeng.ac.
The tree tells you how far it has come. There is an apps/ directory, a packages/ directory, a tools/ directory, turbo.json for the task runner, a bun.lock for the workspace, lefthook.yml for the git hooks, and a commitlint configuration. The applications named in the scripts are the main app, a preview app, the analytics app and the WordPress app, and the packages are the Twilight Toolkit's ui and utils packages plus a twilight-protocol package.
There is also a history section, which is unusual to see in a README and useful to read. The main app has been through three previous generations. Antony-Nuxt used Nuxt.js with Vue.js v2, then Antony used Vue.js v2, then Tony used Vue.js v2 with PHP. The current one is React with Next.js, so the stack has been rewritten three times, which tells you the author is comfortable replacing things.
The project is GPL-3.0, the homepage is lipeng.ac, the last push was on 2026-10-15, and the two published releases are old, 0.0.1 in January 2021 and 0.0.2 in November 2021, so the versioning reflects the website rather than the code.
The main app and its deliberately excessive stack
The feature list for the main app is short: SSR, SSG and on-demand ISR, a command palette, Redux with Redux Saga, a Nexment comment system, a dynamic table of contents sidebar, a personal dashboard, and dark mode.
The stack behind it is where the tone comes from. The README calls it super opinionated and completely overkill, and then lists TypeScript, React with Next.js, Storybook, Turborepo with Bun workspaces, SWR for data fetching with infinite loading, revalidation and Suspense, fetch for API routes, Redux Toolkit with Redux Saga, styled-components and Tailwind CSS, WordPress with Qiniu for static file storage and the WP REST API with a GraphQL implementation coming soon, Tencent Cloud CVM running CentOS, Nginx, MySQL and PHP, Nexment on LeanCloud, and Listmonk for the newsletter. Error logging and web vitals metrics go to Sentry. Linting and formatting are Oxlint with vendored anti-slop and no-comment-walls plugins, plus Oxfmt, and CommitLint runs through Lefthook. CI and deployment are GitHub Actions and Vercel.
The interesting entries are the two that are unusual. The lint plugins are described as vendored, and the names say what they are for, which tells you the author has been fighting a specific problem with generated or boilerplate code. And the WordPress part is the CMS, which is the next section.
The setup is three commands.
git clone [email protected]:ttttonyhe/ouorz-mono.git
bun install
cd apps/mainThen you create a .env file, with the LeanCloud keys NEXT_PUBLIC_LC_KEY and NEXT_PUBLIC_LC_ID, the Sentry variables NEXT_PUBLIC_SENTRY_DSN, SENTRY_AUTH_TOKEN, SENTRY_PROJECT and SENTRY_ORG, and REVALIDATION_REQUEST_TOKEN for on-demand ISR. The dev command is bun run dev:main.
WordPress as a headless CMS, in a container
The WordPress app is a separate service, and the README is unusually blunt about what it costs.
Running WordPress in a Docker container is extremely slow on lower-spec machines, and at least 1 GB of RAM without MySQL 8, or 2 GB with MySQL 8, is recommended. The container is built on the official WordPress image, wordpress:php8.0-apache.
Two design decisions follow from the container being static. Each build outputs a static Docker image, similar to a typical containerised application, which means updating WordPress itself or adding themes or plugins requires redeployment. And all uploads are stored in an external store, Qiniu, which is similar to AWS S3, so wp-content/uploads can be treated as temporary data.
That second decision is the one that makes the architecture coherent. The container is disposable, the content is not in it, and the uploads are not in it either, so a redeploy does not lose anything.
The role of WordPress is also narrowed. The main app uses the WordPress REST API to fetch data, and the WordPress app functions as a headless CMS. The custom theme named peg is used to customise the behaviour of the REST API endpoints, and peg/functions.php is therefore the main focus when developing the WordPress app.
For local development the container is built and run with the database variables passed in.
docker build --tag ouorz-wordpress .
docker run -p 8080:80 \
-e WORDPRESS_DB_HOST=[dev_database_host] \
-e WORDPRESS_DB_USER=[dev_database_user] \
-e WORDPRESS_DB_PASSWORD=[dev_database_pwd] \
-e WORDPRESS_DB_NAME=[dev_database_name] \
-e WORDPRESS_DEBUG=true \
-e WORDPRESS_TABLE_PREFIX=[dev_database_prefix] \
ouorz-wordpressBeyond the database variables there is WORDPRESS_DEBUG, and an optional WORDPRESS_CONFIG_EXTRA that can carry extra PHP configuration, with the README showing examples for a MySQL SSL client flag, turning off PHP warnings and notices, and defining a Redis object cache.
The analytics app, and the one key you have to go and get
The analytics app is based on Umami, and the setup differs from the other two in a useful way: it needs a licence key from a third party before it will do anything useful.
The instructions are to follow the Maxmind documentation to sign up for GeoLite2 and retrieve a licence key, because the geolocation data comes from there. The environment variables for the app are DATABASE_URL, HASH_SALT and MAXMIND_LICENSE_KEY, and the setup is the same three commands as the main app, ending with a different directory, and the run command is a filtered build of the PostgreSQL client followed by the dev script.
bun run --filter '@ouorz/analytics' build-postgresql-client
bun run dev:analyticsThe separate build step for the PostgreSQL client is the kind of detail that suggests a native dependency, and it is a reminder that this is not a hosted service you point at a database URL and forget.
Umami is chosen because it is the analytics tool a self-respecting self-hosted site would use, and the fact that it needs a geolocation database is the price of the feature, since the point of the app is to tell you where the visitors are.
Twilight Toolkit, a library that is mostly a Storybook
Twilight Toolkit is described as a super opinionated front-end toolkit library, and its Storybook is published at ui.twilight-toolkit.ouorz.com.
The state of it is honest in the README. The UI is currently only available in React, with the Foundation and Adaptor implementation coming soon, and the utilities section is marked work in progress.
So this is a component library in the making, and the Storybook is its primary interface, which is the right way to build one. There is a packages/twilight-protocol directory with Solidity contracts, linted with Solhint and formatted with Prettier through a separate script, which explains the Solhint configuration files in the repository root alongside the TypeScript ones.
The naming is worth a note, because the repository is ouorz-mono and the toolkit is Twilight, and the past iterations had the author's own name in them, Antony and Tony. The current name is a wordplay on the author's handle, and the pattern of renaming as the project moves on is consistent with the three previous generations of the main app.
Monorepo practices, and the one rule about the root manifest
The monorepo section lists the tooling and then a set of practices that are worth reading, because they are the difference between a monorepo that works and one that fights you.
The build system is Turborepo with remote caching, the package manager is Bun workspaces, the linter is Oxlint, the formatter is Oxfmt, and the git hooks come from Lefthook.
The practices are four. Use project aliases to run commands in different packages more easily, with the example being bun run --filter @ouorz/main upgrade. Use pre-defined Turborepo scripts whenever content awareness, which is to say caching, is needed, with the example being bun run build:main. The root package.json should only contain development dependencies. And Oxlint and Oxfmt run once for the whole repository, so there is no per-package lint script to keep in sync, which is the rule that saves the most time in a monorepo of this size.
The root manifest confirms the last point. The scripts are all whole-repository commands for lint and format, plus a set of per-package ones for the older tool, and the lint script is plain oxlint with no per-package variants except for lint:main, lint:preview and lint:twilight.
The version in the root manifest is 0.0.2, and the package name is ouorz-mono, marked private with a GPL-3.0-or-later licence.
Editorial conclusion
ouorz-mono fits a developer who wants one repository to hold a personal site, the CMS behind it, the analytics that measure it and a shared component library, and who is prepared to live with a large amount of infrastructure for a small site. It does not fit a team that wants a small deployment, because a personal site here runs three services plus a database, and it does not fit a project that needs a supported CMS, since the WordPress app is a container the author rebuilds whenever the CMS needs updating. Verify three things before you copy it: how much memory the WordPress container needs, since the README warns it is extremely slow on lower-spec machines and asks for at least a gigabyte without MySQL 8, that your object storage is reachable from the container, since uploads live outside it, and that the remote caching in the Turborepo setup is something you want, because it changes what a build means across machines.
Frequently asked questions
What is in the ouorz-mono repository?
A monorepo holding four applications and a toolkit: a main app that is a personal website and academic profile on Next.js, a WordPress app used as a headless CMS, an analytics app based on Umami, and the Twilight Toolkit UI library, plus a twilight-protocol package of Solidity contracts. The build is Turborepo with remote caching over Bun workspaces.
How do I run the main app locally?
Clone the repository, run bun install, and move into apps/main. Then create a .env file with the LeanCloud keys NEXT_PUBLIC_LC_KEY and NEXT_PUBLIC_LC_ID, the Sentry variables NEXT_PUBLIC_SENTRY_DSN, SENTRY_AUTH_TOKEN, SENTRY_PROJECT and SENTRY_ORG, and REVALIDATION_REQUEST_TOKEN for on-demand ISR, and start it with bun run dev:main.
How is WordPress used in ouorz-mono?
As a headless CMS. The main app fetches data through the WordPress REST API, and a custom theme named peg customises the behaviour of those endpoints, so peg/functions.php is the main focus when working on the WordPress app. The container is built on the official WordPress image, and uploads live in external object storage so the container can be rebuilt at any time.
What does the WordPress container need in terms of resources?
The README warns that running WordPress in a Docker container is extremely slow on lower-spec machines, and recommends at least 1 GB of RAM without MySQL 8, or 2 GB with MySQL 8. Each build produces a static image, so updating WordPress or adding themes and plugins means redeploying.
What are the monorepo rules in ouorz-mono?
Use project aliases such as bun run --filter @ouorz/main upgrade for commands in a specific package, and pre-defined Turborepo scripts such as bun run build:main when caching and content awareness matter. The root package.json should hold only development dependencies, and Oxlint and Oxfmt run once for the whole repository, so there is no per-package lint script to keep in sync.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ttttonyhe-ouorz-mono)Was this useful?