-
-
- 联系我们以获得商业支持
+ {t.contactCommercial}
- 反作弊
- 防切屏
- 实时音视频
- 双机位录制
+ {t.antiCheat}
+ {t.screenLock}
+ {t.realtimeAV}
+ {t.dualCamera}
@@ -235,8 +340,8 @@ export default function HomePage() {
transition={{ duration: 0.6 }}
className="text-center mb-16"
>
-
优势特性
-
为什么选择 Hydro
+
{t.keyFeatures}
+
{t.whyHydro}
}
- title="强大"
+ title={t.powerful}
subtitle="Battery included"
- description="比赛、训练、讨论、题解、作业等功能"
+ description={t.powerfulDesc}
iconBgGradient="bg-gradient-to-br from-red-500 to-orange-500"
variants={itemVariants}
transition={{ duration: 0.6 }}
/>
}
- title="性能"
+ title={t.performance}
subtitle="Blazingly fast"
- description="沙箱复用,延迟计算,提高运行效率"
+ description={t.performanceDesc}
iconBgGradient="bg-gradient-to-br from-yellow-500 to-orange-500"
variants={itemVariants}
transition={{ duration: 0.6 }}
/>
}
- title="安全"
+ title={t.security}
subtitle="(Not only) memory safe"
- description="使用 Linux 容器技术隔离用户程序"
+ description={t.securityDesc}
iconBgGradient="bg-gradient-to-br from-blue-200 to-pink-200"
variants={itemVariants}
transition={{ duration: 0.6 }}
/>
}
- title="便捷"
+ title={t.convenient}
subtitle="Easy setup"
- description="支持使用脚本一键搭建"
+ description={t.convenientDesc}
iconBgGradient="bg-gradient-to-br from-green-500 to-teal-500"
variants={itemVariants}
transition={{ duration: 0.6 }}
/>
}
- title="扩展"
+ title={t.extensibleTitle}
subtitle="Plugin integration"
- description="可通过安装附加组件进行扩展"
+ description={t.extensibleDesc}
iconBgGradient="bg-gradient-to-br from-purple-300 to-pink-300"
variants={itemVariants}
transition={{ duration: 0.6 }}
/>
}
- title="开源"
+ title={t.openSource}
subtitle="Open source"
- description="代码基于 AGPL 开源"
+ description={t.openSourceDesc}
iconBgGradient="bg-gradient-to-br from-gray-700 to-gray-900"
variants={itemVariants}
transition={{ duration: 0.6 }}
@@ -314,8 +419,8 @@ export default function HomePage() {
transition={{ duration: 0.6 }}
className="text-center mb-16"
>
- 系统预览
- 简洁、现代、强大的界面设计
+ {t.systemPreview}
+ {t.systemPreviewDesc}
@@ -363,7 +468,7 @@ export default function HomePage() {
- Hydro 由开源社区驱动
+ {t.communityDriven}
- 我们的一些活跃贡献者
+ {t.activeContributors}
@@ -430,7 +535,7 @@ export default function HomePage() {
transition={{ duration: 0.6, delay: 0.2 }}
className="text-4xl md:text-5xl font-bold mb-6"
>
- 准备好开始了吗?
+ {t.readyToStart}
- 加入我们,一起打造更好的在线评测系统
+ {t.joinUs}
-
- 查看文档
+ {t.viewDocs}
,
};
-export default async function Layout({ children, params }: { children: ReactNode, params: Promise<{ slug?: string[] }> }) {
- const { slug } = await params;
+export default async function Layout({
+ children,
+ params,
+}: {
+ children: ReactNode;
+ params: Promise<{ lang: string; slug?: string[] }>;
+}) {
+ const { lang, slug } = await params;
return (
slug?.[0] === key) ? [
{
type: 'custom',
@@ -30,12 +36,12 @@ export default async function Layout({ children, params }: { children: ReactNode
{
title: 'Hydro',
description: 'The Online Judge System',
- url: '/docs/Hydro',
+ url: `/${lang}/docs/Hydro`,
},
{
title: 'XCPC-Tools',
description: 'Tools for on-site contests',
- url: '/docs/Tools',
+ url: `/${lang}/docs/Tools`,
},
]}
/>
diff --git a/app/[lang]/docs/[[...slug]]/page.tsx b/app/[lang]/docs/[[...slug]]/page.tsx
new file mode 100644
index 000000000..b60afb163
--- /dev/null
+++ b/app/[lang]/docs/[[...slug]]/page.tsx
@@ -0,0 +1,54 @@
+import { source } from '@/lib/source';
+import { Popup, PopupContent, PopupTrigger } from 'fumadocs-twoslash/ui';
+import { Callout } from 'fumadocs-ui/components/callout';
+import {
+ DocsPage,
+ DocsBody,
+ DocsDescription,
+ DocsTitle,
+} from 'fumadocs-ui/page';
+import { notFound } from 'next/navigation';
+import defaultMdxComponents from 'fumadocs-ui/mdx';
+
+export default async function Page(props: {
+ params: Promise<{ lang: string; slug?: string[] }>;
+}) {
+ const params = await props.params;
+ const page = source.getPage(params.slug, params.lang);
+ if (!page) notFound();
+
+ const MDX = page.data.body;
+
+ return (
+
+ {page.data.title}
+ {page.data.description}
+
+
+
+
+ );
+}
+
+export async function generateStaticParams() {
+ return source.generateParams();
+}
+
+export async function generateMetadata(props: {
+ params: Promise<{ lang: string; slug?: string[] }>;
+}) {
+ const params = await props.params;
+ const page = source.getPage(params.slug, params.lang);
+ if (!page) notFound();
+
+ return {
+ title: page.data.title,
+ description: page.data.description,
+ };
+}
diff --git a/app/[lang]/layout.tsx b/app/[lang]/layout.tsx
new file mode 100644
index 000000000..b1f2344c0
--- /dev/null
+++ b/app/[lang]/layout.tsx
@@ -0,0 +1,31 @@
+import { RootProvider } from 'fumadocs-ui/provider/next';
+import type { ReactNode } from 'react';
+import { i18nUI } from '@/lib/layout.shared';
+import { i18n } from '@/lib/i18n';
+
+export default async function LangLayout({
+ params,
+ children,
+}: {
+ params: Promise<{ lang: string }>;
+ children: ReactNode;
+}) {
+ const { lang } = await params;
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function generateStaticParams() {
+ return i18n.languages.map((lang) => ({ lang }));
+}
diff --git a/app/api/search/route.ts b/app/api/search/route.ts
index 17fda366a..0a1e6176d 100644
--- a/app/api/search/route.ts
+++ b/app/api/search/route.ts
@@ -5,28 +5,25 @@ import { stopwords as mandarinStopwords } from "@orama/stopwords/mandarin";
export const revalidate = false;
-const tokenizer = createTokenizer({
+const mandarinTokenizer = createTokenizer({
language: 'mandarin',
stopWords: mandarinStopwords,
});
-const search = {
- tokenizer,
- components: {
- tokenizer,
- },
- search: {
- threshold: 1.5,
- tolerance: 2,
- boost: {
- title: 2,
- content: 1,
+export const { staticGET: GET } = createFromSource(source, {
+ localeMap: {
+ zh: {
+ tokenizer: mandarinTokenizer,
+ components: {
+ tokenizer: mandarinTokenizer,
+ },
+ search: {
+ threshold: 1.5,
+ tolerance: 2,
+ },
+ },
+ en: {
+ language: 'english',
},
},
- insertOptions: {
- batchSize: 100,
- async: true,
- },
-};
-
-export const { staticGET: GET } = createFromSource(source, search);
+});
diff --git a/app/docs/[[...slug]]/page.tsx b/app/docs/[[...slug]]/page.tsx
index 795e1ea6b..f178bfd9f 100644
--- a/app/docs/[[...slug]]/page.tsx
+++ b/app/docs/[[...slug]]/page.tsx
@@ -1,54 +1,16 @@
+import { redirect } from 'next/navigation';
import { source } from '@/lib/source';
-import { Popup, PopupContent, PopupTrigger } from 'fumadocs-twoslash/ui';
-import { Callout } from 'fumadocs-ui/components/callout';
-import {
- DocsPage,
- DocsBody,
- DocsDescription,
- DocsTitle,
-} from 'fumadocs-ui/page';
-import { notFound } from 'next/navigation';
-import defaultMdxComponents from 'fumadocs-ui/mdx';
-export default async function Page(props: {
+export default async function DocsRedirectPage(props: {
params: Promise<{ slug?: string[] }>;
}) {
- const params = await props.params;
- const page = source.getPage(params.slug);
- if (!page) notFound();
-
- const MDX = page.data.body;
-
- return (
-
- {page.data.title}
- {page.data.description}
-
-
-
-
- );
+ const { slug } = await props.params;
+ const path = slug?.length ? `/zh/docs/${slug.join('/')}` : '/zh/docs';
+ redirect(path);
}
export async function generateStaticParams() {
- return source.generateParams();
-}
-
-export async function generateMetadata(props: {
- params: Promise<{ slug?: string[] }>;
-}) {
- const params = await props.params;
- const page = source.getPage(params.slug);
- if (!page) notFound();
-
- return {
- title: page.data.title,
- description: page.data.description,
- };
+ return source.generateParams()
+ .filter((p) => p.lang === 'zh')
+ .map(({ slug }) => ({ slug }));
}
diff --git a/app/layout.config.tsx b/app/layout.config.tsx
deleted file mode 100644
index 4ba83064f..000000000
--- a/app/layout.config.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
-import Image from 'next/image';
-
-/**
- * Shared layout configurations
- *
- * you can customise layouts individually from:
- * Home Layout: app/(home)/layout.tsx
- * Docs Layout: app/docs/layout.tsx
- */
-export const baseOptions: BaseLayoutProps = {
- nav: {
- title: (
- <>
-
- Hydro
- >
- ),
- },
-};
diff --git a/app/layout.tsx b/app/layout.tsx
index 6f5ec1d10..eb2f32b59 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,6 +1,5 @@
-import './global.css';
+import '@/app/global.css';
import 'katex/dist/katex.css';
-import { RootProvider } from 'fumadocs-ui/provider/next';
import { Inter } from 'next/font/google';
import type { ReactNode } from 'react';
@@ -8,30 +7,23 @@ const inter = Inter({
subsets: ['latin'],
});
-export default function Layout({ children }: { children: ReactNode }) {
+export default function RootLayout({ children }: { children: ReactNode }) {
return (
-
+
Hydro Docs
-
-
-
-
- {children}
-
-
+ {children}
+
);
diff --git a/app/page.tsx b/app/page.tsx
new file mode 100644
index 000000000..192f92266
--- /dev/null
+++ b/app/page.tsx
@@ -0,0 +1,5 @@
+import { redirect } from 'next/navigation';
+
+export default function RootPage() {
+ redirect('/zh');
+}
diff --git a/content/docs/Hydro/FAQ/debug.en.md b/content/docs/Hydro/FAQ/debug.en.md
new file mode 100644
index 000000000..50d9763de
--- /dev/null
+++ b/content/docs/Hydro/FAQ/debug.en.md
@@ -0,0 +1,44 @@
+---
+title: Debugging Guide
+---
+
+## Process Management
+
+Access your server console and use `pm2 ls` to view the status of running processes.
+A healthy Hydro instance typically has four processes: `hydrooj`, `hydro-sandbox`, `mongodb`, and `caddy`.
+
+If any processes are missing or failing to start:
+1. Run `pm2 stop all` and `pm2 del all`.
+2. Rerun the installation script to restore the default process configuration.
+
+### Troubleshooting Process Failures
+
+- **Caddy**: Usually fails due to port conflicts (port 80/443 already in use) or syntax errors in `~/.hydro/Caddyfile`. Run `cd ~/.hydro && caddy run` in the foreground to see detailed error messages.
+- **Hydro-Sandbox**: Often fails due to insufficient permissions or an outdated kernel. Check logs with `pm2 logs hydro-sandbox --lines 100`.
+- **HydroOJ**: If the main service fails, refer to the section below.
+
+## Debugging HydroOJ
+
+To inspect detailed logs, stop the background process and run Hydro in the foreground:
+1. `pm2 stop hydrooj`
+2. Run the command `hydrooj` directly.
+
+**Suggested Steps:**
+1. **Update**: Ensure you are running the latest version.
+2. **Plugins**: Third-party plugins are a common cause of crashes.
+ - Back up your plugin list: `cp ~/.hydro/addon.json ~/.hydro/addon.json.bak`.
+ - View active plugins: `hydrooj addon list`.
+ - Remove non-official plugins (those without the `@hydrooj/` prefix): `hydrooj addon remove `.
+3. **Restart**: Check if the system runs correctly without third-party plugins. If it does, re-enable them one by one to identify the culprit.
+4. **Support**: If the issue persists, provide the development team with the full console output from startup until the error occurs.
+
+## Frontend Issues
+
+Symptoms include pages failing to load, infinite loading spinners, or error prompts (yellow/red) at the bottom-left of the screen.
+
+1. **Clear Cache**: Press `Ctrl+Shift+Delete` to clear your browser cache and reload.
+2. **Browser Version**: Ensure you are using the latest version of Chrome or a Chromium-based browser.
+3. **Disable Extensions**: Browser extensions can sometimes interfere with page scripts.
+4. **Developer Tools**: Press `F12`, go to the **Console** tab for script errors, and the **Network** tab to identify failed requests.
+5. **Report**: When seeking help in the user group, please include screenshots of both the Console and Network tabs.
+
diff --git a/content/docs/Hydro/FAQ/index.en.mdx b/content/docs/Hydro/FAQ/index.en.mdx
new file mode 100644
index 000000000..2bb3a4fe0
--- /dev/null
+++ b/content/docs/Hydro/FAQ/index.en.mdx
@@ -0,0 +1,224 @@
+---
+title: FAQ Collection
+---
+
+## Good news! This page and major browsers have partnered up—use Ctrl-F to quickly search keywords!
+
+## For more tutorials, see [Common Tutorials](https://hydro.ac/d/faqs/p).
+
+## User QQ Group: 1085853538
+
+## How can I quickly get familiar with system features?
+
+Refer to this post: [https://hydro.ac/discuss/6172ceeed850d38c79ae18f9](https://hydro.ac/discuss/6172ceeed850d38c79ae18f9) for a serverless quick experience of system features.
+If you do not need heavy secondary development, we recommend using the online service directly. Problemsets with over 20,000 problems can be copied directly, with no need to buy cloud servers or maintain them manually.
+If you need customizations such as binding your own domain or changing logos, you can also enable advanced features in the admin panel yourself.
+
+Users in the system only support edit and disable, not delete. This is to fundamentally prevent "teaching accidents." Please do not request user deletion features. If you are certain you will never misoperate, develop that feature yourself.
+
+## What is an OJ?
+
+The judging system you are using now is just a program, not artificial intelligence. So in many places, you need to adapt to it. Otherwise, even if your answer is essentially correct, format errors can make the system unable to understand it and still result in wrong answers.
+The system workflow is as follows:
+
+- Teachers add problems in the system and strictly define input/output formats.
+- Teachers add multiple sets of test data according to the problem format; each set includes input and expected output.
+- Students read the problem and submit programs based on their understanding.
+- The system compiles and runs student programs, then feeds the pre-provided input data to the programs and checks their output.
+- If a student's output is exactly identical to the teacher-provided output, character by character, the program is considered correct; otherwise it is considered wrong.
+- If memory/time limits are exceeded during execution, the program is interrupted and marked incorrect.
+
+After understanding the above, students should realize that if a problem does not require prompts like "Please Input Two Number", printing such text yourself will make your output differ from expected output, causing Wrong Answer.
+If a problem requires a blank line between every two output lines and you omit it, that is a format error, and vice versa.
+You may feel the system is bad for not auto-detecting this; in fact, this is exactly how it effectively trains programming precision and good coding habits. Many strong programmers started by complaining about this system and learned to code carefully and rigorously.
+To run all submissions in a unified way, the system must constrain submission format for everyone.
+For C/C++ learners, every submission must contain exactly one `main` function, it must return `int`, and preferably return 0, because non-zero return values are considered runtime errors by the operating system.
+When a compile error occurs, click the "Compile Error" text link for detailed explanation.
+
+## Error `[ERR_STREAM_PREMATURE_CLOSE]: Premature close` when installing in Arch Linux development mode
+
+Delete `.yarnrc.yml` and `.yarn`, then try again.
+
+## Why can't I access the site after installation?
+
+If you are using providers such as Alibaba Cloud/Tencent Cloud, ensure ports 80 and 443 are allowed in the security group.
+
+## Why can't I log in after configuring reverse proxy (caddy/nginx) (CsrfTokenError)?
+
+When reverse proxying, ensure the Host Header is set correctly. [Details](./install/proxy)
+
+## How to back up / restore backup / migrate data?
+
+`hydrooj backup` `hydrooj restore backup-xxx.zip`
+
+After learning how crontab works, you can use `sudo crontab -e` to create automatic backup schedules.
+
+## Upgrade
+
+See [Upgrade Guide](./FAQ/upgrade)
+
+## How to import/create problems?
+
+There are corresponding entries on the right side of the problem list page.
+
+Remember: do not import too many problems you do not need yet. The correct approach is to import only 5–10 required problems per training assignment. After the assignment/contest ends, let those become part of the training problemset. This keeps lower problem IDs gradually increasing in difficulty and makes self-training easier for later students. Do not chase quantity while ignoring quality. Use fewer problems you do not understand, and use them cautiously.
+
+## How to restrict access for unlogged users?
+
+Manage Domain -> Manage Permissions: disable the "View this domain" permission for Guest group.
+
+## How to add ICP filing number in footer?
+
+Add a line in system setting `footer_extra_html`: `XX ICP XX No. `
+
+## What does time mean in contests/assignments? Difference between OI ranking and normal ranking?
+Time means the time "spent" for participants to solve a problem:
+That is: time solved – contest start time + penalty time
+Penalty time = number of wrong submissions before acceptance * 20 minutes.
+Normal ranking is based on number of solved problems and "spent" time.
+OI ranking is based on score. Problems can be scored proportionally by pass ratio, 100 points each. If you want non-uniform score distribution, use config.
+
+## Where does the script install OJ?
+
+You can get Hydro's default location with `yarn global dir`. (Do not modify code directly; updates will overwrite all changes there. Use the plugin API instead.)
+Default database files are in `/data/db`, but do not copy files directly; `hydrooj backup` is recommended.
+Files such as test data are stored in `/data/file`.
+Config files are in `/root/.config/hydro` and `/root/.hydro`.
+For production servers in operation, always make an offline backup before any operation.
+Always unzip backup files to verify all data is included, and check backup size (large systems should have backups of hundreds of MB). If possible, verify restore success in a VM.
+
+## What is the precision of time limit and memory limit?
+
+The literal time limit precision is 1ms, but due to OS kernel constraints, actual measured precision is usually 4ms.
+Memory limit precision is 1MB. For local native compiled languages like c/c++/pascal/freebasic/clang, it measures the program's own memory allocation; for VM/script languages, it includes memory consumed by the VM/interpreter itself.
+
+## `Outdated lockfile. Please run 'yarn install' and try again.`
+
+```
+cd `yarn global dir` && rm -rf node_modules yarn.lock && yarn install
+```
+
+Then try again.
+
+## I want Python to support numpy and similar libraries. What should I do?
+
+If installed before 2022/8/12, run `pip3 install numpy` then `pm2 restart hydro-sandbox`
+Otherwise refer to the [Compiler](./install/compiler) section.
+
+## I forgot MongoDB account/password after using installation script. What should I do?
+
+Check `/root/.hydro/config.json`.
+
+## How to disable/enable user registration?
+
+Registration is controlled by Guest user (uid = 0) permission PRIV_REGISTER_USER, enabled by default.
+Use `hydrooj cli user setPriv 0 0` to disable registration.
+To re-enable, use `hydrooj cli user setPriv 0 8`.
+
+After changing it, restart hydrooj service: `pm2 restart hydrooj`
+
+## What is user Hydro for? What's the password? Can it log in?
+
+User Hydro (uid = 1) is only for sending system messages (similar to 10000 in QQ) and cannot log in.
+
+## How to modify website icon?
+
+Use `hydrooj addon create` to create a plugin, which will create `/root/addon` automatically.
+Go to `/root/addon/public`, and place your site icons there.
+You need these files in that directory (for different browsers):
+
+- `favicon-16x16.png`
+- `favicon-32x32.png`
+- `favicon-96x96.png`
+- `favicon.ico` (32x32)
+- `android-chrome-192x192.png`
+- `apple-touch-icon-180x180.png`
+
+Matching resolution is recommended but not mandatory. These images are shown on browser tabs.
+You also need this file in that directory:
+
+- `nav_logo_dark.png`
+
+This image is shown as the top-left logo.
+Then go to system settings, find `nav_logo_dark`, change it to `/nav_logo_dark.png`, and restart Hydro to apply changes.
+
+Remember to clear browser cache.
+
+## How to reset data?
+
+
+This operation will delete all users/problems/contests and other data. Proceed with caution!
+
+
+Download [this script](https://github.com/hydro-dev/Hydro/blob/master/install/reset.sh) and run it on the server.
+
+You can adjust as needed; display order matches the order in configuration.
+
+## Judge shows "Total time limit exceeds 60s, judging canceled"
+
+In system settings, modify `total_time_limit` to the allowed maximum judging duration per problem.
+
+## How to add line animation effects in background?
+
+After creating a plugin, put the following content in plugin `frontend/animation.page.ts`:
+
+> Based on https://github.com/hustcc/canvas-nest.js , MIT
+
+```js
+(()=>{function e(e,n,t){return e.getAttribute(n)||t}function n(){l=i.width=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,u=i.height=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}function c(){var t,o,i,a,m;r.clearRect(0,0,l,u),s.forEach(function(e,n){for(e.x+=e.xa,e.y+=e.ya,e.xa*=e.x>l||e.x<0?-1:1,e.ya*=e.y>u||e.y<0?-1:1,r.fillRect(e.x-.5,e.y-.5,1,1),o=n+1;o=t.max/2&&(e.x-=.03*i,e.y-=.03*a),m=(t.max-m)/t.max,r.beginPath(),r.lineWidth=m/2,r.strokeStyle="rgba("+x.c+","+(.2+m)+")",r.moveTo(e.x,e.y),r.lineTo(t.x,t.y),r.stroke()))}),w(c)}var l,u,d,t,o,i=document.createElement("canvas"),x=(t=(o=document.getElementsByTagName("script")).length,o=o[t-1],{l:t,z:e(o,"zIndex",-1),o:e(o,"opacity",.5),c:e(o,"color","0,0,0"),n:e(o,"count",99)}),a="c_n"+x.l,r=i.getContext("2d"),w=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1e3/45)},m=Math.random,y={x:null,y:null,max:2e4};i.id=a,i.style.cssText="position:fixed;top:0;left:0;z-index:"+x.z+";opacity:"+x.o,document.getElementsByClassName("main")[0].appendChild(i),n(),window.onresize=n,window.onmousemove=function(e){e=e||window.event,y.x=e.clientX,y.y=e.clientY},window.onmouseout=function(){y.x=null,y.y=null};for(var s=[],h=0;x.n>h;h++){var f=m()*l,g=m()*u,p=2*m()-1,v=2*m()-1;s.push({x:f,y:g,xa:p,ya:v,max:6e3})}d=s.concat([y]),setTimeout(function(){c()},100)})();
+```
+
+## How much does Hydro cost?
+
+It's free. We are AGPL. If you have extra money, you can [send me a red packet](https://pay.undefined.moe).
+
+## execve: no such file or directory
+
+Script installation installs only a small subset of compilers by default. Please refer to the [Compiler](./install/compiler) section to install/configure other compilers.
+
+## How to customize user badges?
+
+Enter MongoDB and execute the following (replace placeholders in angle brackets accordingly):
+
+```sh
+use hydro
+db.user.update({"_id": }, {$set: {"badge": "##"}})
+```
+
+## Why can't I batch download multiple files?
+
+Please use a modern browser and try enabling HTTPS for your site.
+Otherwise, download files one by one (Ctrl+click filename).
+
+## Why is there no language option on my submission page?
+
+Problem -> Judge Settings -> Allowed languages
+Domain Settings -> Edit Domain Profile -> Allowed languages
+In both places, fill language IDs separated by English commas. If unsure, leave empty.
+
+## The 'yarn global' commands have been remove in 2.x - consider using 'yarn dlx' or a third-party plugin instead
+
+If you cannot understand this issue, just use the installation script and do not mess with development mode.
+
+## I'm in a computer lab environment; many users share one IP and trigger rate limits. How to solve?
+
+Option 1: Set up a proxy server in the intranet and forward intranet IPs to the server. (Recommended)
+Option 2: Use commands like `hydrooj cli system set limit.user_login 999` to set new rate limits (the error page shows which limit was triggered)
+Option 3: Start with `pm2 start hydrooj -- --benchmark` to disable all rate limits (Not recommended)
+
+## Adjust temporary directory size
+
+Judge stores temporary files in /dev/shm, including contestants' output, compiled executables, etc. These files are automatically deleted after judging.
+If you set high parallel judging, pay attention to /dev/shm size limit. We usually recommend reserving at least 512MB.
+
+Check /dev/shm size:
+
+```bash
+df -h /dev/shm
+```
+
+Adjust /dev/shm size:
+
+```bash
+sudo mount -o remount,size=1024M /dev/shm
+```
\ No newline at end of file
diff --git a/content/docs/Hydro/FAQ/meta.en.json b/content/docs/Hydro/FAQ/meta.en.json
new file mode 100644
index 000000000..c338f92e6
--- /dev/null
+++ b/content/docs/Hydro/FAQ/meta.en.json
@@ -0,0 +1,9 @@
+{
+ "title": "FAQ",
+ "description": "Frequently Asked Questions",
+ "pages": [
+ "index",
+ "upgrade",
+ "debug"
+ ]
+}
diff --git a/content/docs/Hydro/FAQ/upgrade.en.md b/content/docs/Hydro/FAQ/upgrade.en.md
new file mode 100644
index 000000000..d2e2409df
--- /dev/null
+++ b/content/docs/Hydro/FAQ/upgrade.en.md
@@ -0,0 +1,45 @@
+---
+title: Upgrade Guide
+---
+
+## Recommended Upgrade Path
+
+To upgrade your Hydro instance to the latest version:
+1. Run: `yarn global upgrade-interactive --latest`
+2. Use the spacebar to select **all** packages except for `pm2`.
+3. Press Enter to confirm.
+4. Restart the service: `pm2 restart hydrooj`
+5. Verify success: Check logs with `pm2 logs hydrooj --lines 100`. Look for the "Server started" message.
+
+**Important Considerations:**
+- Always upgrade the system before adding or updating plugins to avoid compatibility issues.
+- If you have installed plugins from URLs (e.g., `hydrooj install https://...`), re-run those install commands after a system upgrade to ensure the plugins are also updated.
+- All historical versions of Hydro are designed for a seamless upgrade to the latest version. If you have any questions, please contact the official user group.
+
+## Common Upgrade Issues
+
+### 1. Removing nvm
+Early versions of Hydro relied on `nvm` to manage the Node.js environment. This approach is now deprecated in favor of Nix.
+- If `nvm` is present, you can remove it: `rm -rf ~/.nvm`.
+- Ensure Nix is installed: `. <(curl https://hydro.ac/nix.sh)`.
+- Use Nix to reinstall core components: `nix-env -iA nixpkgs.nodejs nixpkgs.yarn nixpkgs.pm2`.
+
+### 2. "NodeJS >= xx required" Errors
+If you see a version error during upgrade:
+1. Check for `nvm` as described above.
+2. Update your Nix channels: `nix-channel --update`.
+3. Reinstall Node.js and Yarn via Nix: `nix-env -iA nixpkgs.nodejs nixpkgs.yarn nixpkgs.pm2`.
+4. Proceed with the upgrade steps.
+5. Use `pm2 restart hydrooj --update-env` to apply the environment changes.
+
+### 3. Upgrading the Sandbox
+If the system displays a warning that your sandbox version is critically low or vulnerable to security issues, follow these steps:
+
+```bash
+nix-channel --update
+nix-env -e hydro.sandbox
+nix-env -iA nixpkgs.go-judge
+ln -sf $(which go-judge) /usr/bin/hydro-sandbox
+pm2 restart hydro-sandbox --update-env
+```
+
diff --git a/content/docs/Hydro/api/judge.en.md b/content/docs/Hydro/api/judge.en.md
new file mode 100644
index 000000000..219f18354
--- /dev/null
+++ b/content/docs/Hydro/api/judge.en.md
@@ -0,0 +1,184 @@
+---
+title: Judge Communication Protocol
+---
+
+Current version: v1.
+
+## Judge-side Interaction Flow
+
+- GET /judge/files (check whether login status is valid; if invalid, enter login flow; usually executed once every six hours)
+- WEBSOCKET /judge/conn (main interaction channel)
+
+If login has expired, perform login.
+
+```http
+POST /login
+
+{"uname":"USERNAME","password":"PASSWORD","rememberme":true}
+```
+
+## WebSocket Connection Establishment Flow
+
+```http
+WEBSOCKET /judge/conn
+Authorization: Bearer COOKIE_SID
+```
+
+After the connection is established, the judge reports current node status to Web (optional)
+Note: the information below is only for data format demonstration and is not guaranteed to be real or valid.
+
+```json
+{
+ "key": "status",
+ "info": {
+ "mid": "MACHINE_ID",
+ "memory": {
+ "total": 25189552128,
+ "free": 660258800,
+ "used": 24529293328,
+ "active": 1558973164,
+ "available": 23636676608,
+ "buffers": 3075653000,
+ "cached": 1000000000,
+ "slab": 1000000000,
+ "buffcache": 1000000000,
+ "swaptotal": 0,
+ "swapused": 0,
+ "swapfree": 0
+ },
+ "cpu": {
+ "manufacturer": "Intel",
+ "brand": "Xeon® Platinum 8269CY",
+ "vendor": "Intel",
+ "family": "6",
+ "model": "85",
+ "stepping": "7",
+ "speed": 2.5,
+ "cores": 32,
+ "physicalCores": 32,
+ "processors": 2,
+ "flags": "fpu vme de pse tsc ...",
+ "cache": {
+ "l1d": 32768,
+ "l1i": 32768,
+ "l2": 262144,
+ "l3": 6291456
+ }
+ },
+ "load": {
+ "avgLoad": 0.01,
+ "currentLoad": 0.01,
+ "currentLoadUser": 0.01,
+ "currentLoadSystem": 0.01,
+ "currentLoadNice": 0.01,
+ "currentLoadIdle": 0.01,
+ "currentLoadIrq": 0.01
+ },
+ "osinfo": {
+ "platform": "linux",
+ "distro": "Ubuntu",
+ "release": "22.04.2 LTS",
+ "codename": "Jammy Jellyfish",
+ "kernel": "5.15.0-84-generic",
+ "arch": "x64",
+ "hostname": "judge",
+ "codepage": "UTF-8",
+ }
+ }
+}
+```
+
+After connection establishment, the judge sends `{"key":"ping"}` every 30s.
+
+## Language Configuration Distribution
+
+After the connection is established, the Web side distributes server-side language settings to the Judge. If the client needs special settings, this message can be ignored.
+
+## Judge Task Push
+
+The Web side pushes judge tasks to the judge side via WebSocket.
+
+```json
+{
+ "task": {
+ "type": "judge",
+ "_id": "RECORD_ID",
+ "lang": "cc.cc11",
+ "uid": SUBMITTER_UID,
+ "code": "USER_SUBMITTED_CODE",
+ "domainId": "SUBMISSION_DOMAIN_ID",
+ "pid": PROBLEM_ID,
+ "contest": "CONTEST_ID (optional)",
+ "input": "INPUT",
+ "source": "SOURCE_ID",
+ "meta": {
+ "rejudge": false,
+ "problemOwner": OWNER_UID
+ },
+ "data": [
+ {
+ "name": "FILE_NAME",
+ "size": SIZE_IN_BYTES,
+ "lastModified": "2023-11-15T08:14:57.535Z",
+ "etag": "ETAG"
+ }
+ ]
+ }
+}
+```
+
+Note 1: if contest ID is `000000000000000000000000`, this submission is a custom test submission, and the custom test uses the `input` field as program input.
+Note 2: the `source` field is a cache ID; submissions with the same `source` field use the same cache directory.
+Note 3: the `source` field contains exactly one character `/`; `domainId/pid` is recommended.
+Note 4: the etag of test data is used to identify whether local cached files are consistent with the cloud; you can use a hash or a modified-time timestamp.
+
+## Test Data Download
+
+If test data used in the pushed judge task is missing, the Judge side requests missing or modified files from Web.
+
+```http
+POST /d/:domainId/judge/files
+Cookie: sid=COOKIE_SID
+
+{"pid":PROBLEM_ID,"files":["a.in","a.out"]}
+```
+
+The server returns:
+
+```json
+{
+ "links": {
+ "a.in": "https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.in",
+ "a.out": "https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.out"
+ }
+}
+```
+
+## Judge Result Reporting
+
+```json
+{
+ "key": "next/end",
+ "domainId": "DOMAIN_ID",
+ "rid": "RECORD_ID",
+
+ "message": "JUDGE_MESSAGE",
+ "compilerText": "COMPILER_OUTPUT",
+ "status": STATUS_CODE,
+ "score": SCORE,
+ "time": TIME_IN_MS,
+ "memory": MEMORY_IN_KB,
+ "progress": PROGRESS_PERCENTAGE,
+ "addProgress": PROGRESS_PERCENTAGE,
+ "case": {
+ "id": ID,
+ "subtaskId": SUBTASK_ID,
+ "score": SCORE,
+ "status": STATUS_CODE,
+ "message": "CHECKER_MESSAGE"
+ }
+}
+```
+
+Except for the three fields `key`, `domainId`, and `rid`, all other fields are optional. For `STATUS_CODE` meanings, see [hydro-dev/Hydro/packages/utils/lib/status](https://github.com/hydro-dev/Hydro/blob/master/packages/utils/lib/status.ts).
+When `key` is `end`, it means the judge task is completed and the result is finalized. The Web side can then count ACs, register scoreboards, and perform related operations.
diff --git a/content/docs/Hydro/dev/PERM_PRIV.en.md b/content/docs/Hydro/dev/PERM_PRIV.en.md
new file mode 100644
index 000000000..c519093f0
--- /dev/null
+++ b/content/docs/Hydro/dev/PERM_PRIV.en.md
@@ -0,0 +1,10 @@
+---
+title: Permissions and Privileges
+---
+
+Hydro permissions are handled using bitwise operations.
+Example: if a user has both `PRIV_EDIT_SYSTEM` and `PRIV_SET_PERM` permissions, it should be set to `(1<<0)|(1<<1)` (that is, 3)
+
+You can check the relevant section in the [source code](https://github.com/hydro-dev/Hydro/blob/master/packages/common/permission.ts).
+
+Further reading: [Permission Structure](../user/permission)
diff --git a/content/docs/Hydro/dev/db-layout.en.md b/content/docs/Hydro/dev/db-layout.en.md
new file mode 100644
index 000000000..1d524c968
--- /dev/null
+++ b/content/docs/Hydro/dev/db-layout.en.md
@@ -0,0 +1,36 @@
+---
+title: Database Layout
+---
+
+## Core Collections
+
+Hydro uses MongoDB for data storage. The following are the most critical collections:
+
+### `document`
+- **Fields**: `domainId`, `docId`, `docType`, `owner`, `title`, `content`.
+- **Description**: Stores all main entities, including problems, contests, and training plans.
+- **Types**: Differentiated by the `docType` field. See `packages/hydrooj/src/model/document.ts` for type definitions.
+
+### `document.status`
+- **Fields**: `domainId`, `docId`, `docType`, `uid`, `status`.
+- **Description**: Stores user-specific states related to a document, such as problem submission history or contest participation scores.
+
+### `record`
+- **Fields**: `_id`, `domainId`, `uid`, `code`, `lang`, `score`, `status`.
+- **Description**: Stores submission records.
+
+### `user`
+- **Fields**: `_id`, `uname`, `unameLower`, `mail`, `mailLower`, `priv`.
+- **Description**: All user account information.
+
+## System Collections
+
+- **`oplog`**: System logs.
+- **`blacklist`**: Banned IPs and email domains.
+- **`system`**: Global system configuration.
+- **`task`**: Submission and background task queues.
+- **`event`**: Internal event messaging (Used by the core, do not modify manually).
+- **`schedule`**: Scheduled task definitions.
+- **`opcount`**: Access statistics for rate-limiting.
+- **`token`**: Temporary data, including session states and verification codes.
+
diff --git a/content/docs/Hydro/dev/frontend-modify.en.md b/content/docs/Hydro/dev/frontend-modify.en.md
new file mode 100644
index 000000000..cce7e57aa
--- /dev/null
+++ b/content/docs/Hydro/dev/frontend-modify.en.md
@@ -0,0 +1,5 @@
+---
+title: Frontend Modification
+---
+
+Refer to [Frontend Modification](../system/frontend-modify/).
diff --git a/content/docs/Hydro/dev/hook.en.md b/content/docs/Hydro/dev/hook.en.md
new file mode 100644
index 000000000..5ea614046
--- /dev/null
+++ b/content/docs/Hydro/dev/hook.en.md
@@ -0,0 +1,54 @@
+---
+title: Write Plugins with TypeScript - Hooks
+---
+
+## Using Hooks in Plugins
+
+Hooks allow you to intercept and modify system behavior at specific points in the execution flow.
+
+### Handler Hooks
+You can listen for events on specific routes using the following syntax:
+`handler//#`
+
+- **Timing**: `before`, `before-operation`, `after`.
+- **RouteName**: The internal name of the route (e.g., `RecordDetail`).
+- **Method**: (Optional) `get` or `post`. If omitted, all methods are captured.
+
+**Example: Restricting Code Visibility**
+This hook prevents users from viewing submission code if the record is more than 24 hours old.
+
+```ts
+import { Context, Time } from 'hydrooj';
+
+export async function apply(ctx: Context) {
+ // Intercept the RecordDetail route after the main logic completes
+ ctx.on('handler/after/RecordDetail#get', (h) => {
+ // 'h' is the Handler instance. We can access the record data via h.rdoc.
+ const oneDayAgo = new Date(Date.now() - Time.day);
+ if (h.rdoc._id.getTimestamp() < oneDayAgo) {
+ h.rdoc.code = 'Access Expired';
+ }
+ });
+}
+```
+
+### Injecting Methods into Handlers
+If you need to replace or extend a method in an existing Handler class, use `withHandlerClass`.
+
+**Example: Overriding Homepage Announcements**
+```ts
+import { Context } from 'hydrooj';
+
+async function customGetAnnounce(domainId: string, limit = 5) {
+ // Custom logic to fetch announcements...
+ return [];
+}
+
+export async function apply(ctx: Context) {
+ // Wait for HomeHandler to be registered, then modify its prototype
+ ctx.withHandlerClass('HomeHandler', (HomeHandler) => {
+ HomeHandler.prototype.getAnnounce = customGetAnnounce;
+ });
+}
+```
+
diff --git a/content/docs/Hydro/dev/index.en.mdx b/content/docs/Hydro/dev/index.en.mdx
new file mode 100644
index 000000000..44adf8482
--- /dev/null
+++ b/content/docs/Hydro/dev/index.en.mdx
@@ -0,0 +1,81 @@
+---
+title: Development Environment Setup
+---
+
+## Overview
+
+The Hydro development environment is intended **only** for developers who plan to contribute to the core codebase or perform extensive low-level modifications.
+
+If you are not experienced with TypeScript or Node.js development, we strongly recommend using the **Plugin System** instead. The automated installation script supports most customization needs via plugins without the complexity of a manual build environment.
+
+### Comparison: Production vs. Development
+
+| Feature | Production Mode | Development Mode |
+| :--- | :---: | :---: |
+| **Ease of Setup** | ✅ Simple | ❌ Complex |
+| **Plugin API Support** | ✅ Full | ✅ Full |
+| **Direct Core Edits** | ❌ Not Recommended | ✅ Supported |
+| **Hot Reloading** | ❌ No | ✅ Yes (Experimental) |
+| **Performance/Stability** | ✅ Optimized | ❌ Unoptimized |
+| **Technical Support** | ✅ Available | ❌ Not Provided |
+| **Memory Required** | 2 GB | 8 GB+ (for UI builds) |
+| **Migration Path** | Can switch to Dev | Requires full reinstall |
+
+
+**Network Requirements**: Building Hydro from source requires a stable international internet connection. Failures like `Connection Reset` or `Timeout` are almost always due to local network restrictions. Consider using a proxy or mirror if you encounter these.
+
+
+## Prerequisites
+
+- **OS**: Linux is required. Windows users should use **WSL2**.
+- **Database**: [MongoDB](https://www.mongodb.com/try/download/community) 4.4+ is required.
+- **Node.js**: Version 18 or later. We recommend using **Nix** for environment management: `. <(curl https://hydro.ac/nix.sh)`.
+- **Yarn**: Version 1.x. Install via `npm install -g yarn` or `nix-env -iA nixpkgs.yarn`.
+- **IDE**: A modern editor with robust TypeScript support (e.g., VS Code) is highly recommended.
+
+## Installation Steps
+
+```bash
+# Clone the repository and its submodules
+git clone https://github.com/hydro-dev/Hydro.git --recursive
+cd Hydro
+
+# Install dependencies
+yarn
+
+# Build the frontend (Requires ~8GB RAM)
+yarn build:ui:production
+```
+
+## Managing Plugins
+
+In development mode, no plugins are enabled by default.
+
+**Official Plugins**: These are located in the `packages/` directory. To enable one (e.g., the default UI):
+```bash
+yarn hydrooj addon add @hydrooj/ui-default
+```
+
+**Custom/Third-party Plugins**: Specify the absolute path to the plugin directory:
+```bash
+yarn hydrooj addon add /path/to/your/addon
+```
+
+## Running the Development Server
+
+The following flags are supported:
+- `--port=XXXX`: Specify the listening port.
+- `--debug`: Enable verbose debug logging.
+- `--watch`: Enable backend hot-reloading.
+
+**Recommended Dev Workflow**:
+1. Run the backend: `yarn debug --port=8888 --watch`
+2. In a separate terminal, run the frontend watcher: `yarn build:ui:dev`
+
+The frontend watcher transpiles changes in real-time. Note that while the backend supports hot-reloading, some module changes may still require a manual restart. This workflow requires the `@hydrooj/ui-default` plugin to be enabled.
+
+## Updates
+To update your development environment:
+1. `git pull` in the root directory.
+2. `yarn && yarn build:ui:production`.
+
diff --git a/content/docs/Hydro/dev/meta.en.json b/content/docs/Hydro/dev/meta.en.json
new file mode 100644
index 000000000..4be847d09
--- /dev/null
+++ b/content/docs/Hydro/dev/meta.en.json
@@ -0,0 +1,14 @@
+{
+ "title": "Development",
+ "description": "Development",
+ "pages": [
+ "index",
+ "naming",
+ "db-layout",
+ "PERM_PRIV",
+ "typescript",
+ "hook",
+ "frontend-modify",
+ "third-party-auth"
+ ]
+}
diff --git a/content/docs/Hydro/dev/naming.en.md b/content/docs/Hydro/dev/naming.en.md
new file mode 100644
index 000000000..c257c30de
--- /dev/null
+++ b/content/docs/Hydro/dev/naming.en.md
@@ -0,0 +1,33 @@
+---
+title: Naming Conventions
+---
+
+## Variable Naming Conventions
+
+To maintain consistency across the codebase, Hydro uses the following standard abbreviations for document types:
+
+| Prefix | Document Type |
+| :--- | :--- |
+| **pdoc** | Problem |
+| **tdoc** | Training / Contest / Homework |
+| **rdoc** | Submission Record |
+| **ddoc** | Discussion |
+| **drdoc** | Discussion Reply |
+| **drrdoc**| Second-level Discussion Reply |
+| **mdoc** | Internal Message |
+| **psdoc** | Problem Submission Status |
+| **tsdoc** | Training/Contest Submission Status |
+
+### Plurals and Collections
+- **`*docs`**: An array of documents (e.g., `pdocs` for an array of problems).
+- **`*dict`**: An object/dictionary where keys are IDs and values are document objects (e.g., `pdict`).
+
+For the full list of interfaces and types, refer to `packages/hydrooj/src/interface.ts`.
+
+## Function Naming Conventions
+
+- **`get(...)`**: Retrieves a single entity. Returns the object or `null` if not found.
+- **`getList(...)`**: Retrieves multiple entities as a dictionary-like object.
+- **`getMulti(...)`**: Returns a database cursor for iterating over multiple records.
+- **`edit(...)`**: Performs an update on existing content.
+
diff --git a/content/docs/Hydro/dev/third-party-auth.en.md b/content/docs/Hydro/dev/third-party-auth.en.md
new file mode 100644
index 000000000..9edc6c7ff
--- /dev/null
+++ b/content/docs/Hydro/dev/third-party-auth.en.md
@@ -0,0 +1,100 @@
+---
+title: Integrate Third-party Account Systems
+---
+
+Hydro supports integrating third-party account systems, and the following built-in modules are available:
+
+- @hydrooj/login-with-github
+- @hydrooj/login-with-google
+
+## Integrating Other Platforms
+
+Before reading this section, make sure you have read the "Plugin Development" chapter.
+
+Using GitHub login as an example:
+
+```ts
+import {
+ Context, ForbiddenError, Handler, superagent, SystemModel,
+ TokenModel, UserFacingError, ValidationError,
+} from 'hydrooj';
+
+declare module 'hydrooj' {
+ interface SystemKeys {
+ 'login-with-github.id': string;
+ 'login-with-github.secret': string;
+ 'login-with-github.endpoint': string;
+ }
+}
+
+// 当用户点击 【使用 XX 登录】 按钮时,此函数会被执行
+async function get(this: Handler) {
+ // 从系统设置中获取基础设置,并储存状态信息(完成登录逻辑后应该跳转到哪一页)
+ const [appid, [state]] = await Promise.all([
+ SystemModel.get('login-with-github.id'),
+ TokenModel.add(TokenModel.TYPE_OAUTH, 600, { redirect: this.request.referer }),
+ ]);
+ // 将用户重定向至第三方平台请求授权。
+ this.response.redirect = `https://github.com/login/oauth/authorize?client_id=${appid}&state=${state}&scope=read:user,user:email`;
+}
+
+// 当用户在三方系统中完成授权,需要重定向到 /oauth/xxx/callback,这时所有返回的参数作为 callback 的一参数传入。
+async function callback({ state, code }) {
+ // 获取系统设置和之前的状态。
+ const [[appid, secret, endpoint, url], s] = await Promise.all([
+ SystemModel.getMany([
+ 'login-with-github.id',
+ 'login-with-github.secret',
+ 'login-with-github.endpoint',
+ 'server.url',
+ ]),
+ TokenModel.get(state, TokenModel.TYPE_OAUTH),
+ ]);
+ if (!s) throw new ValidationError('token');
+ // 使用从 url 中返回的 token 请求第三方的 API,获取用户信息,作为函数返回。
+ // 在 OAuth 协议中,需要使用 state 和 code 换取 access_token 再调用 API,这在不同系统中可能设计不同。
+ // 系统会根据返回的用户信息自动查找已有用户或是创建新用户。
+ const res = await superagent.post(`${endpoint || 'https://github.com'}/login/oauth/access_token`)
+ .send({
+ client_id: appid,
+ client_secret: secret,
+ code,
+ redirect_uri: `${url}oauth/github/callback`,
+ state,
+ })
+ .set('accept', 'application/json');
+ if (res.body.error) {
+ throw new UserFacingError(
+ res.body.error, res.body.error_description, res.body.error_uri,
+ );
+ }
+ const t = res.body.access_token;
+ const userInfo = await superagent.get(`${endpoint ? `${endpoint}/api` : 'https://api.github.com'}/user`)
+ .set('User-Agent', 'Hydro-OAuth')
+ .set('Accept', 'application/vnd.github.v3+json')
+ .set('Authorization', `token ${t}`);
+ const ret = {
+ _id: `${userInfo.body.id}@github.local`,
+ email: userInfo.body.email,
+ bio: userInfo.body.bio,
+ // 提供多个用户名,若需创建用户则从前往后尝试,直到用户名可用
+ uname: [userInfo.body.name, userInfo.body.login].filter((i) => i),
+ avatar: `github:${userInfo.body.login}`,
+ };
+ await TokenModel.del(s._id, TokenModel.TYPE_OAUTH);
+ if (!ret.email) throw new ForbiddenError("You don't have a verified email.");
+ return ret;
+}
+
+// 注册此模块。
+export function apply(ctx: Context) {
+ ctx.provideModule('oauth', 'github', {
+ text: 'Login with Github',
+ callback,
+ get,
+ });
+ ctx.i18n.load('zh', {
+ 'Login With Github': '使用 Github 登录',
+ });
+}
+```
diff --git a/content/docs/Hydro/dev/typescript.en.md b/content/docs/Hydro/dev/typescript.en.md
new file mode 100644
index 000000000..2d845923b
--- /dev/null
+++ b/content/docs/Hydro/dev/typescript.en.md
@@ -0,0 +1,325 @@
+---
+title: Write Plugins with TypeScript
+---
+
+## Why Use Plugins?
+
+If you've worked on other large engineering projects, you likely face these common issues:
+
+1. **Recompilation Delay**: Modifying frontend core code requires full recompilation and service restarts, invalidating user caches and wasting time.
+2. **Maintenance Overhead**: Updating a modified core results in merge conflicts or overwritten changes.
+3. **Fragmented Ecosystem**: Diverse community branches are often incompatible or difficult to combine.
+
+Hydro's **Plugin System** addresses these by providing a stable, high-level API. Developers can build features as isolated, reusable units that remain consistent across updates and support hot-reloading for rapid development.
+
+---
+
+## Getting Started: A Pastebin Plugin
+
+In this guide, we'll implement a simple pastebin service.
+
+### 1. Initialize Your Project
+Prerequisite: **Node.js >= 22**
+
+Use the following command to bootstrap a plugin directory (e.g., in `/root/addon`):
+```bash
+# Using 'yarn init' as an example
+mkdir hydro-pastebin && cd hydro-pastebin
+yarn init
+# Follow the prompts (e.g., @hydrooj/pastebin)
+```
+
+**Recommended Dev Workflow**: Use a local IDE (like VS Code) with code completion. Run `yarn add hydrooj -D` locally to enable TypeScript types for the Hydro API.
+
+### 2. Component Design
+Our pastebin requires the following:
+- **Database Access**: To store and retrieve documents.
+- **Routes**:
+ - `GET /paste/create`: Show the creation form.
+ - `POST /paste/create`: Submit a new paste.
+ - `GET /paste/show/:id`: View a specific paste.
+- **Access Control**: Users can set pastes to private.
+
+### 3. Handler Lifecycle
+Handlers process incoming requests. They support the following lifecycle methods (all must be `async`):
+- `prepare(args)`: Runs first. Used for common parameter validation or pre-fetching data.
+- `get(args)`: Handles GET requests.
+- `post(args)`: Handles POST requests.
+- `post[Operation](args)`: Triggered if a `POST` request includes an `operation` field in the body.
+ - *Example*: ` ` maps to `postDeleteItem`.
+- `cleanup()`: Runs after the response is sent.
+
+**Rendering Logic**: If `this.response.template` is set, the template will be rendered. Otherwise, `this.response.body` is returned directly (typically as JSON).
+
+### 4. Implementation (`index.ts`)
+
+```ts twoslash
+// @noErrors
+// @module: esnext
+import {
+ db, definePlugin, Handler, NotFoundError, randomstring, param, PermissionError, PRIV, Types,
+} from 'hydrooj';
+
+const coll = db.collection('paste');
+
+interface Paste {
+ _id: string;
+ owner: number;
+ content: string;
+ isPrivate: boolean;
+}
+
+declare module 'hydrooj' {
+ interface Model {
+ pastebin: typeof pastebinModel;
+ }
+ interface Collections {
+ paste: Paste; // Define the database collection type
+ }
+}
+
+// Model Logic
+async function add(userId: number, content: string, isPrivate: boolean): Promise {
+ const pasteId = randomstring(16);
+ const result = await coll.insertOne({
+ _id: pasteId,
+ owner: userId,
+ content,
+ isPrivate,
+ });
+ return result.insertedId;
+}
+
+async function get(pasteId: string): Promise {
+ return await coll.findOne({ _id: pasteId });
+}
+
+const pastebinModel = { add, get };
+global.Hydro.model.pastebin = pastebinModel;
+
+// Route Handlers
+class PasteCreateHandler extends Handler {
+ async get() {
+ this.response.template = 'paste_create.html';
+ }
+
+ @param('content', Types.Content)
+ @param('private', Types.Boolean)
+ async post(domainId: string, content: string, isPrivate = false) {
+ const id = await pastebinModel.add(this.user._id, content, !!isPrivate);
+ this.response.redirect = this.url('paste_show', { id });
+ }
+}
+
+class PasteShowHandler extends Handler {
+ @param('id', Types.String)
+ async get(domainId: string, id: string) {
+ const doc = await pastebinModel.get(id);
+ if (!doc) throw new NotFoundError(id);
+ if (doc.isPrivate && this.user._id !== doc.owner) {
+ throw new PermissionError();
+ }
+ this.response.body = { doc };
+ this.response.template = 'paste_show.html';
+ }
+}
+
+// Plugin Registration
+export async function apply(ctx) {
+ // Registers named routes for URL generation
+ ctx.Route('paste_create', '/paste/create', PasteCreateHandler, PRIV.PRIV_USER_PROFILE);
+ ctx.Route('paste_show', '/paste/show/:id', PasteShowHandler);
+}
+```
+
+### 5. Frontend & UI
+- **Templates**: Place `.html` files in the `templates/` directory. Use **Nunjucks** syntax.
+- **Frontend Logic**: Place `.tsx` or `.page.ts` files in the `frontend/` folder. They are automatically bundled as entry points.
+
+```tsx
+// Example frontend/main.page.tsx
+import { addPage, NamedPage } from '@hydrooj/ui-default';
+
+addPage(new NamedPage(['problem_detail'], () => {
+ console.log("This script only runs on problem detail pages.");
+}));
+```
+
+
+## Optional: Write plugins on local machine
+
+Sometimes we want to use a local IDE to develop plugins and upload them to the server (we also recommend this, because editor code completion can greatly simplify the development process). You can do the following:
+
+1. Install NodeJS and yarn on your local machine.
+2. Follow Step 1 and use `yarn init` to create a project.
+3. Open the plugin folder with VSCode.
+4. Run `yarn add hydrooj -D` to install related development components.
+5. Develop the plugin by following the instructions below.
+6. Upload the local folder to the server and enable the uploaded plugin with `hydrooj addon add `.
+
+## Step2 Prepare to write components
+
+Analysis: the pastebin component needs the following features:
+
+- Interact with the database to store/retrieve corresponding documents.
+- Provide the /paste/create route to create new documents.
+- Provide /paste/show/:ID to view created documents.
+- Authenticate by user ID, and allow documents to be set as private to prevent others from viewing.
+
+In routes, all defined functions should be asynchronous. Supported functions are: prepare, get, post, post[Operation], cleanup
+The process is as follows:
+
+```
+First execute prepare(args) (if present)
+args is the full set of incoming parameters (including QueryString, Body, Path),
+Then execute prepare(args) (if present)
+Check request type:
+
+Is it GET?
+ -> Execute get(args)
+Is it POST?
+ -> Execute post(args)
+ -> Contains operation field?
+ -> Execute post[Operation]
+
+Execute cleanup()
+```
+
+If this.response.template specifies a template, it will be rendered; otherwise, the content in this.response.body is returned directly.
+
+* Use underscores for the operation field in form submission, and camelCase for function names.
+
+For example, ` ` corresponds to the `postConfirmDelete` function.
+
+You should provide an `apply` function and mount it together with defined Handlers at `global.Hydro.handler[module name]`.
+The `apply` function will be called during initialization.
+
+# Step3 index.ts
+
+```ts twoslash
+// @noErrors
+// @module: esnext
+// @filename: index.ts
+import {
+ db, definePlugin, Handler, NotFoundError, randomstring, param, PermissionError, PRIV, Types,
+} from 'hydrooj';
+
+const coll = db.collection('paste');
+
+interface Paste {
+ _id: string;
+ owner: number;
+ content: string;
+ isPrivate: boolean;
+}
+
+declare module 'hydrooj' {
+ interface Model {
+ pastebin: typeof pastebinModel;
+ }
+ interface Collections {
+ paste: Paste; // 声明数据表类型
+ }
+}
+
+async function add(userId: number, content: string, isPrivate: boolean): Promise {
+ const pasteId = randomstring(16);
+ // 使用 mongodb 为数据库驱动,相关操作参照其文档
+ const result = await coll.insertOne({
+ _id: pasteId,
+ owner: userId,
+ content,
+ isPrivate,
+ });
+ return result.insertedId; // 返回插入的文档ID
+}
+
+async function get(pasteId: string): Promise {
+ return await coll.findOne({ _id: pasteId });
+}
+
+// 暴露这些接口,使得 cli 也能够正常调用这些函数;
+const pastebinModel = { add, get };
+global.Hydro.model.pastebin = pastebinModel;
+
+// 创建新路由
+class PasteCreateHandler extends Handler {
+ // Get请求时触发该函数
+ async get() {
+ // 检查用户是否登录,此处为多余(因为底部注册路由时已声明所需权限)
+ // 此方法适用于权限的动态检查
+ // this.checkPriv(PRIV.PRIV_USER_PROFILE);
+ this.response.template = 'paste_create.html'; // 返回此页面
+ }
+
+ // 使用 Types.Content 检查输入
+ @param('content', Types.Content)
+ @param('private', Types.Boolean)
+ // 从用户提交的表单中取出content和private字段
+ // domainId 为固定传入参数
+ async post(domainId: string, content: string, isPrivate = false) {
+ // 在HTML表单提交的多选框中,选中值为 'on',未选中则为空,需要进行转换
+ const pasteid = await pastebinModel.add(this.user._id, content, !!isPrivate);
+ // 将用户重定向到创建完成的url
+ this.response.redirect = this.url('paste_show', { id: pasteid });
+ // 相应的,提供了 this.back() 方法用于将用户重定向至前一个地址(通常用于 Ajax 或是部分更新操作)
+ }
+}
+
+class PasteShowHandler extends Handler {
+ @param('id', Types.String)
+ async get(domainId: string, id: string) {
+ const doc = await pastebin.get(id);
+ if (!doc) throw new NotFoundError(id);
+ if (doc.isPrivate && this.user._id !== doc.owner) {
+ throw new PermissionError();
+ }
+ this.response.body = { doc };
+ this.response.template = 'paste_show.html';
+ }
+
+ @param('id', Types.String)
+ async postDelete(domainId: string, id: string) {
+ // 当提交表单并存在 operation 值为 delete 时执行。
+ // 本例中未实现删除功能,仅作为说明。
+ }
+}
+
+// Hydro会在服务初始化完成后调用该函数。
+export async function apply() {
+ // 注册一个名为 paste_create 的路由,匹配 '/paste/create',
+ // 使用 PasteCreateHandler 处理,访问该路由需要 PRIV.PRIV_USER_PROFILE 权限
+ // 提示:路由匹配基于 path-to-regexp
+ ctx.Route('paste_create', '/paste/create', PasteCreateHandler, PRIV.PRIV_USER_PROFILE);
+ ctx.Route('paste_show', '/paste/show/:id', PasteShowHandler);
+}
+
+```
+
+## Step4 template
+
+Templates use nunjucks syntax and should be placed in the `templates/` folder.
+At the end of the request, the template is selected based on `response.template`, rendered with `response.body`, and written into `response.body`.
+If `response.template` is empty or `request.headers['accept'] == 'application/json'`, the rendering step is skipped.
+
+## Step5 locale
+
+Used to provide multilingual translations. The format is the same as Hydro's locale folder format.
+
+## Step6 frontend
+
+Write frontend code in the frontend folder. Files named `[a-zA-Z0-9_]+.page.tsx?` are automatically loaded as entry points.
+The paste feature does not require any additional JS-driven frontend interaction, so a minimal format example is provided below.
+
+```tsx
+import './foo.css'; // 如果有额外的样式
+import { addPage, NamedPage, AutoloadPage } from '@hydrooj/ui-default';
+
+addPage(new NamedPage(['problem_detail'], () => {
+ console.log('仅在题目详情页面执行');
+}));
+
+addPage(new AutoloadPage('my_page_name', () => {
+ console.log('在所有页面均会执行');
+}));
+```
diff --git a/content/docs/Hydro/index.en.mdx b/content/docs/Hydro/index.en.mdx
new file mode 100644
index 000000000..2a6ce773a
--- /dev/null
+++ b/content/docs/Hydro/index.en.mdx
@@ -0,0 +1,76 @@
+---
+title: Introduction
+description: Why use Hydro?
+---
+
+- **Secure**: Uses Linux container technologies (read-only filesystem, namespaces, and cgroups) for isolation, effectively preventing sandbox-escape attacks.
+- **Efficient**: Employs sandbox-reuse technology for exceptional judging performance.
+- **Extensible**: Supports a wide range of official and community plugins.
+- **Powerful**: Combined with the Judge module (or standalone HydroJudge), it supports SPJ (Special Judge), interactive problems, output-only tasks, file I/O, and more.
+- **Customizable**: Offers granular control over permission nodes and system settings.
+- **Beginner-friendly**: No source code modifications required. Manage your site through a user-friendly interface.
+- **Community-driven**: Actively maintained by the development team and the community.
+
+- **Migrating from HustOJ?** Export problems as FPS files and import them using the [fps-importer plugin](/docs/Hydro/plugins/fps-importer).
+- **Migrating from QDUOJ?** Use the `import-qduoj` plugin to import zip-format problem exports.
+- **Migrating from Vijos / SYZOJ / HustOJ / UniversalOJ?** The [migrate plugin](/docs/Hydro/plugins/migrate) can import your existing data directly.
+
+## Feature Comparison
+
+Hydro supports many advanced problem types out of the box. You can explore and download sample problems at [hydro.ac/d/system_test/p](https://hydro.ac/d/system_test/p) (Login required).
+
+The table below compares Hydro with other popular Online Judge systems (assuming no source code modifications).
+
+```
++: Supported
+=: Partially supported
+?: Unknown
+-: Not supported
+```
+
+| Feature | Hydro | HustOJ | SYZOJ[^7] | QDUOJ | Vijos |
+| :---: | :---: | :---: | :---: | :---: | :---: |
+| Installation | One-click script | One-click script | Manual setup | Docker | Docker |
+| Database | MongoDB | MySQL | MariaDB | Postgres | MongoDB |
+| Test Data Storage | Local/S3 [^1] | Local | Local | Local | Database |
+| Multiple Judges | + | =[^5] | =[^8] | = | + |
+| Test Data Sync | On-demand fetch | Full sync | Full sync | Full sync | On-demand fetch |
+| Contests | ACM/OI/IOI/Leduo | ACM/OI | ACM/OI/IOI | ACM/OI/IOI | ACM/OI |
+| Scoreboard Freeze | + | + | - | - | - |
+| Assignment Features | + | + | - | - | + |
+| Customizable Compile/Language | + | =[^9] | - | - | + |
+| Granular Permissions [^4] | + | = | - | - | + |
+| Training Plans (Problem Lists) | + | + | -[^6] | - | + |
+| Teams | + [^2] | - | - | - | + |
+| Hack | + | - | - | - | - |
+| Special Judge | + [^3] | + | + | - | = |
+| Subtasks | + | - | + | - | - |
+| Interactive Problems | + | - | + | - | - |
+| Remote Judge | CF/SPOJ/UOJ/POJ/Luogu | HDU/PKU | - | - | - |
+| Problem Import | fps/syzoj/qduoj/hydro | fps/qduoj | syzoj | fps/qduoj | - |
+
+[^1]: S3 refers to any S3-compatible service, such as Tencent Cloud COS, Alibaba Cloud OSS, etc.
+[^2]: Users can create "Domains" with full administrative control. Domains share user account data but remain logically isolated.
+[^3]: Supports all major SPJ formats.
+[^4]: Refers to fine-grained permission control beyond a simple user/admin binary.
+[^5]: Complex configuration; data requires manual synchronization.
+[^6]: Available in some community-modified versions.
+[^7]: SYZOJ and Lyrio (formerly syzoj-ng, used by loj.ac) are distinct systems. SYZOJ cannot natively import loj.ac problems; Lyrio lacks contest features.
+[^8]: Manual data synchronization required.
+[^9]: Only specific compile parameters can be modified; adding a language requires source code changes.
+
+## Screenshots
+
+
+
+
+
+
+
+
+
+
+## Get Started
+
+Click [Deploy](/docs/Hydro/install/) to set up your own Online Judge!
+
diff --git a/content/docs/Hydro/install/compiler.en.mdx b/content/docs/Hydro/install/compiler.en.mdx
new file mode 100644
index 000000000..278ad26a1
--- /dev/null
+++ b/content/docs/Hydro/install/compiler.en.mdx
@@ -0,0 +1,119 @@
+---
+title: Compilers and Languages
+---
+
+Starting from 2022/8/12, to prevent host-environment changes from affecting judging consistency, Hydro uses [nix]() by default to manage environments for **instances installed after this date**.
+If your Hydro instance was installed prior to this date, please install compilers via `apt`, restart the sandbox with `pm2 restart hydro-sandbox`, and skip this section.
+
+Below is a brief guide to nix operations:
+
+Use `nix-env -iA nixpkgs.` to install a new compiler, then restart the sandbox with `pm2 restart hydro-sandbox` for it to take effect.
+
+You can search for required compilers at [Nixos Search](https://search.nixos.org/packages).
+Here are examples of commonly used compilers:
+
+```sh
+nix-env -iA nixpkgs.coreutils nixpkgs.bash nixpkgs.gawk nixpkgs.unzip # Base components, pre-installed, do not remove
+nix-env -iA nixpkgs.gcc nixpkgs.fpc # C/C++ and Pascal, pre-installed, do not remove
+nix-env -iA nixpkgs.ghc # Haskell
+nix-env -iA nixpkgs.rustc # Rust
+nix-env -iA nixpkgs.python3Minimal
+nix-env -iA nixpkgs.python3Packages.numpy
+nix-env -iA nixpkgs.pypy3
+nix-env -iA nixpkgs.php
+nix-env -iA nixpkgs.go # Golang
+nix-env -iA nixpkgs.nodejs
+nix-env -iA nixpkgs.openjdk_headless # Java
+nix-env -iA nixpkgs.ruby
+nix-env -iA nixpkgs.mono # C#
+nix-env -iA nixpkgs.julia_17-bin # Julia
+nix-env -iA nixpkgs.iverilog # Verilog
+```
+
+Use `nix-env -q` to view the list of installed packages, and use `nix-env -e ` to remove a specific compiler.
+Please be careful not to accidentally delete Hydro base components. After completing your operations, you must restart the sandbox with `pm2 restart hydro-sandbox` for the changes to take effect.
+
+
+Some languages (specifically Java, etc.), due to their language characteristics, require a longer CPU time for compilation. This is particularly noticeable on single-core machines, where compiling even A+B might take several seconds or even tens of seconds.
+The expected performance can be tested by manually running the compilation command on the host:
+
+```sh
+javac -d /w -encoding utf8 ./Main.java && jar cvf Main.jar *.class
+```
+
+At the same time, some compilers will attempt to create a large number of processes to utilize multi-core parallel compilation whenever possible. Please ensure the `processLimit` item in the judge settings is large enough; otherwise, compilation will fail because the compiler cannot create processes.
+
+When the compiler utilizes multi-core parallel compilation, Hydro sums the CPU usage of these processes as the CPU resource limit. If a compilation timeout error occurs, please adjust the `compile_time_limit` item (in ms) under the corresponding language option in the system settings.
+
+Similarly, if a memory limit exceeded error occurs, you can modify the `compile_memory_limit` item (in MB) for the corresponding language.
+
+
+
+After installing a `python` package using `sh nix-env -iA nixpkgs.python3Packages.xxxxx`, if dependencies cannot be found in the sandbox environment, please refer to the [Import Python packages into sandbox](https://hydro.ac/d/faqs/p/15) tutorial to update environment variables.
+
+
+## Language-specific Time Limit Modifications
+
+By default, the system provides double the time limit for Java and Kotlin. This behavior can be modified in the language settings:
+
+```yml
+# System Settings -> Language Settings
+java:
+ # ... existing settings ...
+ time_limit_rate: 2
+```
+
+## Colored C/C++ Compilation Error Output
+
+1. Ensure you have installed a compiler that supports colored output;
+2. In system settings, append `-fdiagnostics-color=always` to the C/C++ compilation commands.
+
+Example:
+
+```yml
+c:
+ compile: /usr/bin/gcc -O2 -Wall -std=c99 -o ${name} foo.c -lm -fdiagnostics-color=always
+```
+
+## Advanced Environment Configuration
+
+If you require a more complex compilation environment configuration, we recommend writing a separate nix file.
+
+```nix
+{
+ system ? builtins.currentSystem,
+ pkgs ? import { system = system; }
+}:
+
+pkgs.buildEnv {
+ name = "hydrojudge-rootfs";
+ paths = with pkgs; [
+ coreutils bash nix zip unzip gcc gawk
+ # The packages above are required for judging, do not remove them.
+ # List the packages you need below, search method is the same as above:
+ fpc python3 rustc
+ ];
+ ignoreCollisions = true;
+ pathsToLink = [ "/" ];
+ # Export some basic info and /etc/passwd required by some compilers
+ postBuild = ''
+ mkdir $out/buildInfo
+ echo 'root:x:0:0:root:/root:/bin/bash' >$out/etc/passwd
+ date >$out/buildInfo/timestamp
+ '';
+}
+```
+
+Copy the file above, save it as `default.nix`, and use `nix-build` to build it.
+After building, a `result` folder will be generated. Remember the path where this folder is located.
+Open `~/.hydro/mount.yaml` and replace `/root/.nix-profile` in it with the compiled `result` folder (switching to the new environment).
+Then save and restart the sandbox.
+
+If you need to change the environment configuration later, simply modify the `default.nix` file, use `nix-build` to rebuild, and restart the sandbox for it to take effect.
+Cache files generated during the build process can be cleaned up using `nix-collect-garbage`.
+
+For a more detailed introduction to the nix language, please refer to the [Nix Guide](https://nixos.org/guides/nix-language.html) and [Nix Manual](https://nixos.org/manual/nix/stable/language/index.html).
+
+## Others
+
+Recommended reading: the [HydroJudge](../plugins/hydrojudge) section, to learn more detailed information about judge machine settings.
\ No newline at end of file
diff --git a/content/docs/Hydro/install/index.en.mdx b/content/docs/Hydro/install/index.en.mdx
new file mode 100644
index 000000000..318dbf4cc
--- /dev/null
+++ b/content/docs/Hydro/install/index.en.mdx
@@ -0,0 +1,89 @@
+---
+title: Deploy Hydro
+---
+
+Multiple deployment options are available to help you build your site. Choose the one that best fits your needs.
+If you encounter any issues during setup, feel free to [contact us](/#contact-us).
+
+## Selecting a Server
+
+Performance varies by provider; the specifications below are for reference only.
+- **Minimum Requirements**: 1 CPU core, 2GB RAM. (Supports ~100 concurrent users).
+- **Important**: Avoid burstable (e.g., AWS t-series) or shared-core instances where possible, as they can cause inconsistent and inaccurate judging time measurements.
+
+**Operating System Notes:**
+- CentOS 8 reached [End-of-Life (EOL)](https://www.centos.org/centos-linux-eol/) on 2021-12-31 and no longer receives security patches. We recommend reinstalling your server with a supported OS.
+
+
+**Recommended OS**: Debian 12, Debian 11, or Ubuntu 22.04. These distributions offer the best support, documentation, and success rate for beginners.
+
+**Unsupported OS**: CentOS and its derivatives (Alibaba Cloud Linux, TencentOS, OpenCloudOS, etc.) are **not supported**.
+
+**Low-Memory Servers (≤ 2GB RAM)**: Avoid Ubuntu 22.04 due to its higher memory footprint. Debian 12 or 11 is recommended.
+For experienced Linux users, **Alpine Linux** is an excellent choice, consuming only ~100MB RAM after boot.
+
+
+Using these referral links helps support the project through small cashbacks (at no extra cost to you):
+- [Tencent Cloud](https://curl.qcloud.com/KE7pzCW4)
+- [Alibaba Cloud (15% discount)](https://www.aliyun.com/minisite/goods?userCode=806xqzxc)
+
+
+**Mainland China Users**: Without an ICP filing, some providers (like China Telecom Cloud) block ports 80 and 443. Ensure you understand the regulations before purchasing.
+
+
+
+**Virtual Machine (VM) Users**:
+- Hydro's database relies on the CPU **AVX instruction set** for optimal performance. Most virtualization software (VMware, VirtualBox, etc.) disables AVX by default; check your documentation to enable it.
+- Lack of exclusive CPU access can lead to inconsistent judging times.
+- Sudden power loss can easily corrupt VM databases. **Regular backups are essential.**
+
+**Docker Users**:
+- When using the installation script, set the `USER` environment variable to `root`.
+- You **must** start the container with `--privileged` for the judge sandbox to function.
+- The development team does not provide free technical support for Docker-based deployments.
+
+**Control Panel Users (e.g., BT/BaoTa)**:
+- These panels often have critical security vulnerabilities. We strongly advise against using them in production.
+- Developers are not responsible for issues arising from panel usage.
+- Free technical support is not available for deployments using third-party panels.
+
+For **paid technical support**, please contact us via WeCom.
+
+
+## Deploy
+
+
+**Required Ports**: Ensure ports `80, 443, 2019, 8888, 5050, 27017` are open in your firewall.
+**Permissions**: All installation and post-installation steps **must** be performed with root privileges (`sudo -i`).
+
+
+Run the following command to start the installation (copy and paste to avoid errors):
+
+```sh
+LANG=en . <(curl https://hydro.ac/setup.sh)
+```
+
+
+The installation script supports advanced flags for custom requirements:
+- `--no-caddy`: Skips reverse proxy setup; the service will listen only on `127.0.0.1:8888`.
+- `--judge`: Installs only the standalone judge component.
+Example: `. <(curl https://hydro.ac/setup.sh) --no-caddy`
+
+
+**Post-Installation Tips**:
+- If you are on a cloud provider (AWS, Alibaba, etc.), ensure your "Security Group" allows traffic on port 80.
+- Open `http://your-server-ip/` in your browser and register an account.
+- To promote the first registered user to Super Admin, run:
+
+```sh
+hydrooj cli user setSuperAdmin 2
+```
+
+- After logging in, access the Control Panel from the navigation bar.
+- **Critical**: In System Settings, verify the `Server BaseURL`. It must be the full URL (including `https://` if applicable) and **must end with a trailing slash `/`** (e.g., `https://hydro.ac/`).
+
+**Loading Problems**:
+You can find a free starter problem set at [hydro.ac/d/tk/p](https://hydro.ac/d/tk/p). Batch import is supported.
+
+If your server is in a private network, you may need to configure "Port Forwarding" or a VPN for external access.
+
diff --git a/content/docs/Hydro/install/meta.en.json b/content/docs/Hydro/install/meta.en.json
new file mode 100644
index 000000000..14d6f208f
--- /dev/null
+++ b/content/docs/Hydro/install/meta.en.json
@@ -0,0 +1,11 @@
+{
+ "title": "Installation",
+ "description": "Install Hydro",
+ "pages": [
+ "s3",
+ "proxy",
+ "compiler",
+ "smtp",
+ "riscv"
+ ]
+}
diff --git a/content/docs/Hydro/install/proxy.en.mdx b/content/docs/Hydro/install/proxy.en.mdx
new file mode 100644
index 000000000..4024c5a4a
--- /dev/null
+++ b/content/docs/Hydro/install/proxy.en.mdx
@@ -0,0 +1,44 @@
+---
+title: Reverse Proxy / SSL Configuration
+---
+
+### Instances installed via script after 2022/10/27 are already configured with Caddy reverse proxy automatically. Please edit the config file located at `~/.hydro/Caddyfile` directly!
+
+
+If you use a reverse proxy, please note that the `server.xff` and `server.xhost` settings in the system settings need to be filled in correctly (in lowercase), corresponding to the header names added by the reverse proxy (usually `x-forwarded-for` and `x-forwarded-host`; some reverse proxy tools use `x-real-ip` instead of `x-forwarded-for`).
+Incorrect configuration of the `server.xhost` setting will cause issues such as users being unable to log in. (CsrfTokenError)
+Incorrect configuration of the `server.xff` setting will result in the inability to record user IPs.
+
+Except for the one-click installation script which automatically configures these settings after installing Caddy, for other tools please configure the system settings before using the tool! Otherwise, it will cause problems like users being unable to log in and user IPs not being recorded.
+
+If you use Nginx, please remember to configure the reverse proxy for the WebSocket protocol; otherwise, it will cause issues such as the judging status not refreshing automatically and the online IDE not functioning properly.
+
+
+Hydro supports using tools like Caddy and HAProxy for reverse proxying. Some configuration examples are provided [here](https://github.com/hydro-dev/Hydro/tree/master/examples/reverse_proxy).
+
+Hydro recommends that you use [Caddy](https://caddyserver.com/). Below is a sample Caddyfile.
+Tip: If your server is located in mainland China, you need to complete ICP filing before you can use ports 80 and 443.
+
+```
+hydro.ac {
+ log {
+ output file /data/access.log {
+ roll_size 1gb
+ roll_keep_for 72h
+ }
+ format json
+ }
+ root * /root/.hydro/static
+ @static {
+ file {
+ try_files {path}
+ }
+ }
+ handle @static {
+ file_server
+ }
+ handle {
+ reverse_proxy http://127.0.0.1:8888
+ }
+}
+```
\ No newline at end of file
diff --git a/content/docs/Hydro/install/riscv.en.mdx b/content/docs/Hydro/install/riscv.en.mdx
new file mode 100644
index 000000000..79b8f0317
--- /dev/null
+++ b/content/docs/Hydro/install/riscv.en.mdx
@@ -0,0 +1,136 @@
+---
+title: Installation on RISC-V Architecture
+---
+
+## System Environment
+
+This article is based on Sipeed Lichee Pi 4A 16G, using RevyOS 20250526_182059 firmware. Thanks to the [Jiachen Project](https://rv2036.org/) for hardware support,
+and thanks to [Anillc](https://github.com/Anillc) and [NickCao](https://github.com/NickCao) for their help.
+
+## Initialize the Nix Environment
+
+```bash
+curl -sSL https://hydro.ac/nix.sh | bash
+```
+
+To save your life, configure extra binary caches: `https://cache.nichi.co https://nix-community.cachix.org`
+`nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= hydra.nichi.co-0:P3nkYHhmcLR3eNJgOAnHDjmQLkfqheGyhZ6GLrUVHwk=`
+
+## Build MongoDB
+
+MongoDB does not provide official RISC-V support, so we need to compile MongoDB ourselves (this step can be skipped if using MongoDB Atlas).
+
+Clone the MongoDB repository:
+
+```bash
+git clone git@github.com:mongodb/mongo --depth=1 --branch=r7.0.22
+```
+
+Download mozjs release:
+
+```bash
+cd src/third_party/mozjs
+bash get-sources.sh
+```
+
+Add RISC-V support to `gen-config.sh` in the same directory:
+
+```diff
+diff --git a/src/third_party/mozjs/gen-config.sh b/src/third_party/mozjs/gen-config.sh
+index 9144a461..141e089b 100755
+--- a/src/third_party/mozjs/gen-config.sh
++++ b/src/third_party/mozjs/gen-config.sh
+@@ -61,6 +61,9 @@ case "$_Path" in
+ _xcode_setup "macosx" "x86_64" "macos-version-min=10.9"
+ _CONFIG_OPTS="--host=x86_64-apple-darwin"
+ ;;
++ "platform/riscv64/linux")
++ _CONFIG_OPTS="--host=riscv64-linux"
++ ;;
+ "platform/aarch64/iOS")
+ _xcode_setup "iphoneos" "arm64" "iphoneos-version-min=10.2"
+ _CONFIG_OPTS="--target=aarch64-apple-darwin"
+```
+
+Run `gen-config.sh` to generate the `platform/riscv64/linux` directory:
+
+```bash
+bash gen-config.sh riscv64 linux
+```
+
+```diff
+diff --git a/src/third_party/mozjs/platform/riscv64/linux/build/Unified_cpp_js_src0.cpp b/src/third_party/mozjs/platform/riscv64/linux/build/Unified_cpp_js_src0.cpp
+new file mode 100644
+index 00000000..624b0d97
+--- /dev/null
++++ b/src/third_party/mozjs/platform/riscv64/linux/build/Unified_cpp_js_src0.cpp
+@@ -0,0 +1,55 @@
++#define MOZ_UNIFIED_BUILD
++#include "builtin/Array.cpp"
++#ifdef PL_ARENA_CONST_ALIGN_MASK
++#error "builtin/Array.cpp uses PL_ARENA_CONST_ALIGN_MASK, so it cannot be built in unified mode."
++#undef PL_ARENA_CONST_ALIGN_MASK
++#endif
++#ifdef INITGUID
+# 行数过多,下略
+```
+
+Modify MongoDB `platform/pause.h` to add RISC-V support:
+
+```diff
+diff --git a/src/mongo/platform/pause.h b/src/mongo/platform/pause.h
+index 67fe3d94..b3f50efb 100644
+--- a/src/mongo/platform/pause.h
++++ b/src/mongo/platform/pause.h
+@@ -69,7 +69,7 @@
+
+ #define MONGO_YIELD_CORE_FOR_SMT() __asm__ volatile("rd %%ccr, %%g0" ::: "memory")
+
+-#elif defined(__EMSCRIPTEN__)
++#elif defined(__EMSCRIPTEN__) || defined(__riscv)
+
+ // TODO: What should this be?
+ #define MONGO_YIELD_CORE_FOR_SMT()
+```
+
+Pass the patches above into nixpkgs:
+
+```diff
+diff --git a/pkgs/servers/nosql/mongodb/7.0.nix b/pkgs/servers/nosql/mongodb/7.0.nix
+index cb4bbf53279f..0526976d4e8b 100644
+--- a/pkgs/servers/nosql/mongodb/7.0.nix
++++ b/pkgs/servers/nosql/mongodb/7.0.nix
+@@ -35,7 +35,11 @@ buildMongoDB {
+ # mongodb-7_0's mozjs uses avx2 instructions
+ # https://github.com/GermanAizek/mongodb-without-avx/issues/16
+ ]
+- ++ lib.optionals (!avxSupport) [ ./mozjs-noavx.patch ];
++ ++ lib.optionals (!avxSupport) [ ./mozjs-noavx.patch ]
++ ++ lib.optionals (stdenv.hostPlatform.isRiscV64) [
++ ./mongodb-riscv.patch
++ ./mozjs-riscv.patch
++ ];
+
+ passthru.tests = {
+ inherit (nixosTests) mongodb;
+```
+
+For the modifications above, refer to [Nixpkgs PR#430577](https://github.com/NixOS/nixpkgs/pull/430577)
+
+Build to obtain MongoDB 7.0.22 for RISC-V, then use `nix copy` to transfer it to the target device.
+
+## Install Components and Start
+
+```bash
+nix profile add nixpkgs#bashInteractive nixpkgs#nodejs nixpkgs#yarn nixpkgs#pm2 nixpkgs#gawk \
+ nixpkgs#go-judge nixpkgs#gcc # and other compilers...
+yarn global add hydrooj @hydrooj/ui-default @hydrooj/hydrojudge
+hydrooj addon add @hydrooj/ui-default
+hydrooj addon add @hydrooj/hydrojudge
+pm2 start hydrooj
+```
+
+## Compiler/Language Compatibility
+
+- Tested and working: bash, c, c++, python3, nodejs, go, ruby
+- Not available yet: java, pascal, kotlin, php, rust, csharp
diff --git a/content/docs/Hydro/install/s3.en.mdx b/content/docs/Hydro/install/s3.en.mdx
new file mode 100644
index 000000000..2c51465a7
--- /dev/null
+++ b/content/docs/Hydro/install/s3.en.mdx
@@ -0,0 +1,63 @@
+---
+title: Storage
+---
+
+
+Hydro instances deployed using the one-click installation script are generally automatically configured for storage.
+
+
+Files are stored locally in the `/data/file/hydro` directory by default. When switching storage backends, you need to manually copy or move the existing files.
+Please read the corresponding tutorial based on the type of storage backend you are using. (We also welcome users of other storage types to provide us with detailed storage tutorials.)
+
+If you wish to move the file storage location, please follow these steps in order:
+
+1. Stop the Hydro service
+2. Move the `/data/file/hydro` directory to the new location
+3. Start Hydro, and immediately go to Control Panel -> Configuration Management, and set `file.path` to the new directory location
+4. Restart the Hydro service
+
+### Use S3 as the Storage Backend
+
+
+If the `file.pathStyle` option is disabled, please fill in the real URLs in the `endPointForUser` and `endPointForJudge` settings; the `/fs/` endpoint will be unavailable.
+
+
+**SeaweedFS**
+
+
+The installation and maintenance of SeaweedFS are relatively complex and require a considerable amount of professional knowledge. This is for reference only and is not recommended for non-professional users.
+
+
+After [installing and configuring SeaweedFS](https://github.com/seaweedfs/seaweedfs), go to Control Panel > manage_config.
+
+- `file.type`: `s3`
+- `file.endPoint`: `http://127.0.0.1:8333`
+- `file.accessKey`: Refer to SeaweedFS configuration
+- `file.secretKey`: Refer to SeaweedFS configuration
+- `file.bucket`: `hydro` (SeaweedFS internal bucket name)
+- `file.region`: `Auto`
+- `file.pathStyle`: true
+- `file.endPointForUser`: `/fs/`
+- `file.endPointForJudge`: `/fs/`
+
+Save and restart. For existing files, please copy them manually.
+
+**Tencent Cloud COS**
+
+Go to Control Panel > System Settings > Bucket Settings.
+
+- `file.type`: `s3`
+- `file.endPoint`: `https://cos..myqcloud.com` (or https)
+- `file.accessKey`: The SecretId of your Tencent Cloud API key
+- `file.secretKey`: The SecretKey of your Tencent Cloud API key
+- `file.bucket`: \
+- `file.region`: Auto
+- `file.pathStyle`: false
+- `file.endPointForUser`: `https://.cos..myqcloud.com/`
+- `file.endPointForJudge`: `https://.cos..myqcloud.com/`
+
+Save and restart. For existing files, please copy them manually.
+
+**Alibaba Cloud OSS**
+
+// TODO & PRs Welcome
\ No newline at end of file
diff --git a/content/docs/Hydro/install/smtp.en.md b/content/docs/Hydro/install/smtp.en.md
new file mode 100644
index 000000000..b10f52592
--- /dev/null
+++ b/content/docs/Hydro/install/smtp.en.md
@@ -0,0 +1,26 @@
+---
+title: SMTP
+---
+
+Take QQ Mail as an example.
+
+- SMTP_USER: 12345678@qq.com
+- SMTP_PASS: provided SMTP password
+- SMTP_HOST: smtp.qq.com
+- SMTP_PORT: 465/587 (refer to your mail service provider documentation)
+- SMTP_SECURE: whether to use an encrypted TLS connection (refer to your mail service provider documentation; providers that use STARTTLS do not need this checked)
+- SMTP_FROM: sender signature (Tip: if unsure, fill in your email address; incorrect value will cause email sending failure)
+
+Known fully compatible providers include:
+
+- QQ Mail
+- Tencent Exmail
+- NetEase 163 Mail
+- Feishu Domain Mail
+- Zeptomail
+- Zoho Mail
+- Outlook
+- Gmail
+- Sina Mail
+
+If you use other providers and find no issues, welcome to submit a Pull Request to this list.
diff --git a/content/docs/Hydro/meta.en.json b/content/docs/Hydro/meta.en.json
new file mode 100644
index 000000000..ddc27d19e
--- /dev/null
+++ b/content/docs/Hydro/meta.en.json
@@ -0,0 +1,13 @@
+{
+ "title": "Hydro",
+ "root": true,
+ "description": "Hydro",
+ "pages": [
+ "install",
+ "system",
+ "user",
+ "FAQ",
+ "dev",
+ "plugins"
+ ]
+}
diff --git a/content/docs/Hydro/plugins/elastic.en.mdx b/content/docs/Hydro/plugins/elastic.en.mdx
new file mode 100644
index 000000000..fa4df78ff
--- /dev/null
+++ b/content/docs/Hydro/plugins/elastic.en.mdx
@@ -0,0 +1,15 @@
+---
+title: Elastic search
+---
+
+
+This plugin requires the third-party software Elasticsearch. If you **only install the plugin without configuring/installing the third-party software**, the system may fail to run properly. Elasticsearch is not lightweight software; if your server does not meet its requirements, installation is not recommended.
+
+
+After installing Elasticsearch, install the `@hydrooj/elastic-search` plugin.
+
+Go to the HydroOJ control panel and correctly fill in the `endpoint` in System Settings.
+
+Then find Rebuild Problem Index in Script Management, click Run, and leave the parameters empty.
+
+At this point, search should work properly.
diff --git a/content/docs/Hydro/plugins/extra.en.md b/content/docs/Hydro/plugins/extra.en.md
new file mode 100644
index 000000000..0f7b22fe1
--- /dev/null
+++ b/content/docs/Hydro/plugins/extra.en.md
@@ -0,0 +1,40 @@
+---
+title: Other
+---
+
+## Premium and Custom Add-ons
+
+Hydro offers a variety of premium plugins for enterprise and complex educational needs. For inquiries or custom development, please contact the development team via the **QQ Group (1085853538)**.
+
+### Authentication and Security
+- **SMS Support**: Replace or augment email with SMS for registration and password recovery. Supports Alibaba, Tencent, and Huawei Cloud APIs.
+- **WeChat Login**: Allows users to log in by scanning a WeChat QR code (Requires a verified WeChat Service Account).
+
+### Contest Tools
+- **Contest PDF**: Instantly export all problem statements in a contest into a single, formatted PDF.
+- **Bulk Submit**: Tools for offline contests (OI-style) to collect, package, and upload contestant code for centralized judging.
+
+### Educational Features
+- **Course System**: A comprehensive management suite for classes, handouts, and student progress tracking.
+- **User Expiration**: Automate access control based on subscription or enrollment periods.
+- **Blockly**: Integrated block-based visual programming for beginners.
+
+### UI and UX
+- **Swiper**: A customizable carousel banner for the site homepage.
+- **History Charts**: Visual representation of user rating and submission frequency history.
+- **User Management Panel**: An enhanced, one-stop web interface for administrators to manage users and permissions.
+
+### Advanced Capabilities
+- **AI Integration**: AI-driven bug detection, problem Q&A, and solution analysis.
+- **Turtle/GOC Graphics**: Specialized environments for Turtle graphics and GOC programming.
+
+### External Problem Sets
+
+We provide access to high-quality mirrors for popular competitive programming platforms:
+- **Mirror Services**: For **LOJ, AtCoder, and BZOJ**, we maintain dedicated mirrors with complete test data. We charge a nominal operational fee of **0.002 CNY per submission**.
+- **Self-Hosting Data**:
+ - **LOJ**: Use [loj-download](https://github.com/hydro-dev/loj-download) (~180GB).
+ - **AtCoder**: Public test data downloads are no longer provided.
+ - **BZOJ**: Please search for third-party sources (approx. 64GB).
+- **Luogu Integration**: Remote judging for Luogu is available through the [Luogu Open Platform](https://docs.lgapi.cn/open/). This service is managed by Luogu. Alternatively, you can purchase authorization directly through [Hydro](https://hydro.ac/luogu/pay) at a discounted channel rate.
+
diff --git a/content/docs/Hydro/plugins/fps-importer.en.md b/content/docs/Hydro/plugins/fps-importer.en.md
new file mode 100644
index 000000000..d4bb70b13
--- /dev/null
+++ b/content/docs/Hydro/plugins/fps-importer.en.md
@@ -0,0 +1,16 @@
+---
+title: fps-importer
+---
+
+## Import Problems from FPS Files
+
+In the problemset page, choose "Import from FPS file" under the "Create Problem" section on the right.
+In the opened window, you can upload:
+
+- an XML file in fps format
+- a zip file that contains one or more XML files in fps format
+
+To prevent parsing fps files from consuming excessive memory, the system rejects files larger than 64MiB by default;
+XML files must use UTF-8 encoding, otherwise Chinese problem statements may become garbled;
+In newer versions of fps-importer, administrators can modify the import file size limit, but note that we still do not recommend importing overly large problem packages.
+If your file exceeds the size limit, consider splitting it locally first with tools such as Easy-Fps-Viewer.
diff --git a/content/docs/Hydro/plugins/geoip.en.md b/content/docs/Hydro/plugins/geoip.en.md
new file mode 100644
index 000000000..69b1ddec3
--- /dev/null
+++ b/content/docs/Hydro/plugins/geoip.en.md
@@ -0,0 +1,5 @@
+---
+title: GeoIP
+---
+
+This plugin requires MaxMind's `Geolite2-City.mmdb`. After installing the plugin, you need to copy the mmdb file to the same directory as the plugin to enable it. If you don't know what this is, do not install it.
diff --git a/content/docs/Hydro/plugins/hydrojudge.en.mdx b/content/docs/Hydro/plugins/hydrojudge.en.mdx
new file mode 100644
index 000000000..1543f9817
--- /dev/null
+++ b/content/docs/Hydro/plugins/hydrojudge.en.mdx
@@ -0,0 +1,233 @@
+---
+title: hydrojudge
+---
+
+
+You can quickly install a standalone judge machine with the one-click installation script. For details, see [Deploy Hydro](../install/#Deploy).
+
+
+## Preparation
+
+Before configuring the judge machine, make sure your site is accessible and login/registration works normally.
+
+You should download compilers for the languages you want to support in advance. If you upgrade/reinstall compilers after configuring the judge machine, you need to restart the sandbox.
+For compiler details, refer to the [Compiler](../install/compiler) section.
+
+If you are not using the automatic script, you need to manually install the sandbox service as follows:
+Go to [criyle/go-judge](https://github.com/criyle/go-judge/releases) and download the go-judge build for your CPU architecture.
+go-judge needs to run in the background and listen on `127.0.0.1:5050`. If your system uses cgroup v1 or a distro without systemd init, run it **as root**.
+You can manage it with pm2.
+
+## Installation
+
+### As an add-on
+
+
+Because a judge installed as an add-on must be on the same server as Hydro, each Hydro instance can have at most one add-on-installed judge machine.
+
+
+Run the following commands on the machine where Hydro is installed to install `@hydrooj/hydrojudge`:
+
+```sh
+yarn global add @hydrooj/hydrojudge
+hydrooj addon add @hydrooj/hydrojudge
+```
+
+After restarting Hydro, hydrojudge will run normally.
+
+### As a standalone process
+
+
+This method helps you deploy judge machines on any server.
+
+
+
+We recommend that all standalone judge machines use identical hardware and that you disable the built-in judge to ensure stable judging results.
+Judge-related options in System Settings only control the built-in judge. Standalone judges must be configured in judge.yaml.
+
+
+First, create an account with PRIV_JUDGE permission. See [here](../system/cli/#创建评测账号) for details. (Run this on the Hydro server)
+
+Then install HydroJudge on the server that runs the judge machine:
+
+```sh
+. <(curl https://hydro.ac/setup.sh) --judge
+```
+
+Create directory `~/.config/hydro`, then create file `judge.yaml` in it. The config format is:
+
+```yaml
+hosts:
+ localhost:
+ type: hydro # For vj4 users, fill in vj4 here
+ server_url: http://localhost/ # URL where Hydro runs
+ uname: judge # Judge account username
+ password: abc123 # Judge account password
+ detail: true # default is true
+```
+
+After configuration, run the command below to start it (you can manage it with pm2):
+
+```sh
+hydrojudge
+```
+
+## Update
+
+HydroJudge receives updates from time to time. You can use `yarn global upgrade-interactive --latest` to check for and apply updates.
+
+## Disable
+
+- As an add-on: In System Settings > Config Management, enable Disable builtin judge, then restart Hydro.
+- As a standalone process: Stop it according to how you started it.
+
+## Uninstall
+
+After disabling, run the commands below.
+
+```sh
+yarn global remove @hydrooj/hydrojudge
+hydrooj addon remove @hydrooj/hydrojudge
+```
+
+## Judge Settings
+
+### As an add-on
+
+Modify parameters in System Settings > hydrojudge, then restart Hydro and hydrojudge.
+
+### As a standalone process
+
+If you need to change settings such as the maximum number of test cases per problem, add the following at the end of `~/.config/hydro/judge.yaml`:
+
+```yaml
+testcases_max: 100 # Maximum test cases per problem
+total_time_limit: 120 # Maximum total judging time per problem
+parallelism: 2 # Number of judging processes per judge machine
+# More optional settings can be added here, in the same format as above
+```
+
+All settings listed [here](https://github.com/hydro-dev/Hydro/blob/master/packages/hydrojudge/src/config.ts#L16) can be added here.
+
+## Modify compiler options / add support for new languages
+
+Modify `hydrooj.langs` in Control Panel > System Settings (applies to all judge machines connected to this server)
+or configure it in `~/.config/hydro/langs.yaml` (applies to a single standalone judge machine, not recommended).
+
+For file format, see [here](https://github.com/hydro-dev/Hydro/blob/master/packages/hydrooj/setting.yaml#L22).
+
+If you added a new language, you also need to modify Language Highlight ID and Monaco language modes in Control Panel > System Settings.
+These define syntax highlighting (based on PrismJS) and Monaco editor language mode respectively after selecting that language.
+
+After modification, restart Hydro and hydrojudge.
+
+See more in the [Compilers and Languages](../install/compiler) section.
+
+## Debug sandbox environment
+
+If you need to debug compilation/runtime errors in the sandbox, use `hydrojudge terminal` to open an interactive judge terminal. This terminal runs in an isolated sandbox identical to the judging environment.
+
+## Clear data cache
+
+To clear judging data cache, use `hydrojudge cache prune` to remove test data unused for 30 days. To specify days, add parameter `--duration=x` to clear data unused for `x` days.
+
+To clear all cached data, use `hydrojudge cache clean`.
+
+## Test data format
+
+Configure according to [Test Data Format](../user/problem/#测试数据格式).
+
+## Adjust sandbox storage size
+
+
+If you do not adjust sandbox storage size, judging with file I/O and large input/output files may cause errors.
+
+
+For users installed before 2022/8/12:
+
+Run the following on the server to find the runtime directory of hydro-sandbox:
+```sh
+pm2 info hydro-sandbox | grep "exec cwd"
+```
+
+Refer to custom mount configuration in [Sandbox filesystem mount documentation](https://docs.goj.ac/mount#customization), save it in the runtime directory as `mount.yaml`.
+Modify `size` and `nr_inodes` mount parameters for `work dir` and `tmp dir` to your desired values, save, then restart `hydro-sandbox` to apply.
+
+For users installed after 2022/8/12:
+
+Edit `/root/.hydro/mount.yaml` and modify `size`.
+
+## Increase program stack size
+
+**Instances installed after 2022/8/12 already have unlimited stack size enabled by default; no manual action needed**
+
+In many cases, the default stack size provided by the system is insufficient. You need to manually provide a larger stack for user programs.
+
+Modify hydro-sandbox startup arguments in pm2 to `ulimit -s unlimited && /usr/bin/hydro-sandbox`:
+
+```sh
+pm2 del hydro-sandbox
+pm2 start bash --name hydro-sandbox -- -c "ulimit -s unlimited && hydro-sandbox"
+```
+
+## Improve judging precision
+
+Disable CPU frequency scaling and Intel Turbo Boost to avoid CPU frequency fluctuations.
+
+Disable ASLR so code with memory addressing errors can produce more reproducible results. Add the following line in `/etc/sysctl.conf` and run `sudo sysctl -p`:
+
+```
+kernel.randomize_va_space = 0
+```
+
+Enable sandbox CPU affinity. For example, on an `8`-core system, to restrict judging tasks to CPU `2,4,6`, use:
+
+```sh
+pm2 start hydro-sandbox -- -c "ulimit -s unlimited && hydro-sandbox -mount-conf /root/.hydro/mount.yaml -cpuset 2,4,6"
+pm2 save
+```
+
+Then the maximum number of concurrent tasks is the number of cores separated by `,` (in this example, `3`), and each concurrent judging task is assigned one core in the configuration. When enabling this option, `parallelism` is recommended to match the number of cores available to sandbox tasks. This setting should be tuned based on the judge machine's CPU specifics (such as hyper-threading, NUMA, etc.). It also requires sandbox version `v1.11.2` or above.
+
+Also, to prevent other tasks from using those cores, you can use `isolcpus` kernel parameter. For example, on an `8`-core system, to prevent other tasks from using CPU `2-7`, add `isolcpus=2-7` to kernel boot parameters. See [Inaccurate memory measurement](#内存计量不准确) for how to modify kernel boot parameters.
+
+## Inaccurate memory measurement
+
+If you see warning `You are using cgroup v2 without kernel 5.19+. This could result in inaccurate memory usage measurements.` in the control panel, it means current memory usage measurement has error.
+
+Some Linux devices use cgroup2 by default, and cgroup2 kernels before 5.19 removed interfaces for precise memory usage accounting.
+For more accurate memory measurement, enabling cgroup v1 is recommended (you can verify whether cgroup v1 is enabled by checking if `/sys/fs/cgroup/memory/memory.memsw.usage_in_bytes` exists):
+
+Using Ubuntu's default bootloader GRUB 2 as an example, edit `/etc/default/grub`:
+In
+
+```
+GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
+```
+
+add `cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0`, so it becomes:
+
+```
+GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0"
+```
+
+Run the following command to update GRUB 2 config, then reboot.
+
+```sh
+update-grub && reboot
+```
+
+## Memory controller not enabled
+
+If you see warning `The memory cgroup controller is not enabled. This could result in inaccurate memory usage measurements.` in the control panel, it means the memory cgroup controller is not enabled on current system.
+
+Some Linux systems (such as Raspbian) do not enable the memory cgroup controller by default. Enabling it provides more accurate memory limits and measurements.
+
+Using Raspbian as an example, edit `/boot/firmware/cmdline.txt` (or `/boot/cmdline.txt` if it does not exist):
+Add the following at the end (note the space)
+
+```
+cgroup_enable=memory cgroup_memory=1
+```
+
+After reboot, check `/proc/cgroups` to confirm memory controller `memory` is enabled.
diff --git a/content/docs/Hydro/plugins/index.en.mdx b/content/docs/Hydro/plugins/index.en.mdx
new file mode 100644
index 000000000..e8ed11d27
--- /dev/null
+++ b/content/docs/Hydro/plugins/index.en.mdx
@@ -0,0 +1,82 @@
+---
+title: Plugins
+---
+
+Hydro supports extending its functionality through plugins.
+
+
+Plugins have full access to all content on your site. Do not enable plugins from unknown sources.
+
+
+## Add-on List
+
+
+When installing with the installation script, the **bolded** plugins below are installed automatically.
+Some plugins (*italicized*) require third-party software. If you **only install the plugin without configuring/installing the third-party software**, the system may fail to run properly. See the plugin detail pages in the left sidebar for more information.
+
+
+Hydro officially provides the following add-ons:
+
+| ID | Description |
+|----------------------------|-----------------------------------------------|
+| **@hydrooj/a11y** | Some small utility features |
+| @hydrooj/onsite-toolkit | Onsite contest toolkit |
+| @hydrooj/blog | Blog functionality |
+| **@hydrooj/fps-importer** | Import problems in fps format |
+| *@hydrooj/geoip* | Display user login location (requires IP DB) |
+| **@hydrooj/hydrojudge** | Judging component |
+| @hydrooj/import-qduoj | Import problem sets exported from QDUOJ |
+| @hydrooj/import-hoj | Import problem sets exported from HOJ |
+| @hydrooj/login-with-github | Allow users to log in with GitHub |
+| @hydrooj/login-with-google | Allow users to log in with Google |
+| @hydrooj/migrate | Upgrade from vijos4/HustOJ/SYZOJ/UniversalOJ |
+| @hydrooj/recaptcha | Enable reCAPTCHA during registration |
+| **@hydrooj/ui-default** | Hydro's default user interface |
+| *@hydrooj/onlyoffice* | Display problems in doc/docx format |
+| *@hydrooj/sonic* | Sonic-based enhanced problem search (requires sonic) |
+| *@hydrooj/elastic-search* | Elastic-based enhanced problem search (requires Elastic) |
+| @hydrooj/vjudge | Codeforces/SPOJ/UOJ/POJ |
+| @hydrooj/prom-client | Export system status to Prometheus |
+
+Most plugin configurations can be found after installation in Control Panel > System Settings.
+
+Some plugins may affect normal system usage if installed but not properly configured!
+
+## Installation
+
+First install the required module globally, then register it with hydrooj. Example: installing @hydrooj/geoip
+
+```sh
+yarn global add @hydrooj/geoip
+hydrooj addon add @hydrooj/geoip
+```
+
+Or, if you are installing a plugin obtained through other means (such as one you created yourself), use the folder **absolute path** directly:
+(the folder path must be the one that **contains package.json**)
+
+```sh
+hydrooj addon add /root/xxx
+```
+
+Do not place plugins nested inside other plugin folders, or it may cause unpredictable issues.
+
+**After installing a plugin, you must restart hydrooj for it to take effect.**
+
+## View Registered Plugin List
+
+```sh
+hydrooj addon list
+```
+
+## Update
+
+```sh
+yarn global upgrade-interactive --latest
+```
+
+## Uninstall
+
+```sh
+yarn global remove @hydrooj/geoip
+hydrooj addon remove @hydrooj/geoip
+```
diff --git a/content/docs/Hydro/plugins/meta.en.json b/content/docs/Hydro/plugins/meta.en.json
new file mode 100644
index 000000000..02f5a4348
--- /dev/null
+++ b/content/docs/Hydro/plugins/meta.en.json
@@ -0,0 +1,15 @@
+{
+ "title": "Plugins",
+ "icon": "blocks",
+ "pages": [
+ "fps-importer",
+ "hydrojudge",
+ "migrate",
+ "elastic",
+ "recaptcha",
+ "sonic",
+ "vjudge",
+ "geoip",
+ "extra"
+ ]
+}
diff --git a/content/docs/Hydro/plugins/migrate.en.mdx b/content/docs/Hydro/plugins/migrate.en.mdx
new file mode 100644
index 000000000..99030a4fc
--- /dev/null
+++ b/content/docs/Hydro/plugins/migrate.en.mdx
@@ -0,0 +1,112 @@
+---
+title: migrate
+---
+
+## Upgrade from HUSTOJ
+
+
+If you are using the original version of HUSTOJ, it is recommended to follow these steps:
+
+1. Check and fix all invalid data (invalid dates / invalid email format / start time later than end time, etc.)
+2. It is recommended to create a server snapshot.
+3. Run the installation script directly on the machine where HUSTOJ is installed. The script will prompt you to import data.
+4. Check whether all data is normal. If everything is fine, you're done.
+5. If not, run `pm2 stop all && systemctl start nginx` to switch back to HUSTOJ and fix the data.
+6. Run `rm -rf /data ~/.hydro` and then rerun the installation script, returning to step 3.
+
+
+
+Migration will delete all current Hydro data (including user account information) and import HUSTOJ data.
+Please make sure to back up relevant files.
+
+
+Please complete Hydro deployment first and finish file service configuration (`setting_file`).
+Before migrating data, stop all running HUSTOJ services and keep only its database running.
+Note that the database used by Hydro must not be the same as the source HUSTOJ database.
+
+After installing the plugin, you should find a script named `migrateHustoj` in Control Panel > Script Management.
+Its parameter format is as follows:
+
+```json
+{"host":"localhost","port":3306,"name":"jol","username":"","password":"","domainId":"system","contestType":"","dataDir":"","uploadDir":""}
+```
+
+This information can usually be found in `/home/judge/src/web/include/db_info.inc.php`;
+
+- host: database host (`DB_HOST`)
+- port: database port (`DB_PORT`)
+- name: database name, usually `jol` (`DB_NAME`)
+- username&password: account/password, use empty strings if none (`DB_USER`/`DB_PASS`)
+- domainId: target domain for migration, default is `system`
+- contestType: `oi` or `acm`, depending on your setup (`OJ_OI_MODE`)
+- dataDir: location of the `data` folder in HUSTOJ (stores critical data such as problem test data; requires manual handling) (`OJ_DATA`)
+- uploadDir: location of uploaded files in HUSTOJ (stores uploaded images and files, usually `/home/judge/src/web/upload/`)
+
+After the script finishes, restart the Hydro instance to automatically complete the remaining upgrade steps.
+After migration, log in using the original HUSTOJ administrator account.
+
+
+## Upgrade from SYZOJ
+
+The migration process for SYZOJ is similar to HUSTOJ. Run the script named `migrateSyzoj`; unlike HUSTOJ migration, `contestType` is not required.
+Its parameter format is as follows:
+
+```json
+{"host":"localhost","port":3306,"name":"syzoj","username":"","password":"","domainId":"system","dataDir":""}
+```
+
+- host: database host
+- port: database port
+- name: database name, usually `syzoj`
+- username&password: account/password, use empty strings if none
+- domainId: target domain for migration, default is `system`
+- dataDir: location of the `data` folder in SYZOJ (stores critical data such as problem test data; requires manual handling)
+
+Since the SYZOJ script migrates all data from the original site, it may take a long time to run.
+After the script finishes, restart the Hydro instance to automatically complete the remaining upgrade steps.
+After migration, log in using the original SYZOJ administrator account.
+
+## Upgrade from UniversalOJ
+
+UniversalOJ (commonly called UOJ community edition) uses a migration process similar to the two above. Run the script named `migrateUniversalOJ`.
+
+Because its upgrade process is relatively complex, the installation script already provides automatic upgrade support. If needed, you can run the installation script for one-click migration. For manual migration, please ask in the developer group.
+
+Since the UniversalOJ script migrates all data from the original site, it may take a long time to run.
+After the script finishes, restart the Hydro instance to automatically complete the remaining upgrade steps.
+After migration, log in using the original UniversalOJ administrator account.
+
+## Upgrade from Vijos
+
+
+Migration will delete all current Hydro data (including user account information) and import vj4 data.
+Please make sure to back up relevant files.
+
+
+Please complete Hydro deployment first and finish file service configuration (`setting_file`).
+Before migrating data, stop all running vj4 services and keep only its database running.
+Note that the database used by Hydro must not be the same as the source vj4 database.
+If you are using vj4-docker, you can modify `docker-compose.yml` to map the database to a different local port.
+
+After installing the plugin, you should find a script named `migrateVijos` in Control Panel > Script Management.
+Its parameter format is as follows:
+
+```json
+{"host":"localhost","port":27017,"name":"vj4","username":"","password":""}
+```
+
+- host: database host
+- port: database port
+- name: database name
+- username&password: account/password, use empty strings if none
+
+
+In vj4-docker, the database name is vj4 with no account/password.
+
+
+After the script finishes, restart the Hydro instance to automatically complete the remaining upgrade steps.
+After migration, log in using the original vj4 administrator account.
+
+
+If your vj4 was upgraded from vj2 or tyvj, do not uninstall this plugin after migration, or some users may be unable to log in.
+
diff --git a/content/docs/Hydro/plugins/recaptcha.en.mdx b/content/docs/Hydro/plugins/recaptcha.en.mdx
new file mode 100644
index 000000000..042ef7170
--- /dev/null
+++ b/content/docs/Hydro/plugins/recaptcha.en.mdx
@@ -0,0 +1,12 @@
+---
+title: recaptcha
+---
+
+
+We use reCAPTCHA v3 to verify that registrants are human. It is normal not to see a traditional CAPTCHA during registration.
+
+
+Go to https://www.google.com/recaptcha/admin/create to create reCAPTCHA keys.
+For reCAPTCHA type, choose "reCAPTCHA v3".
+
+After creation, fill the site key and secret key into `key` and `secret` under the recaptcha section in System Settings respectively. Restart Hydro, and reCAPTCHA will work properly.
diff --git a/content/docs/Hydro/plugins/sonic.en.md b/content/docs/Hydro/plugins/sonic.en.md
new file mode 100644
index 000000000..84c23ae77
--- /dev/null
+++ b/content/docs/Hydro/plugins/sonic.en.md
@@ -0,0 +1,133 @@
+---
+title: Sonic
+---
+
+## Installation
+
+### Install [sonic-server](https://github.com/valeriansaliou/sonic)
+
+Run the following command as root:
+
+```bash
+nix-env -iA nixpkgs.sonic-server
+```
+
+### Install the sonic plugin
+
+Run the following commands as root:
+
+```bash
+yarn global add @hydrooj/sonic
+hydrooj addon add @hydrooj/sonic
+```
+
+## Start
+
+In `/root/.sonic/config.cfg` (create it if it does not exist, or use any other path you prefer), write the configuration according to the example below.
+
+Configuration example:
+
+```toml
+# Sonic
+# Fast, lightweight and schema-less search backend
+# Configuration file
+# Example: https://github.com/valeriansaliou/sonic/blob/master/config.cfg
+
+
+[server]
+
+log_level = "error"
+
+
+[channel]
+
+inet = "127.0.0.1:1491" # listens on localhost by default
+tcp_timeout = 300
+
+auth_password = "SecretPassword"
+
+[channel.search]
+
+query_limit_default = 10
+query_limit_maximum = 100
+query_alternates_try = 4
+
+suggest_limit_default = 5
+suggest_limit_maximum = 20
+
+
+[store]
+
+[store.kv]
+
+path = "/data/sonic/store/kv/"
+
+retain_word_objects = 1000
+
+[store.kv.pool]
+
+inactive_after = 1800
+
+[store.kv.database]
+
+flush_after = 900
+
+compress = true
+parallelism = 2
+max_files = 100
+max_compactions = 1
+max_flushes = 1
+write_buffer = 16384
+write_ahead_log = true
+
+[store.fst]
+
+path = "/data/sonic/store/fst/"
+
+[store.fst.pool]
+
+inactive_after = 300
+
+[store.fst.graph]
+
+consolidate_after = 180
+
+max_size = 2048
+max_words = 250000
+```
+
+Run the following commands:
+```
+pm2 start sonic -- -c /root/.sonic/config.cfg
+pm2 save
+```
+
+## Configuration
+
+### Backend address configuration
+
+Go to the HydroOJ control panel and configure the sonic backend address.
+
+If you copied the sample configuration directly, configure as follows:
+
+- host: `127.0.0.1`
+- port: `1491`
+- auth: `SecretPassword`
+
+After modification, restart HydroOJ.
+
+### Restart HydroOJ
+
+Run command `pm2 restart hydrooj`.
+
+### Rebuild problem index
+
+Go to the HydroOJ control panel, find Rebuild Problem Index in Script Management, click Run, and leave parameters empty.
+
+At this point, search should work properly.
+
+## FAQ
+
+### Problem search does not work correctly after installation
+
+Please update HydroOJ to the latest version, then run Rebuild Problem Index again.
diff --git a/content/docs/Hydro/plugins/vjudge.en.mdx b/content/docs/Hydro/plugins/vjudge.en.mdx
new file mode 100644
index 000000000..f29cbd146
--- /dev/null
+++ b/content/docs/Hydro/plugins/vjudge.en.mdx
@@ -0,0 +1,168 @@
+---
+title: VJudge
+---
+
+
+Codeforces recently updated its firewall rules. Submissions from the current open-source VJudge are blocked by the firewall and cannot be used directly; you will need to modify the source code yourself.
+At the same time, a per-account daily submission limit has been added. Unless you have specific requirements, we recommend disabling Codeforces VJudge.
+
+This document is outdated and kept only for archival purposes. The tutorial below is intended only as an example. For detailed installation instructions, please refer to the **FAQs (Common Tutorials)** for specific usage guidance.
+
+Some supported remote sites impose limits on submission count, access frequency, and request origin. Hydro does not guarantee 100% availability of VJudge.
+
+
+## Codeforces
+
+After installing the plugin, create a domain named `codeforces`, then enter the database command: `db.domain.updateOne({_id:'codeforces'},{$set:{mount:'codeforces'}});`
+
+In the `codeforces` domain settings, configure `allowedLangs` as follows (in newer versions, simply select all languages prefixed with `codeforces` in the allowed submission languages):
+
+```
+codeforces,codeforces.43,codeforces.52,codeforces.50,codeforces.54,codeforces.59,codeforces.61,codeforces.65,codeforces.9,codeforces.28,codeforces.32,codeforces.12,codeforces.60,codeforces.36,codeforces.48,codeforces.19,codeforces.3,codeforces.4,codeforces.51,codeforces.13,codeforces.6,codeforces.7,codeforces.31,codeforces.40,codeforces.41,codeforces.67,codeforces.49,codeforces.20,codeforces.34,codeforces.55
+```
+
+Insert the following entry into the `vjudge` table:
+
+```js
+{type:'codeforces', handle:'', password:''}
+```
+
+Add the following configuration to the end of the `langs` settings:
+
+```yaml
+codeforces:
+ execute: none
+ display: Codeforces
+ domain:
+ - codeforces # Allow domain 'codeforces' to use these languages
+codeforces.43:
+ highlight: cpp astyle-c
+ monaco: cpp
+ display: GNU GCC C11 5.1.0
+ comment: //
+codeforces.52:
+ highlight: cpp astyle-c
+ monaco: cpp
+ display: Clang++17 Diagnostics
+ comment: //
+codeforces.50:
+ highlight: cpp astyle-c
+ monaco: cpp
+ display: GNU G++14 6.4.0
+ comment: //
+codeforces.54:
+ highlight: cpp astyle-c
+ monaco: cpp
+ display: GNU G++17 7.3.0
+ comment: //
+codeforces.59:
+ highlight: cpp astyle-c
+ monaco: cpp
+ display: Microsoft Visual C++ 2017
+ comment: //
+codeforces.61:
+ highlight: cpp astyle-c
+ monaco: cpp
+ display: GNU G++17 9.2.0 (64 bit, msys 2)
+ comment: //
+codeforces.65:
+ highlight: cpp astyle-cs
+ monaco: csharp
+ display: C# 8, .NET Core 3.1
+ comment: //
+codeforces.9:
+ highlight: cpp astyle-cs
+ monaco: csharp
+ display: C# Mono 6.8
+ comment: //
+codeforces.28:
+ highlight: d
+ monaco: plain
+ display: D DMD32 v2.091.0
+ comment: //
+codeforces.32:
+ highlight: go
+ display: Go 1.15.6
+ comment: //
+codeforces.12:
+ highlight: haskell
+ display: Haskell GHC 8.10.1
+ comment: --
+codeforces.60:
+ highlight: java astyle-java
+ monaco: java
+ display: Java 11.0.6
+ comment: //
+codeforces.36:
+ highlight: java astyle-java
+ monaco: java
+ display: Java 1.8.0_241
+ comment: //
+codeforces.48:
+ highlight: kotlin
+ display: Kotlin 1.4.0
+ comment: //
+codeforces.19:
+ highlight: ocaml
+ monaco: plain
+ display: OCaml 4.02.1
+ comment: ['(*','*)']
+codeforces.3:
+ highlight: pascal
+ display: Delphi 7
+ comment: //
+codeforces.4:
+ highlight: pascal
+ display: Free Pascal 3.0.2
+ comment: //
+codeforces.51:
+ highlight: pascal
+ display: PascalABC.NET 3.4.2
+ comment: //
+codeforces.13:
+ highlight: perl
+ display: Perl 5.20.1
+ comment: '#'
+codeforces.6:
+ highlight: php
+ display: PHP 7.2.13
+ comment: //
+codeforces.7:
+ highlight: python
+ display: Python 2.7.18
+ comment: '#'
+codeforces.31:
+ highlight: python
+ display: Python 3.9.1
+ comment: '#'
+codeforces.40:
+ highlight: python
+ display: PyPy 2.7 (7.3.0)
+ comment: '#'
+codeforces.41:
+ highlight: python
+ display: PyPy 3.7 (7.3.0)
+ comment: '#'
+codeforces.67:
+ highlight: ruby
+ display: Ruby 3.0.0
+ comment: '#'
+codeforces.49:
+ highlight: rust
+ display: Rust 1.49.0
+ comment: //
+codeforces.20:
+ highlight: scala
+ display: Scala 2.12.8
+ comment: //
+codeforces.34:
+ highlight: javascript
+ display: JavaScript V8 4.8.0
+ comment: //
+codeforces.55:
+ highlight: javascript
+ display: Node.js 12.6.3
+ comment: //
+```
+
+After that, restart Hydro.
diff --git a/content/docs/Hydro/system/cdn.en.mdx b/content/docs/Hydro/system/cdn.en.mdx
new file mode 100644
index 000000000..8340449d9
--- /dev/null
+++ b/content/docs/Hydro/system/cdn.en.mdx
@@ -0,0 +1,43 @@
+---
+title: Use a Content Delivery Network
+---
+
+## Overview
+
+Using a Content Delivery Network (CDN) can significantly improve the performance and accessibility of your Hydro instance, especially if your server has limited bandwidth. In most cases, configuring a **Static Resource CDN** provides the best balance of performance gains and ease of setup.
+
+## Static Resource CDN
+
+To offload static assets (images, scripts, styles) to a CDN:
+1. Create a CDN distribution with your cloud provider.
+2. Set the CDN origin to your Hydro server's address.
+3. In the Hydro Control Panel, set `server.cdn` to your CDN domain (e.g., `https://cdn.example.com/`). **Ensure it ends with a trailing slash.**
+4. **Caching Configuration**:
+ - Recommended cache duration: 1 week or longer.
+ - **CORS/Referer**: Ensure the CDN allows Cross-Origin Resource Sharing (CORS) and permits requests with an empty Referer (common for anti-leech settings).
+
+## Full-Site CDN (Acceleration)
+
+A full-site CDN proxies all traffic, including dynamic pages.
+
+
+Full-site CDN configuration is complex and varies significantly between providers. If you are inexperienced, we recommend using only a **Static Resource CDN**.
+
+
+
+**Critical Requirements for Full-Site CDNs:**
+- **WebSocket Support**: You **must** enable WebSocket support in your CDN settings. Without it, real-time features like judging status updates and the Online IDE will fail.
+- **Dynamic Content Caching**: Ensure that **only** static assets are cached. Caching dynamic pages (like login or profile pages) will lead to session inconsistencies and security issues.
+
+
+### Recommended Cache Settings:
+| Type | Content | Cache Behavior |
+| :--- | :--- | :--- |
+| Dynamic | All other files | Follow Origin (No Cache) |
+| Static | `.jpg, .js, .png, .css, .gif` | Cache (e.g., 1 day) |
+
+### IP Forwarding:
+To ensure Hydro can identify the real user IP instead of the CDN's IP:
+1. Configure your CDN to include the client's original IP in the `X-Forwarded-For` header.
+2. In Hydro System Settings, set `server.xff` to `x-forwarded-for` (case-insensitive).
+
diff --git a/content/docs/Hydro/system/cli.en.mdx b/content/docs/Hydro/system/cli.en.mdx
new file mode 100644
index 000000000..6d7c0a5b8
--- /dev/null
+++ b/content/docs/Hydro/system/cli.en.mdx
@@ -0,0 +1,104 @@
+---
+title: Hydro CLI
+---
+
+
+Before using the CLI, please complete the database configuration.
+Parameters wrapped in `<>` are required, and parameters wrapped in `[]` are optional. If omitted, default settings are used.
+**Please replace all parts wrapped in `<>` or `[]` according to your specific situation (including the brackets).**
+
+
+The CLI helps users quickly perform some operations in the console.
+These commands need to be executed in the terminal as the root user (in the location where the installation command was executed).
+Some commonly used examples are provided below.
+
+## Create a User
+
+
+Rarely used. We recommend using the Control Panel > Import Users feature instead.
+
+
+```sh
+hydrooj cli user create
+# The email, username, and password for this user
+
+# For example, to create a user with email hydro@hydro.local, username Hydro, password hydrohydro, and UID 2:
+# Please ensure the UID is a positive integer not less than 2 and is not occupied, and that both the email and username are unique.
+hydrooj cli user create hydro@hydro.local Hydro hydrohydro 2
+```
+
+If everything is normal, you will see the user's uid in the command line window after running this command.
+
+## Set Site Super Admin
+
+```sh
+hydrooj cli user setSuperAdmin
+
+# For example, to set the user with uid 2 as an admin:
+hydrooj cli user setSuperAdmin 2
+```
+
+## Set User Privilege
+
+```sh
+hydrooj cli user setPriv
+```
+
+For information about the `[priv]` parameter, you can read [here](../dev/PERM_PRIV/).
+
+## Change User Password
+
+```sh
+hydrooj cli user setPassword
+
+# For example, to change the password of the user with uid 1 to hydrohydro:
+hydrooj cli user setPassword 1 hydrohydro
+```
+
+## Create a Judge Account
+
+First, [create an account](#create-a-user).
+
+You need to pay attention to the number returned by running this command, which indicates the user's `uid`. You need to fill it in the command below, and then grant judging privileges to that account.
+
+```sh
+hydrooj cli user setJudge
+```
+
+Once completed, write the configured username and password into the judge machine configuration file, and the judge machine will be able to connect to the web side.
+
+## Blacklist Related
+
+Ban a user:
+
+```sh
+hydrooj cli user setPriv 0
+```
+
+IP/Email domain ban:
+
+```sh
+# The key format is ip::xxx.xxx.xxx.xxx (bans IP access) or mail::xxx.com (forbids registration with xxx.com emails)
+hydrooj cli blacklist add [duration] # Add to the blacklist for a duration of [duration] (an integer in months, defaults to 12; if duration=0, it's a permanent ban)
+hydrooj cli blacklist get # Get information about in the blacklist
+hydrooj cli blacklist del # Remove from the blacklist
+```
+
+## Command List
+
+All functions located in [this folder](https://github.com/hydro-dev/Hydro/tree/master/packages/hydrooj/src/model) can be called using the CLI.
+
+Not all runnable commands are listed here, because for many features, we recommend accessing them via the Web.
+
+```sh
+hydrooj cli user create [uid] [regip] [priv]
+# Create a user with email , username , password , ID [uid], registration IP [regip], and privilege [priv]
+hydrooj cli user setUname # Set the username of the user with ID to
+hydrooj cli user setPriv # Set the privilege of the user with ID to
+hydrooj cli user setPassword # Set the password of the user with ID to
+hydrooj cli user setEmail # Set the email of the user with ID to
+hydrooj cli user setSuperAdmin # Set the user with ID as the site super admin
+hydrooj cli problem import # Import the Hydro format problem package from into the domain
+hydrooj cli problem export # Export all problem packages in the domain
+hydrooj cli system set # Modify the value of the system setting to
+```
\ No newline at end of file
diff --git a/content/docs/Hydro/system/database.en.mdx b/content/docs/Hydro/system/database.en.mdx
new file mode 100644
index 000000000..f9fa4c061
--- /dev/null
+++ b/content/docs/Hydro/system/database.en.mdx
@@ -0,0 +1,52 @@
+---
+title: Database Backup and Restore
+---
+
+## Overview
+
+Hydro uses MongoDB as its primary data store.
+
+
+### Direct Database Access Warning
+**Modifying the database directly is strongly discouraged.**
+1. **Relational Integrity**: Modifying a field in one table may break references in others. This can lead to unpredictable system failures.
+2. **Caching**: Changes made directly to the database may not be recognized by Hydro's caching mechanism, making them appear ineffective.
+3. **Privilege Risk**: Direct database operations are highly privileged. A single mistake can lead to catastrophic data loss.
+
+
+If a direct query is absolutely necessary, use the `hydrooj db` command to open the database shell or retrieve the connection string from `~/.hydro/config.json`.
+
+*Note: Ensure your MongoDB client is configured with the correct `authSource` (typically `admin` or `hydro`).*
+
+## Backup and Restore
+
+To ensure data integrity, we recommend scheduling regular backups.
+
+### Automated Backups
+If you installed Hydro using the automated script, use the following commands:
+- **Backup**: `hydrooj backup`
+ - This generates a `.zip` archive in your current directory containing both the database and files.
+ - Parameters: `--dbOnly` (Database only), `--withAddons`, `--withLogs`.
+- **Restore**: `hydrooj restore `
+
+### Incremental Backups (Hydro 5.0.0+)
+Hydro supports incremental backups via **Restic**.
+1. Initialize a repository: `restic init`
+2. Run backup: `hydrooj backup -r -p `
+
+### Manual Backups
+If you prefer standard tools:
+1. Use `mongodump` for the database.
+2. Back up the `/data/file` directory for test data and attachments.
+
+**Best Practices:**
+- **Never** copy the database directory while MongoDB is running.
+- **Verification**: Regularly verify the size and contents of your backup files.
+- **Off-Site Storage**: Always store backups on a different machine or cloud storage to mitigate hardware failure risks.
+
+## Manual Restore
+1. Use `mongorestore` to import the database data.
+2. Restore the contents of `/data/file` to the corresponding path on your new server.
+
+{/* It actually works, but most people are not doing it right, so it's better to hide this instruction */}
+{/* If you only want to migrate deployment between machines, simply copy related folders (usually `/data/db`, `/data/file`, and `/root/.hydro/config.json`) **after stopping Hydro and MongoDB services**. */}
diff --git a/content/docs/Hydro/system/frontend-modify.en.mdx b/content/docs/Hydro/system/frontend-modify.en.mdx
new file mode 100644
index 000000000..7dfacd64f
--- /dev/null
+++ b/content/docs/Hydro/system/frontend-modify.en.mdx
@@ -0,0 +1,31 @@
+---
+title: Frontend Modification
+---
+
+This guide teaches you how to modify frontend files.
+
+If you are using developer mode, directly modify files under `packages/ui-default/templates`.
+
+If you deployed using the installation script:
+
+First run `hydrooj addon create` to create a local addon (if you have not done this before).
+
+## Modify page translations or add a new language:
+
+- Modify translations: search the translation you want to change in [zh.yaml](https://github.com/hydro-dev/Hydro/blob/master/packages/ui-default/locales/zh.yaml), then add **only that line, not the whole file** after editing into `~/addon/locales/zh.yaml`.
+- Add a language: create a new file using [zh.yaml](https://github.com/hydro-dev/Hydro/blob/master/packages/ui-default/locales/zh.yaml) as reference format. Community contributions to multilingual translations are welcome.
+
+## Modify page templates:
+
+Usually, add `view-source:` before the URL you visit (for example, `view-source:https://hydro.ac`) to view source code. In line 2, `` contains `data-page`, which is the page name (except homepage, which is `main.html`).
+Find the corresponding file in [default templates](https://github.com/hydro-dev/Hydro/tree/master/packages/ui-default/templates), copy the **entire file content** to `~/addon/templates/`, then modify it.
+
+
+Template modification may cause feature issues after system upgrades. For better compatibility, we recommend using addon frontend features to dynamically inject/modify elements, instead of replacing entire templates.
+
+For more details, see [Plugin Development](../dev/typescript).
+
+
+In particular, the default template for creating problems is at `partials/problem_default.md`, and for creating training plans at `partials/training_default.json`; modify them the same way.
+
+All changes above take effect after restarting Hydro.
diff --git a/content/docs/Hydro/system/import-user.en.mdx b/content/docs/Hydro/system/import-user.en.mdx
new file mode 100644
index 000000000..bdc8b853f
--- /dev/null
+++ b/content/docs/Hydro/system/import-user.en.mdx
@@ -0,0 +1,27 @@
+---
+title: Import Users
+---
+
+Currently supports importing user data in CSV format (separated by `,`) or Excel format (TAB-separated). Data can be created with a text editor or with tools like Excel.
+
+Each line must contain at least 3 columns and at most 5 columns: email, username, password, display name, user profile. (Display name and user profile are optional.)
+Please use UTF-8 encoding, otherwise Chinese text may become garbled.
+If you use CSV format (comma-separated), the user profile column is unavailable.
+
+```text
+foo@undefined.moe user1 password1
+bar@undefined.moe user2 password2 temp
+test@undefined.moe user3 password3 test {"group":"class1","studentId":"123","school":"Hydro School"}
+```
+
+After pasting, you can click Preview to validate the imported data.
+
+This will create three users:
+
+- `user1` with password `password1`, email `foo@undefined.moe`;
+- `user2` with password `password2`, email `bar@undefined.moe`, display name `temp`;
+- `user3` with password `password3`, email `test@undefined.moe`, display name `test`, school `Hydro School`, student ID `123`; this user will be assigned to group `class1` in the current Domain;
+
+
+Users cannot be deleted after creation. Please proceed carefully.
+
diff --git a/content/docs/Hydro/system/maintain.en.md b/content/docs/Hydro/system/maintain.en.md
new file mode 100644
index 000000000..b2f602a99
--- /dev/null
+++ b/content/docs/Hydro/system/maintain.en.md
@@ -0,0 +1,61 @@
+---
+title: Maintenance
+---
+
+## Process Management (PM2)
+
+Hydro's automated installation script uses **PM2** to manage system processes.
+
+### Core Processes
+You can view active processes by running `pm2 ls`. A typical Hydro installation includes:
+- `hydrooj`: The main web application.
+- `hydro-sandbox`: The judge sandbox component.
+- `mongodb`: The database engine.
+- `caddy`: The reverse proxy and SSL manager.
+
+### Standard Commands
+Use `` or `` from the process list as a parameter (e.g., `pm2 restart hydrooj` or `pm2 restart 0`).
+
+```bash
+pm2 ls # List all processes
+pm2 start # Start a process
+pm2 stop # Stop a process
+pm2 restart # Restart a process
+pm2 logs --lines 100 # View the last 100 log entries
+pm2 save # Save current process list for auto-boot
+pm2 resurrect # Manually restore a saved process list
+```
+
+
+### Performance Notes
+- **LXC/Minimal Systems**: In some environments, Hydro may not auto-start after a server reboot. If this occurs, use `pm2 resurrect` to restore your processes.
+- **Service Recovery**: If your process list becomes corrupt, run `pm2 stop all && pm2 del all`, then rerun the automated installation script. **Existing data will not be lost.**
+- **Multi-Process Mode**: While Hydro supports clustering (`-i `), this is generally unnecessary for servers with 4 or fewer cores and will significantly increase memory consumption.
+
+
+## Software Updates
+
+Hydro releases regular updates. To upgrade your instance:
+
+```bash
+# Update Hydro and its core components
+yarn global upgrade-interactive --latest
+
+# Apply the updates by restarting the service
+pm2 restart hydrooj
+```
+
+**Warning**: Do **not** upgrade PM2 itself unless specifically instructed, as this may clear your saved process configuration.
+
+### Version Checking
+To check your currently installed Hydro version:
+```bash
+cd $(yarn global dir) && yarn list --pattern hydrooj
+```
+
+### System Cleanup
+To free up disk space from package caches:
+```bash
+yarn cache clean && nix-collect-garbage
+```
+
diff --git a/content/docs/Hydro/system/meta.en.json b/content/docs/Hydro/system/meta.en.json
new file mode 100644
index 000000000..ce4cae2c7
--- /dev/null
+++ b/content/docs/Hydro/system/meta.en.json
@@ -0,0 +1,14 @@
+{
+ "title": "System Documentation",
+ "description": "System Documentation",
+ "pages": [
+ "maintain",
+ "cli",
+ "import-user",
+ "cdn",
+ "database",
+ "frontend-modify",
+ "onsite-contest",
+ "FAQ"
+ ]
+}
diff --git a/content/docs/Hydro/system/onsite-contest.en.md b/content/docs/Hydro/system/onsite-contest.en.md
new file mode 100644
index 000000000..c029650c5
--- /dev/null
+++ b/content/docs/Hydro/system/onsite-contest.en.md
@@ -0,0 +1,37 @@
+---
+title: Onsite Contest Guide
+---
+
+## External Scoreboard (Public View)
+
+For XCPC rules, you can publish a public-facing scoreboard by installing the `@hydrooj/scoreboard-xcpcio` plugin.
+
+### Configuration:
+In the Control Panel, locate the `scoreboard-xcpcio.publish` settings:
+- **`domainId` / `contestId`**: Specify the contest you wish to export.
+- **`publishToken`**: A secret string to prevent unauthorized overwrites.
+- **`publishPath`**: The URL slug for your scoreboard (alphanumeric only).
+- **`publishEndpoint`**: Set to `https://scoreboard.hydrooj.com/_publish`.
+
+Restart your server after configuration. The live scoreboard will be synchronized to `https://scoreboard.hydrooj.com/`.
+
+## Resolver Playback (Final Reveal)
+
+To perform a "reveal" or "playback" of the contest results:
+1. Install the `@hydrooj/onsite-toolkit` plugin.
+2. Export the contest's CDP package and extract it on your local machine.
+3. Open [resolver.hydrooj.com](https://resolver.hydrooj.com).
+4. Select the directory containing the extracted `.ndjson` files.
+5. In the settings, disable **JudgingQueue** and **School Badge Display**, and enable **User Avatar Display**.
+
+### Controls:
+- **Step (Single Action)**: Left Mouse Button / Right Arrow / Down Arrow / Space.
+- **Auto (Automatic Reveal)**: `A`
+- **Speed Up / Slow Down**: `[` and `]`
+- **Fast Forward**: `Ctrl + Right Arrow`
+- **Restart**: `R`
+
+## Logistics: Team PCs, Balloons, and Printing
+
+For a comprehensive suite of contest tools, see the [XCPC-Tools](../../Tools) documentation.
+
diff --git a/content/docs/Hydro/system/onsite-contest.md b/content/docs/Hydro/system/onsite-contest.md
index e7a5a214d..28d47a105 100644
--- a/content/docs/Hydro/system/onsite-contest.md
+++ b/content/docs/Hydro/system/onsite-contest.md
@@ -22,4 +22,4 @@ publishEndpoint 填写 `https://scoreboard.hydrooj.com/_publish`,设置完成
## 选手机,气球,打印
-参照 [XCPC-Tools](/docs/Tools)
+参照 [XCPC-Tools](../../Tools)
diff --git a/content/docs/Hydro/user/copy-problem.en.md b/content/docs/Hydro/user/copy-problem.en.md
new file mode 100644
index 000000000..69c00c498
--- /dev/null
+++ b/content/docs/Hydro/user/copy-problem.en.md
@@ -0,0 +1,18 @@
+---
+title: Copy Problem
+---
+
+Copying problems lets users copy any problem they are allowed to submit to into a Domain where they have problem-creation permission, so the problem can be used in contests/homework/training plans.
+
+## Workflow
+
+1. Open the problem page or problem list page of the problem you want to copy.
+2. Click the "Copy" button at the bottom of the right sidebar, or select multiple problems and click the copy button on the right.
+3. In the popup window, enter the ID of the target Domain.
+4. Click "Confirm" and it will automatically redirect to the copied problem link.
+
+## **Limits**
+
+- Viewing/modifying test data of the copied problem is not allowed.
+- You cannot copy a problem that was itself copied.
+- Some problems may not allow copying. This follows the admin setting in Domain Settings > Edit Domain Profile.
diff --git a/content/docs/Hydro/user/domain.en.mdx b/content/docs/Hydro/user/domain.en.mdx
new file mode 100644
index 000000000..e28ae9ecb
--- /dev/null
+++ b/content/docs/Hydro/user/domain.en.mdx
@@ -0,0 +1,94 @@
+---
+title: Domain
+---
+
+## Overview
+
+The **Domain** feature functions similarly to "Teams" or "Groups," allowing multiple isolated environments (e.g., different classes, clubs, or organizations) within a single Hydro instance.
+
+Users with the `PRIV_CREATE_DOMAIN` permission (granted to admins by default) can create new domains. Data is fully isolated between domains, though user account credentials are shared across the entire instance.
+
+## Creating a Domain
+
+1. Log in and navigate to the **"My"** tab.
+2. Find **"My Domains"** and click **"Create Domain"**.
+3. Fill in the following details:
+ - **ID**: A unique identifier used in the domain's URL. **Note: This cannot be changed after creation.**
+ - **Name**: The display name of the domain.
+ - **Announcement**: Content shown on the domain's homepage.
+ - **Avatar**: The domain's icon. Supports `gravatar:email`, `qq:id`, `github:name`, or a direct `url:link`.
+
+Once created, you will have administrative privileges within that domain, allowing you to manage problems, contests, and users.
+
+## Initializing Discussion Nodes
+
+In the **"Manage Domain"** tab, click **"Initialize Discussion Nodes"** to set up the default forum structure for your domain.
+
+## Access Control
+
+### Hydro v5 and Later
+
+In Hydro v5, access is managed through two primary roles:
+- **Guest**: The default role for non-logged-in users or users who have not yet joined the domain.
+- **Default**: The standard role for members who have joined the domain.
+
+**Key Features:**
+- **Self-Service Joining**: Admins can enable "Allow users to join domain" in the domain settings.
+- **Rankings**: Only users who have joined the domain will appear on its ranking list.
+- **Manual Assignment**: If an admin manually assigns a role other than `guest` or `default` to a user, that user will automatically join the domain with the assigned role.
+- **Blocking**: Explicitly setting a user's role to `guest` prevents them from re-joining via self-service.
+- **Leaving**: Users can leave a domain voluntarily (unless it is the `system` domain) or be removed by an admin, which resets their role to `guest`.
+
+**v4 to v5 Migration:**
+During the upgrade, Hydro automatically:
+1. Marks all existing users in a domain as "joined."
+2. Enables self-service joining (assigning the `default` role) for domains that previously had no join conditions.
+
+### Hydro v4
+
+In v4, non-logged-in users are `guest` and logged-in users are `default` by default. Setting a user's role to `default` is equivalent to removing them from the domain's specific member list.
+
+## Creating Contests and Homework
+
+To create a contest or homework assignment:
+1. Navigate to the **"Contest"** or **"Homework"** tab.
+2. Click **"Create"** on the right sidebar.
+3. Use the search/filter feature to add problems by ID or title.
+
+
+If a contest or homework becomes inaccessible (e.g., due to deleted problems), you can force-access the edit page by appending `/edit` to the URL (e.g., `/contest//edit`).
+
+
+## Creating Training Plans
+
+Training plans allow you to group problems into structured paths. To create one:
+1. In the **"Training"** tab, click **"Create Training Plan"**.
+2. Fill in the **Title**, **Summary**, and **Description**.
+3. Configure the **Plan** using the following JSON-like format:
+
+```json
+[
+ {
+ "_id": 1,
+ "title": "Getting Started",
+ "requireNids": [],
+ "pids": [1001, 1002]
+ },
+ {
+ "_id": 2,
+ "title": "Advanced Topics",
+ "requireNids": [1],
+ "pids": [1003]
+ }
+]
+```
+
+- `_id`: Numeric identifier for the section.
+- `title`: Section name.
+- `requireNids`: Array of section IDs that must be completed first.
+- `pids`: Array of problem IDs included in this section.
+
+
+If a training plan becomes inaccessible, append `/edit` to the URL (e.g., `/training//edit`) to fix the configuration.
+
+
diff --git a/content/docs/Hydro/user/index.en.md b/content/docs/Hydro/user/index.en.md
new file mode 100644
index 000000000..4a65c6031
--- /dev/null
+++ b/content/docs/Hydro/user/index.en.md
@@ -0,0 +1,37 @@
+---
+title: User Documentation
+---
+
+## Problem Difficulty
+
+In Hydro, problem difficulty is calculated by an algorithm based on submission count, acceptance rate, and the submission time and judging result of each submission.
+
+1. In general, the larger the value, the harder the problem.
+2. Difficulty for new problems may be inaccurate; it becomes more reliable after enough submissions are collected.
+3. Earlier submissions have a larger impact on the calculated difficulty.
+4. Difficulty is algorithm-based, so inaccurate results are still possible.
+
+## Participate in Contests
+
+You can click the "Participate" button on the contest details page to join.
+During the contest, the "Scoreboard" displays ranking according to contest rules.
+After the contest ends, you can still practice problems in the contest, but the "Scoreboard" will stop updating.
+
+## Post Discussions
+
+If you want to post a discussion, **please enter a discussion node first**, then click "Create a discussion" and fill in:
+
+- Title;
+- Content;
+- Highlight: if enabled, a prominent red line appears on the left side of the post (requires "Highlight Discussion" permission);
+- Pin: whether to pin the discussion (requires "Pin Discussion" permission).
+
+Then click "Create" to publish.
+
+## Claim Homework
+
+On the homework details page, you can click "Claim Homework".
+Before homework starts, you cannot view the problems in it.
+During the homework period, your progress and others' progress are counted in real time on the "Scoreboard".
+After homework enters the extension period, you can still submit, but scoreboard scores are converted by percentage according to extension penalty rules.
+After the homework deadline, you can still practice problems, but the "Scoreboard" will stop updating.
diff --git a/content/docs/Hydro/user/meta.en.json b/content/docs/Hydro/user/meta.en.json
new file mode 100644
index 000000000..6d8320416
--- /dev/null
+++ b/content/docs/Hydro/user/meta.en.json
@@ -0,0 +1,12 @@
+{
+ "title": "User Guide",
+ "description": "User Guide",
+ "pages": [
+ "domain",
+ "permission",
+ "problem",
+ "testdata",
+ "problem-format",
+ "copy-problem"
+ ]
+}
diff --git a/content/docs/Hydro/user/permission.en.md b/content/docs/Hydro/user/permission.en.md
new file mode 100644
index 000000000..c6050a227
--- /dev/null
+++ b/content/docs/Hydro/user/permission.en.md
@@ -0,0 +1,48 @@
+---
+title: Permission System
+---
+
+Hydro's permission system uses a two-layer structure: Privilege (PRIV) and Permission (PERM).
+Permissions are represented internally with bit operations. Definitions and values can be found in the [source code](https://github.com/hydro-dev/Hydro/blob/master/packages/common/permission.ts).
+
+## Privilege
+
+Privilege refers to permissions a user has across the whole system, effective in all Domains, such as creating users, editing system settings, creating Domains, viewing Domains, etc.
+
+Specifically, `PRIV.PRIV_USER_PROFILE` controls whether an account can log in as a normal account. Without this privilege, the account cannot log in (banned).
+
+Common needs:
+
+ - If you do not want regular users to upload files, disable `PRIV_CREATE_FILE` for the default role
+ - If you need to disable site messages, disable `PRIV_SEND_MESSAGE`
+
+## Permission
+
+Permission refers to permissions a user has within a single Domain, such as creating problems/contests, posting/deleting discussions, etc.
+
+If `PERM.PERM_VIEW` is disabled, that user cannot view this Domain.
+
+## Roles
+
+Usually we need to assign the same permissions to a specific group of users. With many users, this becomes chaotic and hard to manage, so we designed **roles** for batch operations and management.
+Roles are for Domain-level permissions (PERM). Three built-in roles are provided:
+
+- guest (applies to non-logged-in users, including banned users)
+- default (applies to all users without an assigned role, including users not joined to the Domain)
+- root (has all permissions)
+
+Normally, if you need special Domain permission control, you should create a new role (for example, member) and assign selected users to it.
+Removing a role assignment from a user in a Domain is equivalent to setting that user's role to default.
+If needed, you can also create other roles such as teacher or admin.
+Because there may be many users in the system (tens of thousands or even hundreds of thousands), only users whose role is not default are shown in the user list.
+
+## Join Domain
+
+### Hydro v5
+
+See the explanation in the Domain section.
+
+### Hydro v4
+
+The process of joining a Domain is essentially the process where **a user self-serves their own role from default to another role (such as member)** through some method.
+So choosing guest or default as the role in a join-domain invitation link is meaningless.
diff --git a/content/docs/Hydro/user/problem-create.en.md b/content/docs/Hydro/user/problem-create.en.md
new file mode 100644
index 000000000..e3bb98f70
--- /dev/null
+++ b/content/docs/Hydro/user/problem-create.en.md
@@ -0,0 +1,421 @@
+---
+title: Notes on Creating Common Hydro Problem Types
+---
+
+Author: laomai
+qq: 29985091
+Website: http://82.157.98.222:8888/
+Date: 2022/03/16
+
+This article records the author's practical experiments while using Hydro, and I hope it helps everyone. It includes the following content:
+
+0. Hydro problem storage format
+1. Creating the simplest OJ problem
+2. OJ problems with custom header files (function-interactive problems)
+3. Semi-automatic checker problems (no need to input expected output manually)
+4. Fully checker-based problems (no need to input input/output data manually)
+5. Specifying input and output files
+6. Multiple subtasks
+7. Objective problems (fill-in-the-blank and multiple-choice with standard answers)
+
+## 0. Hydro problem storage format
+
+If you want to prepare problems locally and then upload them in batches, the format below should help.
+Each problem should use its own directory, with the directory name as the problem number such as 1, 2, 3, 4, etc.
+Each problem directory usually contains the following:
+`problem_zh.md` This file is the problem content, i.e., problem statement, in markdown format.
+`problem.yaml` file. This is the problem configuration information, such as title and tags.
+`testdata` subdirectory, corresponding to files in the test data section on the website.
+It must contain at least one `config.yaml` file to describe judge type; see examples below for details.
+If a problem has test cases, each case should provide at least one `.in` file and one output file (some test types do not require this; see details below).
+`additional_file` subdirectory stores extra files for contestants, such as header files, images, PDF documents, etc. In the problem markdown document, you can provide download links like this: `[text](file://xxx.txt)`
+
+Below are the manual steps for entering various problem types, i.e., operations after logging in and clicking create problem, as shown below:
+
+
+Assume all problem statements use the markdown document below:
+
+ # 要求
+
+ 输入两个整数,输出他们的和
+
+ # 样例
+
+ ```input1
+ 123 500
+ ```
+
+ ```output1
+ 623
+ ```
+
+## 1. Create the simplest OJ problem
+
+Problem URL: http://82.157.98.222:8888/p/P10000
+
+1. After creating a new problem, edit the statement content, enter problem ID and title, then click Create, as shown below.
+2. You will then see the interface below. Click Create File, with filename `1.in`, representing input for case 1.
+3. Edit `1.in` content as two integers, e.g., 2 and 3, separated by space, as shown below, then click Confirm.
+4. Similarly create a `1.out` file with content 5. Note the numeric index must match the `.in` file. The created file list should look like this.
+
+
+
+5. Now input and expected output for the first case are ready, and the problem can be solved.
+6. AC code for this problem:
+
+```cpp
+#include
+using namespace std;
+int main(int argc,char* argv[]){
+ int a,b;
+ cin>>a>>b;
+ cout <<(a+b);
+ return 0;
+}
+```
+
+## 2. Function-interactive problems
+
+Problem URL: http://82.157.98.222:8888/p/P10001
+The difference from type 1 is that the problem setter provides an extra header file to contestants. Contestants can include this header in their main function to call provided functions, or implement functions declared in the header.
+
+1. Statement input and test data input are the same as type 1.
+2. This problem additionally uploads two files: `tools.h` and `config.yaml`, as shown below.
+
+
+
+`tools.h` content:
+
+```cpp
+#include
+using namespace std;
+
+int add(int x,int y); //留待做题者实现
+
+int main(int argc,char* argv[]){
+ int a,b;
+ cin>>a>>b;
+ cout << add(a,b);
+ return 0;
+}
+```
+
+This header implements a main function and declares function `add` to be implemented by contestants. Of course, the problem setter should state the function signature in requirements and upload `tools.h` to the additional file list for contestant convenience.
+In the statement, you can provide a download link in this format, and customize the text in brackets: `[tools.h](file://tools.h)`, as shown below.
+
+
+
+
+
+`config.yaml` content:
+```yaml
+type: default
+filename: null
+user_extra_files:
+ - tools.h
+```
+
+AC code for this problem:
+
+```cpp
+#include "tools.h"
+int add(int x,int y){
+ return x+y;
+}
+```
+
+As you can see, for this type, once contestants include the given header, they do not need to implement `main`, and can focus on implementing the required function.
+
+## 3. Semi-checker mode — custom checker and modified output handling
+
+Example URL: http://82.157.98.222:8888/p/P10002
+This type does not require manually giving expected output for each case, but requires writing a reference checker program. During judging, user output is compared with checker logic.
+
+Still using A+B as example:
+
+1. Statement is similar to type 1.
+2. Test data only needs `1.in`.
+3. Write checker program `checker.cc` with content:
+
+```cpp
+#include "testlib.h"
+int main(int argc, char * argv[]) {
+ registerTestlibCmd(argc, argv);
+ int a = inf.readInt(); // 读取输入流的第一个整数
+ int b = inf.readInt(); // 读取输入流的下一个整数
+ int d = a+b;
+ int c = ouf.readInt(); // 读取输出流的下一个整数
+ if (a+b != c)
+ quitf(_wa, "%d + %d expected %d, found %d", a, b,d,c); //输出错误的具体信息,便于做题者调试
+ else
+ quitf(_ok, "answer of %d + %d is %d",a,b,c);
+}
+```
+
+4. `config.yaml` content:
+
+```yaml
+checker_type: testlib
+checker: checker.cc
+cases:
+ - input: 1.in
+ output: /dev/null # 无输出
+```
+
+Final test file list:
+
+
+
+When the program is wrong, output effect is as follows.
+
+You can see detailed error information is printed, making debugging easier.
+
+AC code is same as type 1:
+
+```cpp
+#include
+using namespace std;
+int main(int argc,char* argv[]){
+ int a,b;
+ cin>>a>>b;
+ cout <<(a+b);
+ return 0;
+}
+```
+
+# 4. Fully automatic checker problems
+
+If you do not want to manually input test input data and want it generated dynamically each run, set type to `interactive` and provide an interactor/checker program. Still using sum as example.
+Example URL: http://82.157.98.222:8888/p/P10005
+
+Final file list in test data section is shown below:
+
+
+
+1. `checker.cc` content:
+
+```cpp
+#include "testlib.h"
+#include
+using namespace std;
+
+int main(int argc, char* argv[]) {
+ setName("Interactor A+B");
+ registerInteraction(argc, argv);
+ //自动生成两个随机整数
+ rnd.setSeed(time(NULL));
+ int a = rnd.next(1000);
+ int b = rnd.next(1000);
+ // 本程序的输出将作为用户程序的输入
+ cout << a << " " << b << endl;
+ int c;
+ // 用户程序的最后输出将作为本程序的输入
+ cin >> c;
+ //对比用户结果和预期结果
+ if (a+b != c)
+ quitf(_wa, "%d + %d expected %d, found %d", a, b, a+b, c); //输出错误的具体信息,便于做题者调试
+ else
+ quitf(_ok, "answer of %d + %d is %d",a,b,c);
+}
+```
+
+2. `config.yaml` content:
+
+```yaml
+type: interactive
+interactor: checker.cc
+cases:
+- input: /dev/null # no input and no output, dynamic generated
+ output: /dev/null
+- input: /dev/null # no input and no output, dynamic generated
+ output: /dev/null
+```
+
+
+
+AC code is the same as type 1.
+
+## 5. File I/O based tests
+
+Example URL: http://82.157.98.222:8888/p/P10003
+Sometimes you want to specify input and output file names. In that case, `1.in` and `1.out` are similar to type 1,
+but you need to provide `config.yaml`, for example:
+
+```yaml
+file: test
+```
+
+Then in runtime, judge environment copies each input file to `test.in`, and compares output with `test.out`.
+AC code:
+
+```cpp
+#include
+using namespace std;
+int main(int argc,char* argv[]){
+ int a,b;
+ ifstream ifs("test.in");
+ ifs>>a>>b;
+ ofstream ofs("test.out");
+ ofs <<(a+b);
+ return 0;
+}
+```
+
+## 6. Subtask testing
+
+Example URL: https://hydro.ac/d/system_test/p/7
+1. Prepare statement and input/output files for each subtask. Recommended filename format: `data-`, where `id` is subtask ID.
+2. Refer to the following `config.yaml`:
+
+```yaml
+time: 100ms
+memory: 8m
+subtasks:
+ - score: 20
+ id: 0
+ cases:
+ - input: data1-1.in
+ output: data1-1.ans
+ - input: data1-2.in
+ output: data1-2.ans
+ - input: data1-3.in
+ output: data1-3.ans
+ - input: data1-4.in
+ output: data1-4.ans
+ - input: data1-5.in
+ output: data1-5.ans
+ - score: 20
+ id: 1
+ cases:
+ - input: data2-1.in
+ output: data2-1.ans
+ - input: data2-2.in
+ output: data2-2.ans
+ - input: data2-3.in
+ output: data2-3.ans
+ - input: data2-4.in
+ output: data2-4.ans
+ - input: data2-5.in
+ output: data2-5.ans
+ - score: 20
+ id: 2
+ cases:
+ - input: data3-1.in
+ output: data3-1.ans
+ - input: data3-2.in
+ output: data3-2.ans
+ - input: data3-3.in
+ output: data3-3.ans
+ - input: data3-4.in
+ output: data3-4.ans
+ - input: data3-5.in
+ output: data3-5.ans
+ - score: 20
+ id: 3
+ if: [2]
+ cases:
+ - input: data4-1.in
+ output: data4-1.ans
+ - input: data4-2.in
+ output: data4-2.ans
+ - input: data4-3.in
+ output: data4-3.ans
+ - input: data4-4.in
+ output: data4-4.ans
+ - input: data4-5.in
+ output: data4-5.ans
+ - score: 20
+ id: 4
+ if: [1, 3]
+ cases:
+ - input: data5-1.in
+ output: data5-1.ans
+ - input: data5-2.in
+ output: data5-2.ans
+ - input: data5-3.in
+ output: data5-3.ans
+ - input: data5-4.in
+ output: data5-4.ans
+ - input: data5-5.in
+ output: data5-5.ans
+```
+
+You can see `if` specifies prerequisite subtasks.
+Also, if a subtask does not provide `cases`, judge will auto-search files like `data-x.in` and `data-x.out`, where `id` is subtask ID.
+In the example above, subtask IDs are intentionally different from file-number groups, so each subtask needs manual `cases` assignment.
+
+
+## 7. Objective problem creation
+
+> Note: format of objective problems has been updated in the new version.
+
+Example URL: http://82.157.98.222:8888/p/P10004
+Objective problems only need statement and `config.yaml`.
+Example:
+
+```yaml
+1. 填空题
+
+1+1 = {{ input(1) }}
+
+2. 选择题
+
+{{ select(2) }}
+- 1+1=2
+- 1+1=3
+- 1+1=4
+
+3. 多选题
+
+{{ multiselect(3) }}
+- A
+- B
+- C
+
+```
+
+
+
+Uploaded `config.yaml` content:
+
+```yaml
+type: objective # 表明该题为客观题
+answers: # 列举出每一题的正确选项与对应的得分
+ '1': ['2', 50]
+ '2': [['A', 'B'], 30] # 填空题支持多答案,满足其一得分
+ '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分
+
+```
+
+Runtime effect:
+
+
+
+After finishing, click submit. Effect below:
+
+
+
+As you can see, scoring result is correct.
+
+## 8. Summary
+
+For all programming problems, statement input is mandatory. If a checker/interactor program is specified, output data may not need to be entered manually.
+If judge type is set to `interactive`, input data also does not need manual entry.
+When using special judging methods, you generally need to upload a `config.yaml` file and set corresponding fields.
+For programming problems, fields used in this document include:
+
+`type` is usually `default`; for fully automatic checker problems, set to `interactive`.
+
+checker_type: testlib
+checker: checker.cc
+Used to specify custom checker program.
+
+`filename: test` is used to specify reading/writing `test.in` and `test.out`.
+
+cases:
+ - input: 1.in
+
+Used to specify test cases.
+
+For more detailed introduction, see:
+https://hydro.js.org/docs/user/testdata/
diff --git a/content/docs/Hydro/user/problem-create.md b/content/docs/Hydro/user/problem-create.md
index 686ef5690..e3717f0b7 100644
--- a/content/docs/Hydro/user/problem-create.md
+++ b/content/docs/Hydro/user/problem-create.md
@@ -23,7 +23,7 @@ qq: 29985091
每个题目应自占一个目录,目录名为题目编号比如1 ,2,3,4等等.
每个题目目录下一般有下面的元素:
`problem_zh.md` 这个文件是就是题目的内容,即题目的描述,是一个markdown格式的文档.
-`probelm.yaml` 文件.这个是题目的配置信息. 比如标题和标签等。
+`problem.yaml` 文件.这个是题目的配置信息. 比如标题和标签等。
testdata 子目录,对应网站里的测试数据部分里的文件,
里面至少有一个config.yaml文件 用来说明测试的类型.具体内容见后面的例子
如果题目有测试用例,则每个用例至少要提供一个in文件和一个输出文件(但有些测试类型不用,详情见后)
diff --git a/content/docs/Hydro/user/problem-format.en.md b/content/docs/Hydro/user/problem-format.en.md
new file mode 100644
index 000000000..5e629dc3e
--- /dev/null
+++ b/content/docs/Hydro/user/problem-format.en.md
@@ -0,0 +1,41 @@
+---
+title: Hydro Problem Format
+---
+
+To facilitate data exchange between systems, Hydro defines a zip-based standard format for problem transfer. The file structure inside the archive is as follows:
+
+```
+>? tree
+.
+├── any_name_folder/
+│ ├── problem.yaml
+│ ├── problem_en.md
+│ ├── testdata
+│ │ ├── config.yaml
+│ │ ├── a1.in
+│ │ ├── a1.out
+│ │ ├── a2.in
+│ │ ├── a2.out
+│ │ ├── a3.in
+│ │ └── a3.out
+│ └── additional_file
+│ ├── a.png
+│ └── b.pdf
+└── ...
+```
+
+`problem.yaml` content is as follows:
+
+```yaml
+title: Problem Title
+tag:
+- tag1
+- tag2
+pid: problem_id (letters + numbers)
+```
+
+`problem_*.md` stores the statement in markdown format. Language codes support full forms (such as en_US) and short forms (such as en). If statements in multiple languages exist at the same time, Hydro will automatically detect and provide language switching.
+
+The `testdata` folder stores all test data files. For naming rules and config file format, refer to the **Test Data Format** section.
+
+`additional_file` stores additional files, usually images, PDF files, etc. These files can be accessed in the statement using paths like `file://filename`.
diff --git a/content/docs/Hydro/user/problem.en.mdx b/content/docs/Hydro/user/problem.en.mdx
new file mode 100644
index 000000000..596e15909
--- /dev/null
+++ b/content/docs/Hydro/user/problem.en.mdx
@@ -0,0 +1,108 @@
+---
+title: Problem
+---
+
+## Creating a Problem
+
+Users with the `PERM_CREATE_PROBLEM` permission can create new problems.
+To do so, click the **"Create Problem"** button at the bottom-right of the problem set page.
+
+
+Problem IDs cannot be solely numeric. If you leave the ID field empty, the system will auto-assign a numeric ID.
+
+
+For detailed instructions on editing problem statements, see below and [laomai's guide](./problem-create).
+
+## Importing Problems
+
+### From Hydro Archives
+You can upload problem archives previously exported from Hydro. For large archives, use the CLI import tool:
+
+```bash
+# Import a Hydro-format package (.zip or folder) into a specific domain.
+hydrooj cli problem import
+```
+
+### From SYZOJ
+The [loj-download](https://github.com/hydro-dev/loj-download) tool can download Hydro-format problem archives from sites based on SYZOJ or SYZOJ-NG.
+
+### From FPS Files
+See the [fps-importer](../plugins/fps-importer/) plugin documentation.
+
+### From QDUOJ
+See the `import-qduoj` plugin documentation.
+
+## Editing Problem Statements
+
+Problem statements are written using Markdown with several built-in extensions.
+
+### Sample Data Grouping
+Test cases with the same numeric index are paired automatically and displayed side-by-side:
+
+`````markdown
+```input1
+1 2
+```
+
+```output1
+3
+```
+`````
+
+### Referencing Additional Files
+You can link to or embed files uploaded in the "Files" tab:
+
+- **Download Link**: `[Download input.in](file://input.in)`
+- **Image Embedding**: ``
+- **PDF Viewing**: `@[pdf](file://specification.pdf)`
+- **Word Document Viewing**: `@[doc](file://manual.docx)` (Requires the `onlyoffice` plugin).
+
+
+If using external storage (S3/OSS), files may be downloaded instead of previewed due to `Content-Disposition` headers. Please refer to your storage provider's documentation to enable in-browser previews:
+- [Tencent Cloud COS Docs](https://cloud.tencent.com/document/product/436/96243)
+- [Alibaba Cloud OSS Docs](https://help.aliyun.com/zh/oss/user-guide/how-to-ensure-an-object-is-previewed-when-you-access-the-object)
+
+
+### Advanced Formatting
+- **Merged Tables**: Use standard Markdown table syntax; Hydro handles cell merging where appropriate.
+- **Embedded HTML**: For layouts not supported by Markdown, you can use safe HTML tags like `text `.
+
+### Tags
+Assign tags using the category panel on the right or by entering comma-separated terms.
+
+## Test Data and Files
+
+Manage test cases and additional resources via the **"Files"** panel. Drag-and-drop is supported. See [Test Data Format](../user/testdata) for more details.
+
+## Objective Problems (Multiple Choice/Fill-in-the-Blank)
+
+### Statement Syntax
+Objective problems use custom tags to place input fields or selection menus:
+
+```markdown
+1. Fill in the blank: 1 + 1 = {{ input(1) }}
+
+2. Single choice: {{ select(2) }}
+- Choice A (Correct)
+- Choice B
+- Choice C
+
+3. Multiple choice: {{ multiselect(3) }}
+- Answer 1
+- Answer 2
+- Answer 3
+```
+
+### Configuration (`config.yaml`)
+Objective problems require a `config.yaml` file to define correct answers and scoring:
+
+```yaml
+type: objective
+answers:
+ '1': ['2', 50] # Question 1: Answer is '2', worth 50 points.
+ '2': # Question 2: Multiple valid answers with different scores.
+ 'A': 30
+ 'B': 10
+ '3': [['A', 'B'], 20] # Question 3: Both A and B must be selected for 20 points.
+```
+
diff --git a/content/docs/Hydro/user/testdata.en.mdx b/content/docs/Hydro/user/testdata.en.mdx
new file mode 100644
index 000000000..b5c9cab6c
--- /dev/null
+++ b/content/docs/Hydro/user/testdata.en.mdx
@@ -0,0 +1,106 @@
+---
+title: Test Data Format
+---
+
+## Automatic Recognition Mode
+
+
+You can multi-select files to upload or use drag-and-drop. Zip archives will be automatically extracted upon upload.
+
+
+For standard problems, you only need to provide `.in` and `.out` (or `.ans`) files. Files must contain a numeric suffix to be correctly identified (e.g., `1.in` or `test1.in`). Files like `sample.in` will not be automatically recognized as test cases.
+
+```bash
+# Example Directory Structure:
+.
+├── a1.in
+├── a1.out
+├── a2.in
+├── a2.out
+├── a3.in
+└── a3.out
+```
+
+Detected test data will use default limits of **1s** (time) and **256MB** (memory).
+
+## Using a Configuration File (`config.yaml`)
+
+
+We recommend using the **Judge Settings** panel in the problem editor for a more intuitive experience.
+
+
+A `config.yaml` file allows for granular control. The following example shows available options:
+
+```yaml
+# Problem type: default (standard comparison), objective, or interactive.
+type: default
+
+# Global limits (overridden by per-testcase limits).
+time: 1s
+memory: 128m
+
+# Input/Output Filename (e.g., foo.in / foo.out).
+# Remove this for Standard I/O (stdin/stdout).
+filename: foo
+
+# Options for type: default
+# Checker type: default (ignores trailing whitespace/newlines),
+# testlib (common), hustoj, lemon, etc.
+checker_type: default
+
+# Path to the custom checker (if not default).
+# Language is identified by extension (.cc for C++).
+checker: chk.cc
+
+# Path to the interactor (required for interactive problems).
+interactor: interactor.cc
+
+# Extra files to be copied into the judge working directory.
+user_extra_files:
+ - helper_input.txt
+judge_extra_files:
+ - secret_data.txt
+
+# Test Case Configuration
+# If CASES and SUBTASKS are missing, the system defaults to automatic recognition.
+subtasks:
+ - score: 30
+ type: min # min/max/sum: score for the subtask based on cases within it.
+ time: 1s
+ memory: 64m
+ cases:
+ - time: 0.5s
+ memory: 32m
+ input: a.in
+ output: a.out
+ - input: b.in
+ output: b.out
+ - score: 70
+ time: 0.5s
+ memory: 32m
+ if: [0] # Dependent on passing subtask 0.
+ cases:
+ - input: c.in
+ output: c.out
+ - input: d.in
+ output: d.out
+
+# Permitted Languages (Must match judge machine lang.yaml IDs).
+langs:
+ - c
+ - cc
+ - cc.cc11o2
+ - pas
+
+# Per-language Time/Memory multipliers.
+time_limit_rate:
+ py.py3: 2
+memory_limit_rate:
+ java: 1.5
+```
+
+Sample configurations for various problem types can be found in the [System Test Problemset](https://hydro.ac/d/system_test/).
+
+```
+
+You can find config examples for different problem types in [this problemset](https://hydro.ac/d/system_test/).
diff --git a/content/docs/Tools/index.en.mdx b/content/docs/Tools/index.en.mdx
new file mode 100644
index 000000000..c3f1e68ad
--- /dev/null
+++ b/content/docs/Tools/index.en.mdx
@@ -0,0 +1,74 @@
+---
+title: Onsite Contest Guide
+---
+
+This guide is for users who want to run onsite contests and deploy judging infrastructure in an internal network.
+The date schedule below is for reference only; you can arrange it based on actual conditions.
+
+Some content in this article also applies to DOMJudge.
+
+## Day -1 Preparation
+
+Please check whether all items in the list below are configured as required:
+
+About contestant machines:
+
+- Contestant machines are preinstalled with Linux and have the corresponding development environment.
+- CAICPC is recommended as the installation image; select the second boot option for one-click installation.
+- All contestant machines are connected to the internal network, cannot access each other, but can access public network servers (if your router does not support this, you can use iptables on contestant machines to block other traffic).
+- DHCP can be used to configure contestant machine networking, but ensure lease duration is long enough (seven days recommended).
+
+About server setup:
+
+- The server uses a static IP and can access any device in the internal network (including contestant machines);
+- The server runs Linux with a relatively new kernel. Older kernel versions are known to potentially freeze under high load [details](https://blog.taoky.moe/2023-12-02/icpc-2023-hefei-judgehosts-scale.html);
+
+About the CAICPC image:
+
+- This image is modified from the standard ICPC image.
+- Added status reporting for unified server status monitoring;
+- Supports calling VLC to capture screen and camera streams for the live module;
+- Supports batch dispatch of management commands (one-click lock screen / unlock / reboot / show seat number, etc.);
+
+## Day 0 Preparation
+
+- Install Hydro using the installation script.
+- Import required contest users.
+- Install the `@hydrooj/onsite-toolkit` plugin.
+- Install standalone modules by following `https://github.com/hydro-dev/xcpc-tools`.
+- Volunteers open the seat.txt file on all contestant desktops, fill in seat numbers, save; seat numbers shown in the backend should refresh synchronously;
+- If automatic login by seat number is needed, export the IP/team table and fill it in onsite-toolkit settings.
+- After preparation is complete, batch-change contestant machine passwords to strong passwords!!!
+
+// TODO: tools configuration
+
+About printing:
+
+- Printing is configured in `xcpc-tools`.
+- Create a printer token on the server side, place a computer next to the contest site, install corresponding printer drivers, run `xcpc-tools` in client mode, fill in the token, and it can connect.
+- `xcpc-tools` automatically fetches and prints print tasks. By default, each file prints at most five pages, and team name and seat number are printed at the top of the paper.
+
+About balloons:
+
+- Balloons are usually printed by a receipt printer. Whenever a team solves a problem, a receipt is printed;
+- The receipt contains team name, seat number, balloon color, all current balloon colors of that team, etc. Volunteers distribute balloons according to the receipt.
+
+About automatic login:
+
+After enabling, users in the address list are automatically logged into the specified corresponding account. Users cannot log in again, cannot log out, and cannot log in from other IPs.
+Before operating, make sure the list does not contain administrator accounts and IPs used by administrators!
+
+Optional:
+
+- Install grafana and netdata to monitor server runtime status ~~and show leadership~~;
+
+## Day 1 Warm-up Contest
+
+Warm-up contests usually use at least one problem that can be brute-forced with repeated submissions, guiding contestants to submit heavily and testing server load.
+
+## Day 2 Official Contest
+
+- If balloons are needed, inflate them early (usually the balloon group is very busy in the hour before the contest)
+- Remember to refill printer paper, same for receipt printers.
+
+// TODO: scoreboard freeze configuration
diff --git a/content/docs/Tools/meta.en.json b/content/docs/Tools/meta.en.json
new file mode 100644
index 000000000..5719689fa
--- /dev/null
+++ b/content/docs/Tools/meta.en.json
@@ -0,0 +1,3 @@
+{
+ "root": true
+}
diff --git a/content/index.en.md b/content/index.en.md
new file mode 100644
index 000000000..5e9a9d4c9
--- /dev/null
+++ b/content/index.en.md
@@ -0,0 +1,97 @@
+---
+home: true
+heroImage: /favicon.png
+heroText: Hydro
+tagline: High-performance Online Judge System
+actions:
+ - text: Introduction 💡
+ link: /docs/
+ type: primary
+ - text: Deployment Guide
+ link: /docs/install/
+features:
+- title: Secure
+ details: Uses Linux container technology to isolate user programs
+- title: Convenient
+ details: Supports one-click deployment with scripts
+- title: Powerful
+ details: Provides contests, training, discussions, editorials, assignments, and more, and can be extended by installing add-ons
+- title: Fast
+ details: Sandbox reuse and delayed calculation improve execution efficiency
+footer: AGPL3.0 Licensed | Copyright © 2021-present Undefined
+---
+
+
+
+
+
+
+
+
+
+
+
+Hydro is a high-performance online judge system for competitive programming. It is designed to be lightweight, powerful, and easy to deploy with provided installation scripts.
+
+[GitHub Repository](https://github.com/hydro-dev/Hydro)
+
+Starring this project encourages the developers!
+We welcome donations to support the development and maintenance of Hydro.
+Hydro also offers paid custom development services; please contact us for inquiries.
+If you find the documentation lacking, please submit a Pull Request or contact the development team with suggestions.
+Please report bugs and suggest features through [GitHub Issues](https://github.com/hydro-dev/Hydro/issues).
+
+[Try it on Gitpod](https://gitpod.io/#https://github.com/hydro-dev/Hydro)
+
+[Hydro Online Judge](https://hydro.ac/)
+
+## Contact Us
+
+- Email: [i@undefined.moe](mailto:i@undefined.moe)
+- Telegram: [@undefinedmoe](https://t.me/undefinedmoe)
+- Hydro User Group: 1085853538
+
+**Note 1:** Hydro is an open-source framework. Anyone can use it in compliance with the license. For copyright complaints, please contact the administrator of the specific website (typically the user with UID=2); the developers are not responsible for hosted content.
+
+**Note 2:** Before joining the user group, please read ["How To Ask Questions The Smart Way"](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README.md). Please be aware that the group may contain informal or potentially offensive content. If this is a concern, **please do not join**.
+
+## Open-source License
+
+Content under `examples/`, `install/`, and `packages/ui-default/` is licensed under AGPL-3.0.
+The rest of the project is dual-licensed:
+
+1. Free usage is permitted under the terms of the AGPL-3.0 license and the additional terms below.
+2. For closed-source or commercial usage, please contact us to purchase a separate license.
+
+## Additional Terms
+
+In accordance with Article 7 of the AGPL-3.0 license, the following additional terms apply:
+
+1. You may not remove copyright notices or author/source attributions. ([AGPL3 7(b)](LICENSE#L356))
+2. When redistributing modified versions, you must clearly indicate the modifications in the software name or version number. ([AGPL3 7(c)](LICENSE#L360))
+3. The author's name may not be used for promotional purposes without explicit permission. ([AGPL3 7(d)](LICENSE#364))
+
+Specifically:
+- Deployments of Hydro must retain the `Powered by Hydro` footer text, linking to `hydro.js.org/this-repo/fork`.
+- If you modify or extend the source code, your modifications must also be open-sourced under AGPL-3.0-or-later. You may indicate this as `Powered by Hydro, Modified by xxx`.
+- This restriction extends to the following:
+ - Hydro plugins.
+ - Components interacting with Hydro via HTTP or other protocols.
+
+If you require these modules to remain closed-source, please contact us to purchase a license.
+
+In light of past community incidents, we make the following statements:
+- Open-sourcing this project does not obligate the developers to provide support.
+- Please read "How To Ask Questions The Smart Way" before seeking help.
+- Developers reserve the right to cease providing technical support to any individual or entity.
+- While we **strive** to ensure smooth upgrades, we cannot guarantee that new versions will not introduce breaking changes. Internal implementations may be modified or removed without prior notice.
+
+If you do not agree with these terms, please refrain from using this project.
+
+## Acknowledgements
+
+(In alphabetical order)
+
+- [GitHub](https://github.com/) for code hosting and CI/CD.
+- [criyle](https://github.com/criyle) for the judge sandbox implementation.
+- [Vijos](https://github.com/vijos/vj4) for the UI framework inspiration.
diff --git a/lib/i18n.ts b/lib/i18n.ts
new file mode 100644
index 000000000..629895291
--- /dev/null
+++ b/lib/i18n.ts
@@ -0,0 +1,6 @@
+import { defineI18n } from 'fumadocs-core/i18n';
+
+export const i18n = defineI18n({
+ defaultLanguage: 'zh',
+ languages: ['zh', 'en'],
+});
diff --git a/lib/layout.shared.tsx b/lib/layout.shared.tsx
new file mode 100644
index 000000000..ec2a5f185
--- /dev/null
+++ b/lib/layout.shared.tsx
@@ -0,0 +1,42 @@
+import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
+import { i18n } from '@/lib/i18n';
+import { defineI18nUI } from 'fumadocs-ui/i18n';
+import Image from 'next/image';
+
+export const i18nUI = defineI18nUI(i18n, {
+ translations: {
+ zh: {
+ displayName: '中文',
+ toc: '目录',
+ search: '搜索文档',
+ lastUpdate: '最后更新于',
+ searchNoResult: '没有结果',
+ previousPage: '上一页',
+ nextPage: '下一页',
+ chooseLanguage: '选择语言',
+ },
+ en: {
+ displayName: 'English',
+ },
+ },
+});
+
+export function baseOptions(locale: string): BaseLayoutProps {
+ return {
+ i18n,
+ nav: {
+ title: (
+ <>
+
+ Hydro
+ >
+ ),
+ url: `/${locale}`,
+ },
+ };
+}
diff --git a/lib/source.ts b/lib/source.ts
index 6eb20cb83..ec0ec50db 100644
--- a/lib/source.ts
+++ b/lib/source.ts
@@ -2,10 +2,12 @@ import { docs } from 'fumadocs-mdx:collections/server';
import { loader } from 'fumadocs-core/source';
import { icons } from 'lucide-react';
import { createElement } from 'react';
+import { i18n } from '@/lib/i18n';
export const source = loader({
baseUrl: '/docs',
source: docs.toFumadocsSource(),
+ i18n,
icon(icon) {
if (!icon) return;
if (icon in icons) return createElement(icons[icon as keyof typeof icons]);