` to separate paragraphs. + + ```java + /** + * This is the first paragraph of the Javadoc. + *
+ * This is the second paragraph of the Javadoc.
+ */
+ ```
+
+ - Each paragraph must be a grammatically correct and semantically complete paragraph following English sentence conventions.
+ - All `@param`, `@return`, `@throws`, and `@see` explanations must follow these rules:
+ - Do not start with a capital letter.
+ - If the description ends with a declarative sentence, do not use punctuation at the end.
+
+ ```java
+ /**
+ * Returns the greater of two {@code int} values. That is, the
+ * result is the argument closer to the value of
+ * {@link Integer#MAX_VALUE}. If the arguments have the same value,
+ * the result is that same value.
+ *
+ * @param a an argument
+ * @param b another argument
+ * @return the larger of {@code a} and {@code b}
+ */
+ public static int max(int a, int b) {
+ return (a >= b) ? a : b;
+ }
+ ```
+
+## Dependency Management (Gradle)
+
+- **Build File**: `build.gradle.kts` must be well-organised with clear separation of plugins, dependencies, and tasks.
+- **Dependency Versions**: Dependency versions must be centrally managed in the `gradle/libs.versions.toml` file to ensure consistency.
+- **Plugin Management**: Explicitly declare Gradle plugins and their versions.
+- **Avoid Unnecessary Dependencies**: Only include dependencies actually used by the project. Regularly review and clean up unused dependencies.
+
+## API Design (RESTful)
+
+- **RESTful Principles**: Follow RESTful principles:
+ - **Resources**: Model data as resources identifiable by URI.
+ - **HTTP Methods**: Use standard HTTP methods appropriately (GET for retrieval, POST for creation, PUT for full update, PATCH for partial update, DELETE for removal).
+ - **Statelessness**: APIs should be stateless; each request from client to server must contain all the information needed to understand the request.
+- **URIs**:
+ - Use plural nouns for collection resources (e.g., `/users`, `/products`).
+ - Use hyphens in URIs for readability (e.g., `/user-accounts`).
+ - Avoid verbs in URIs (e.g., use `/users` instead of `/getAllUsers`).
+- **Status Codes**: Use appropriate HTTP status codes to indicate the result of API requests (e.g., `200 OK`, `201 Created`, `204 No Content`, `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found`, `500 Internal Server Error`).
+- **Response Format**: JSON is the preferred response format.
+- **Versioning**: Where version control is required, use the `X-Endpoint-Version` header parameter to control API versions.
+
+## Spring Boot Best Practices & Layered Architecture
+
+- **Layered Architecture (MVC with Manager Layer)**: Our backend applications follow a strict multi-layered architecture, ensuring clear separation of responsibilities and improving maintainability and testability. The layers and their responsibilities are:
+
+ - **Controller Layer**: Located in the `controller` package. Responsible for exposing RESTful APIs, handling HTTP requests, and mapping request parameters/bodies to service layer calls. Controllers should remain lightweight, focusing primarily on input validation (using DTOs) and coordinating calls to the `Service` layer.
+ - **Service Layer**: Located in the `service` package. This layer encapsulates core business logic. Services expose a directly consumable API to the `Controller` layer, abstracting business processes and transaction management. Services coordinate calls to the `Manager` layer to execute business operations.
+ - **Manager Layer**: Located in the `manager` package. This layer provides atomic business operations that can be composed by the `Service` layer. Managers typically handle more complex business logic and may involve interacting with multiple repositories or other external systems at a finer granularity.
+ - **Repository Layer (MyBatis)**: Located in the `repository` package and `src/main/resources/repository` (for XML mapping files). This layer is responsible for providing atomic database interaction operations.
+
+ **Inter-Layer Communication Strategy**:
+ - **Components within a layer may only call components in the layer directly below it.**
+ - **Cross-layer calls are strictly prohibited** (e.g., Controller directly calling Manager, Service directly calling Repository).
+ - **Upward calls are strictly prohibited** (e.g., Service calling Controller).
+ - **Lateral calls** (e.g., Service A calling Service B for a different domain) should be carefully considered and typically indicate a need to refactor shared logic into a `Manager` or a dedicated `Service` for that shared concern.
+
+ - **Configuration**: Prefer `application.yml` over `application.properties` for configuration properties, offering better readability and hierarchical structure. Use `@ConfigurationProperties` for type-safe configuration.
+ - **Dependency Injection**: All dependencies should use constructor injection (mandatory dependencies) or setter injection (optional dependencies). Avoid `@Autowired` on fields, as it makes testing more difficult and hides dependencies.
+ - **Services**: Business logic classes are annotated with `@Service`. Services should be kept lean and focused on orchestrating domain operations, typically involving business logic processing through `Manager` layer components and interaction through `Manager` or directly with MyBatis repositories (if the particular operation does not require intermediate Manager logic, though the Manager layer is preferred for all repository interactions consistent with the layered architecture definition).
+
+- **Repositories (MyBatis & JPA)**:
+ - **The project uses both MyBatis and JPA for database operations**. Repository interfaces in the `repository` and `mapper` packages define the data access contract.
+ - Corresponding SQL definitions are managed in XML mapping files located in `src/main/resources/mapper`.
+ - Data operation conventions:
+ - Use JPA for simple database operations.
+ - Use MyBatis for complex database operations.
+ - When performing paginated queries, page numbers should start from 0 (*compatible with Spring Data JPA*).
+ - **Data Access Method Naming Conventions**:
+ - For **querying data lists**: methods **must** start with `selectListBy`, followed by the filter criteria (e.g., `selectListByUserId`, `selectListByDepartmentIdAndStatus`). These methods must also include a `PageRequest` parameter for pagination.
+ - For querying **single data records**: methods **must** start with `selectOne` (e.g., `selectOneById`, `selectOneByUsername`).
+ - For **saving new data**: methods **must** be named `save`, and Mapper method return type must be `int` (affected row count).
+ - For **updating existing data**: methods **must** be named `update`, and Mapper method return type must be `int` (affected row count).
+ - For **deleting data**: methods **must** start with `deleteBy`, clearly indicating the deletion criteria (e.g., `deleteById`). Mapper method return type must be `int` (affected row count).
+
+- **Controllers**:
+ - Annotate REST controllers with `@RestController`.
+ - Use `@GetMapping`, `@PostMapping`, etc. to map HTTP methods (GET, POST, PUT, DELETE) to appropriate controller methods.
+ - Ensure request and response payloads are clearly defined (DTOs) and documented.
+ - Controllers should primarily handle HTTP request/response mapping and delegate actual business logic to the service layer.
+
+- **DTOs (Data Transfer Objects)**: Define separate DTOs for request and response bodies to decouple the internal domain model from the API contract. Use validation annotations on DTOs (e.g., `@Valid`, `@NotNull`, `@Size`).
+
+- **Logging (SLF4J & Logback)**:
+ - All logging in the application uses `org.slf4j.Logger`.
+ - Configure `application-dev.yml` to set logging levels, appenders, and output formats.
+ - Log messages should be descriptive and provide sufficient context. Avoid logging sensitive information.
+ - Use parameterised logging for performance and to prevent string concatenation overhead (e.g., `log.debug("Processing user: {}", userId);`).
+ - Standard log levels: `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`.
+
+## Project Structure
+
+Backend applications follow a structured Gradle project layout. The core application should be clearly divided into various sub-packages.
+
+```text
+backend-application
+├── build.gradle.kts // Project's main Gradle build script
+├── config // External configuration directory
+│ ├── application-dev.yml // Application properties for the development environment
+│ └── application-prod.yml.example // Example production properties (to be copied and configured)
+├── database // Database-related files
+│ └── init.d // Database initialisation scripts
+│ └── init-en_GB.sql // SQL script for database schema and initial data using the specified locale (British English)
+├── gradle // Gradle Wrapper and configuration files
+│ ├── libs.versions.toml // Centralised dependency version management (Gradle Version Catalog)
+│ └── wrapper // Gradle Wrapper files
+│ ├── gradle-wrapper.jar
+│ └── gradle-wrapper.properties
+├── gradle.properties // Project-specific Gradle properties
+├── gradlew // Gradle Wrapper executable (Linux/macOS)
+├── gradlew.bat // Gradle Wrapper executable (Windows)
+├── settings.gradle.kts // Gradle settings for multi-project builds (if applicable)
+└── src
+ ├── main
+ │ ├── java
+ │ │ └── com/onixbyte/application // Application root package
+ │ │ ├── Application.java // Spring Boot application main entry point
+ │ │ ├── config // Spring configuration classes
+ │ │ ├── constant // Classes defining application-wide constants
+ │ │ ├── controller // REST API endpoints
+ │ │ ├── domain // Core domain models and related types
+ │ │ │ ├── common // Common domain objects/utilities
+ │ │ │ ├── entity // JPA/MyBatis entities representing database tables
+ │ │ │ ├── model // General-purpose entity class models
+ │ │ │ ├── view // Data transfer objects specifically for read-only operations (e.g., query results, report structures)
+ │ │ │ └── web // Data transfer objects specifically for web request/response bodies
+ │ │ │ ├── request // Request DTOs
+ │ │ │ └── response // Response DTOs
+ │ │ ├── exception // Custom application-specific exceptions
+ │ │ ├── extension // Extension points or custom functionality
+ │ │ │ ├── jackson // Jackson serialisation/deserialisation extensions
+ │ │ │ └── redis // Redis-related extensions
+ │ │ │ └── serializer
+ │ │ ├── filter // Servlet filters or Spring Security filters
+ │ │ ├── manager // Business logic coordinators, typically orchestrating multiple services or repositories
+ │ │ ├── mapper // Data access layer (MyBatis interfaces)
+ │ │ ├── processor // General-purpose processing components or business workflows
+ │ │ ├── properties // Classes for type-safe configuration properties (`@ConfigurationProperties`)
+ │ │ ├── repository // Data access layer (Spring Data JPA interfaces)
+ │ │ ├── security // Spring Security-specific components
+ │ │ │ ├── authentication // Custom authentication mechanisms
+ │ │ │ └── provider // Custom authentication providers
+ │ │ ├── service // Core business logic (transactional layer)
+ │ │ ├── utils // General-purpose utility classes
+ │ │ └── validation // Custom validation logic
+ │ │ └── group // Validation groups for different contexts (e.g., create, update)
+ │ └── resources
+ │ ├── application.yml // Default application properties
+ │ └── mapper // MyBatis XML mapping files
+ └── test
+ └── java
+ └── com/onixbyte/helix
+ └── HelixApplicationTests.java // Spring Boot integration tests
+```
+
+**Key Observations and Specific Instructions:**
+
+- **External `config` Directory**
+ - Environment configurations (`application-dev.yml`, `application-prod.yml.example`) are managed in the top-level `config` directory, separate from `src/main/resources`. This facilitates environment-specific property management, allowing different configurations to be mounted or linked at deployment time.
+ - **Do not upload any configuration files other than `src/main/resources/application.yml` to the Git repository.**
+- **Database Initialisation**: The `database/init.d` directory is reserved for SQL scripts, specifically database schema initialisation (`init-en_GB.sql`), which is critical for environment setup and CI/CD pipelines. This structure suggests a "schema-first" or "code-driven schema evolution" approach.
+- **`client` Package**: This package is used to provide services for all middleware to the application, such as HTTP, S3 storage, Redis calls, etc. For self-coded functional implementations that need to be added to the Spring context (such as JSON Web Token generation and parsing), placing them in this package is also recommended.
+- **MyBatis & Spring Data JPA Integration**
+ - The `src/main/java/.../mapper` package contains MyBatis mapper interfaces, while the actual SQL definitions reside in `src/main/resources/mapper/*.xml` files. This separation is key to keeping code clean while leveraging MyBatis's powerful XML mapping capabilities.
+ - The `src/main/java/.../repository` package contains Spring Data JPA interfaces.
+- **`domain` Package Granularity**:
+ - `domain.entity`: Reserved for classes directly mapped to database tables (POJOs for MyBatis).
+ - `domain.model`: For more general-purpose domain objects or aggregate roots that do not map one-to-one with individual tables.
+ - `domain.view`: Specifically for Data Transfer Objects (DTOs) used in read-only scenarios (e.g., query results, report structures).
+ - `domain.web.request` / `domain.web.response`: Clearly separated DTOs for incoming API requests and outgoing API responses, strictly adhering to the API contract and decoupled from internal domain entities.
+- **`manager` and `processor` Packages**: These packages imply a layered architecture where "managers" coordinate operations involving multiple services or repositories, while "processors" may handle specific aspects of business processes. It is mandatory to clearly define the responsibilities of classes in these packages to prevent anti-patterns such as "anaemic domain model" or "god objects".
+- **`security` Package**: This sub-package contains custom Spring Security components beyond the initial configuration, such as custom authentication types and providers, indicating a tailored security implementation.
+- **`properties` Package**: This package is for custom `@ConfigurationProperties` classes, facilitating type-safe access to application settings defined in YML files — well-positioned.
+- **`extension` Package**: This is a flexible area for application-specific extensions, such as custom Jackson serialisers or Redis customisations. It should be used sparingly to avoid becoming a "miscellaneous" dumping ground.
+
+## Security (Spring Security)
+
+- **Mandatory Use**: Spring Security is mandatory in all Spring Boot web applications.
+- **Authentication & Authorisation**: Configure authentication mechanisms (e.g., OAuth 2.0, JWT, session-based) and authorisation rules in `SecurityConfig.java`.
+- **CSRF Protection**: Ensure CSRF protection is enabled for state-modifying operations, unless there is a strong reason to disable it (e.g., stateless APIs with other mechanisms already in place).
+- **CORS**: Correctly configure Cross-Origin Resource Sharing (CORS) according to frontend deployment requirements.
+- **Third-Party Identity Providers**: When integrating with third-party identity providers (e.g., Microsoft Entra ID), follow best practices for secure token handling and user provisioning. Sensitive credentials must be securely managed (e.g., environment variables, Vault).
+- **Input Validation**: Always validate all user input on the server side to prevent common vulnerabilities such as SQL injection, XSS, etc.
+- **Content Security Policy (CSP)**: Consider implementing a robust CSP for the frontend to mitigate XSS attacks.
diff --git a/docs/en-gb/blog/contents/minio-admin-guide.md b/docs/en-gb/blog/contents/minio-admin-guide.md
new file mode 100644
index 0000000..7769d08
--- /dev/null
+++ b/docs/en-gb/blog/contents/minio-admin-guide.md
@@ -0,0 +1,200 @@
+---
+title: MinIO Administration Guide for New Versions
+tags:
+ - minio
+ - storage
+ - s3
+ - devops
+ - cheatsheet
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+In newer versions, MinIO has removed administrative functionality from the Web UI. You now need to use the **MinIO Client (mc)** command-line tool for all management operations.
+
+## Installing MinIO Client (mc)
+
+### Windows:
+
+```powershell
+# Download mc.exe
+Invoke-WebRequest -Uri "https://dl.min.io/client/mc/release/windows-amd64/mc.exe" -OutFile "mc.exe"
+
+# Or using Chocolatey
+choco install minio-client
+```
+
+### Linux/macOS:
+
+```bash
+# Linux
+wget https://dl.min.io/client/mc/release/linux-amd64/mc
+chmod +x mc
+sudo mv mc /usr/local/bin/
+
+# macOS
+brew install minio/stable/mc
+```
+
+## Configuring the MinIO Client
+
+```bash
+# Add a MinIO server alias
+mc alias set myminio http://localhost:9000 minioadmin minioadmin
+
+# Verify the connection
+mc admin info myminio
+```
+
+## User Management
+
+### Creating Users
+
+```bash
+# Create a new user
+mc admin user add myminio newuser newpassword
+
+# List all users
+mc admin user list myminio
+```
+
+### Creating Access Keys and Secret Keys
+
+```bash
+# Create a service account for a user (generates AccessKey/SecretKey)
+mc admin user svcacct add myminio newuser
+
+# Or specify custom AccessKey and SecretKey
+mc admin user svcacct add myminio newuser --access-key "MYACCESSKEY123" --secret-key "MYSECRETKEY456"
+
+# View a user's service accounts
+mc admin user svcacct list myminio newuser
+```
+
+## Permission Management
+
+### Creating Policies
+
+```bash
+# Create a policy file policy.json
+cat > policy.json << EOF
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject"
+ ],
+ "Resource": [
+ "arn:aws:s3:::mybucket/*"
+ ]
+ }
+ ]
+}
+EOF
+
+# Add the policy
+mc admin policy add myminio mypolicy policy.json
+
+# Assign the policy to a user
+mc admin policy set myminio mypolicy user=newuser
+```
+
+## Bucket Management
+
+```bash
+# Create a bucket
+mc mb myminio/mybucket
+
+# List buckets
+mc ls myminio
+
+# Set bucket policy
+mc policy set public myminio/mybucket
+```
+
+## Common Administration Commands
+
+```bash
+# View server information
+mc admin info myminio
+
+# View server configuration
+mc admin config get myminio
+
+# Restart the server
+mc admin service restart myminio
+
+# View logs
+mc admin logs myminio
+
+# View statistics
+mc admin prometheus metrics myminio
+```
+
+## Practical Script Example
+
+Create an administration script `setup-minio.sh`:
+
+```bash
+#!/bin/bash
+
+MINIO_ALIAS="myminio"
+MINIO_URL="http://localhost:9000"
+ADMIN_USER="minioadmin"
+ADMIN_PASS="minioadmin"
+
+# Configure the MinIO client
+mc alias set $MINIO_ALIAS $MINIO_URL $ADMIN_USER $ADMIN_PASS
+
+# Create an application user
+APP_USER="appuser"
+APP_PASS="apppassword"
+mc admin user add $MINIO_ALIAS $APP_USER $APP_PASS
+
+# Create a service account and retrieve AccessKey/SecretKey
+echo "Creating service account for $APP_USER..."
+CREDENTIALS=$(mc admin user svcacct add $MINIO_ALIAS $APP_USER --json)
+ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.accessKey')
+SECRET_KEY=$(echo $CREDENTIALS | jq -r '.secretKey')
+
+echo "Generated credentials:"
+echo "Access Key: $ACCESS_KEY"
+echo "Secret Key: $SECRET_KEY"
+
+# Create a bucket
+mc mb $MINIO_ALIAS/app-bucket
+
+# Set a read-only policy
+mc policy set download $MINIO_ALIAS/app-bucket
+```
+
+## Web Console Access
+
+Although administrative functionality has been removed, you can still access the MinIO Console via:
+
+```bash
+# Launch the MinIO Console (if installed separately)
+mc admin console myminio
+```
+
+Alternatively, specify the console address when starting the MinIO server:
+
+```bash
+minio server /data --console-address ":9001"
+```
+
+## Summary
+
+Managing the new MinIO relies entirely on the `mc` command-line tool:
+
+1. **Install the mc client**
+2. **Configure the server alias**
+3. **Use `mc admin` commands for user, permission, and bucket management**
+4. **Generate AccessKeys/SecretKeys via `mc admin user svcacct`**
+
+While this approach requires command-line operations, it provides more powerful and flexible management capabilities, particularly suited for automated deployment and script-based management.
diff --git a/docs/en-gb/blog/contents/mybatis-flex.md b/docs/en-gb/blog/contents/mybatis-flex.md
new file mode 100644
index 0000000..a5a7a09
--- /dev/null
+++ b/docs/en-gb/blog/contents/mybatis-flex.md
@@ -0,0 +1,31 @@
+---
+title: MyBatis Flex
+tags:
+ - java
+ - mybatis
+ - spring-boot
+ - orm
+ - framework
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+> This article only aims at using `MyBatis Flex` in Spring Boot 3
+
+## Installation and Configuration
+
+### Installation
+
+Add the following codes to `libs.versions.toml` in `gradle` :
+
+```toml
+[versions]
+mybatisFlexVersion = "X.Y.Z"
+hikariVersion = "X.Y.Z"
+
+[libraries]
+hikari = { group = "com.zaxxer", name = "HikariCP", version.ref = "hikariVersion" }
+mybatisFlex-processor = { group = "com.mybatis-flex", name = "mybatis-flex-processor", version.ref = "mybatisFlexVersion" }
+mybatisFlex-starter = { group = "com.mybatis-flex", name = "mybatis-flex-spring-boot3-starter", version.ref = "mybatisFlexVersion" }
+```
diff --git a/docs/en-gb/blog/contents/postgresql-zhparser-fuzzy-search.md b/docs/en-gb/blog/contents/postgresql-zhparser-fuzzy-search.md
new file mode 100644
index 0000000..fca75a6
--- /dev/null
+++ b/docs/en-gb/blog/contents/postgresql-zhparser-fuzzy-search.md
@@ -0,0 +1,212 @@
+---
+title: Accelerating Fuzzy Search in PostgreSQL with Tokenisation
+tags:
+ - postgresql
+ - zhparser
+ - full-text-search
+ - performance
+author:
+ name: Siu Jam Oh
+ email: jamo.siu@gmail.com
+---
+
+## Background and Challenges
+
+As our business data surpassed **2 million rows**, traditional `LIKE '%keyword%'` fuzzy queries triggered frequent database I/O alerts, with query response times degrading from milliseconds to seconds. To improve search efficiency and support Chinese semantics, we decided to introduce the `zhparser` extension for full-text search.
+
+## Evolution Path and Environment Adaptation
+
+This implementation went through four key phases, each addressing distinct technical challenges:
+
+### CentOS 7.9 VM (Feasibility Validation)
+
+- **Goal**: Validate the compatibility of `SCWS` + `zhparser` on older systems.
+- **Core Action**: Manually compiled `postgresql-16.2` from source in a CentOS 7.9 environment, got the extension working end-to-end.
+
+**Conclusion**: Confirmed significant performance improvements from the tokenisation approach for Chinese search.
+
+### Local Docker Container (Containerisation Exploration)
+
+- **Goal**: Initial testing in a complete local system.
+- **Core Action**: Injected binary `.so` files via `docker cp`, resolved `ldconfig` dynamic library path visibility issues.
+- **Discovery**: Identified that **missing dictionary files** cause tokenisation to degrade into single-character (particle-level) tokenisation — a critical failure point.
+
+### EulerOS 2.0 Test Server (Self-Compiled Environment Adaptation)
+
+- **Goal**: Adapt to the production OS architecture (x86_64) and self-compiled PostgreSQL installation.
+- **Core Issue**: Resolved `libscws.so.1` loading errors.
+- **Key Solutions**:
+ - Ensured the `postgres` runtime user has access permissions to `/usr/local/scws/lib`.
+ - Modified `systemd` service environment variables or created `/usr/lib64` symlinks to force refresh library search paths.
+
+### Production Deployment Preparation (Final Tuning)
+
+- **Goal**: Ensure query stability at 2M+ data volume.
+- **Optimisation**: Addressed cases where non-semantic fragments (e.g., "古唐合") returned no results by establishing a "full-text search first + `pg_trgm` index assist" degraded query strategy.
+
+## Core Installation and Configuration Steps (Self-Compiled Environments)
+
+### Installing the `SCWS` Tokenisation Engine
+
+SCWS is the underlying core dependency of `zhparser` and must be installed first.
+
+1. **Download and Extract**: Download the source package (e.g., `scws-1.2.3`).
+2. **Compile and Install**:
+
+ ```bash
+ ./configure --prefix=/usr/local/scws
+ make && make install
+ ```
+
+3. **Verify the Library**: Ensure `/usr/local/scws/lib/libscws.so.1` exists.
+
+### Compiling and Installing `zhparser`
+
+This step requires `pg_config` from the self-compiled PostgreSQL installation.
+
+1. **Get the Source**: Clone the `zhparser` project from GitHub.
+2. **Compile with Specified Path**:
+
+ ```bash
+ # Ensure pg_config is in PATH, or specify manually
+ make USE_PGXS=1 PG_CONFIG=/usr/local/pgsql/bin/pg_config
+ make USE_PGXS=1 PG_CONFIG=/usr/local/pgsql/bin/pg_config install
+ ```
+
+ *Note: The `install` step automatically places `zhparser.so` into PG's `pkglibdir` and extension scripts into the `extension` directory.*
+
+### Resolving Dynamic Library Dependencies
+
+1. **Refresh System Cache**:
+
+ ```bash
+ echo "/usr/local/scws/lib" > /etc/ld.so.conf.d/scws.conf
+ ldconfig
+ ```
+
+2. **Permission Check**: Ensure the OS user running `postgres` has `rx` permission on `/usr/local/scws/lib`.
+3. **Force Symlink (Alternative)**: If `ldconfig` fails, symlink the library file to `/usr/lib64`.
+
+### Restarting the Database
+
+After modifying system shared library configuration, the PostgreSQL process must be restarted to reload environment variables and linked libraries.
+
+```bash
+## Restart using pg_ctl (paths may vary for self-compiled installations)
+/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data restart
+
+## Or restart via systemd (if registered as a service)
+systemctl restart postgresql
+```
+
+### Database-Level Initialisation
+
+Connect to `psql` and run the logical configuration:
+
+```sql
+-- Create the extension
+CREATE EXTENSION zhparser;
+
+-- Create a full-text search configuration and bind the tokeniser
+CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
+
+-- Add token mappings
+ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l,t,b WITH simple;
+
+-- [Optional] Specify the dictionary path for self-compiled installations
+-- ALTER DATABASE postgres SET zhparser.dict_path = '/usr/local/scws/etc/dict.utf8.xdb';
+```
+
+## Performance Analysis and Pitfalls
+
+### Index Performance Bottleneck Analysis
+
+During testing, it was found that even exact queries suffered from `Bitmap Index Scan` due to an improperly designed composite index (with `create_time` as the leading column), resulting in query times as high as **482 ms**.
+
+- **Improvement**: Created single-column **B-tree** indexes on frequently searched columns, reducing response time to under **10 ms** with `Index Scan`.
+
+### GIN Index and Non-Semantic Matching
+
+- **Cross-Word Truncation**: The tokenisation engine is semantic-based, so truncated strings like "古唐合" may fail to match with `@@` due to tokenisation boundaries.
+- **Mitigation Strategy**: Adopt a "waterfall search" approach. Full-text search (FTS) first; if the result set is empty, automatically degrade to `LIKE` fuzzy queries, assisted by `pg_trgm` indexing.
+
+## Final Deployment Strategy: Dual-Track Parallel Retrieval
+
+After analysing the data, we found that approximately 1.24% of account names contain non-standard Simplified Chinese characters, and some company names in the database are unusual enough to cause search failures. We adopted a "stepwise degradation" strategy:
+
+- **Step 1: Full-Text Search (Fast Track)**: Use GIN index for `@@` matching.
+- **Step 2: Result Evaluation**: If the result set is empty, check whether the search term contains letters or suspected Traditional Chinese characters.
+- **Step 3: Fuzzy Fallback (Safe Fallback)**: Execute `LIKE '%keyword%'`. Although slower, since this serves as a "gap-fill" logic triggered only ~1% of the time, it won't impose overall system pressure.
+
+## Search Optimisation: Integrating a Custom Business Lexicon
+
+To address issues like company brand names being incorrectly segmented by full-text search (e.g., "元一" being split into a numeral and a quantifier), we built an automated maintenance pipeline from data extraction to index rebuild.
+
+### Lexicon Extraction and Preprocessing
+
+Leverage the structural parsing capabilities of **`companynameparser`** to strip region names and industry suffixes, and use **`jieba`** for semantic validation to ensure core brand name integrity:
+
+- **Extraction Logic**: Traverse all `buyer_unique_name` values via a Python script, extracting the core `brand` field.
+- **Weight Compensation**: For words prone to fragmentation (e.g., those containing "元", "一", "三"), manually boost TF (term frequency weight) to **50.0–60.0** to ensure their priority overrides built-in quantifier rules.
+- **Output Specification**: Produce SCWS-compliant 4-field `UTF-8` text (WORD, TF, IDF, ATTR). Use tab `\t` separators to avoid parsing anomalies.
+
+### Lexicon Compilation and Deployment
+
+:::tip
+Users compiling `xdb` binary dictionary files on Windows can visit OnixByte’s [GitHub](https://github.com/onixbyte/scws/releases/tag/1.2.3) or [GitLab](https://git.onixbyte.cn/onixbyte/scws/-/releases/1.2.3) pages to download the native scws command-line tool for Windows, pre-compiled using MingW.
+:::
+
+Convert the text dictionary to SCWS's efficient binary format (XDB):
+
+1. **Compile the Binary Dictionary**:
+
+ ```bash
+ # Use scws-gen-dict to generate an encrypted binary lexicon
+ /usr/local/scws/bin/scws-gen-dict -i custom_company.txt -o /usr/local/scws/etc/custom_company.xdb -c utf8
+ ```
+
+2. **File Distribution and Permissions**: Move the generated `.xdb` file to the tokenisation data directory and ensure the `postgres` user has read permission:
+
+ ```bash
+ cp custom_company.xdb /usr/local/pgsql/share/tsearch_data/
+ chown postgres:postgres /usr/local/pgsql/share/tsearch_data/custom_company.xdb
+ ```
+
+### Database Parameter Configuration
+
+Modify `postgresql.conf` to force-load `zhparser` and its custom extension lexicon:
+
+```plain text
+## Preload the extension library (requires restart to take effect)
+shared_preload_libraries = 'zhparser'
+
+## Load custom external dictionaries (use paths relative to tsearch_data)
+zhparser.extra_dicts = 'custom_company.xdb'
+```
+
+### Hot Index Rebuild and Verification
+
+Since tokenisation rules have changed, existing data must be semantically synchronised via index rebuild:
+
+**Physically Restart the Service**:
+
+```bash
+su - postgres -c "/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data restart"
+```
+
+**Online Index Rebuild**: Use the `CONCURRENTLY` keyword to refresh the GIN index without blocking DML operations on 400K rows:
+
+```bash
+REINDEX INDEX CONCURRENTLY index_name;
+```
+
+**Tokenisation Effectiveness Verification**:
+
+```sql
+-- Expected part-of-speech should show as n (noun), not x (unknown)
+SELECT * FROM ts_debug('chinese', '元一能源');
+```
+
+**Optimisation Notes:**
+- **Explicit Weight Compensation**: This is the key technique that resolved the "元一" tokenisation failure (shown as `x`).
+- **Distinguish Restart from Reload**: `shared_preload_libraries` must be activated via `restart`, not a simple reload.
diff --git a/docs/en-gb/blog/contents/quartile-method.md b/docs/en-gb/blog/contents/quartile-method.md
new file mode 100644
index 0000000..dafad33
--- /dev/null
+++ b/docs/en-gb/blog/contents/quartile-method.md
@@ -0,0 +1,22 @@
+---
+title: The Quartile Method
+tags:
+ - statistics
+ - algorithm
+ - data-analysis
+ - math
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+The quartile method is a commonly used statistical technique primarily employed for data analysis and presentation. The method divides a data set into four equal parts, each containing one quarter of the data. The key statistics include the first quartile (Q1), second quartile (Q2, the median), and third quartile (Q3).
+
+- The first quartile (`Q1`), also known as the lower quartile, is the value at the 25th percentile of a data set sorted in ascending order.
+- The second quartile (`Q2`), also known as the median, is the value at the 50th percentile of a data set sorted in ascending order.
+- The third quartile (`Q3`), also known as the upper quartile, is the value at the 75th percentile of a data set sorted in ascending order.
+- The interquartile range (`IQR`) is the difference between the third quartile and the first quartile, used to measure the dispersion of the middle 50% of data. The formula is IQR = Q3 - Q1. The IQR is commonly used in constructing box plots, an effective way to describe data distribution, particularly useful for identifying outliers.
+
+Upper bound = Q3 + 1.5 × IQR.
+
+Lower bound = Q1 - 1.5 × IQR.
diff --git a/docs/en-gb/blog/contents/setup-ldap-service.md b/docs/en-gb/blog/contents/setup-ldap-service.md
new file mode 100644
index 0000000..43c789b
--- /dev/null
+++ b/docs/en-gb/blog/contents/setup-ldap-service.md
@@ -0,0 +1,140 @@
+---
+title: Setting Up an LDAP Service
+tags:
+ - ldap
+ - openldap
+ - authentication
+ - linux
+ - devops
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+Setting up an LDAP (Lightweight Directory Access Protocol) server is a core step in implementing enterprise-level **centralised identity authentication** and **permission management**. The most commonly used open-source implementation is **OpenLDAP**.
+
+Below are detailed steps for setting up an OpenLDAP server on Debian/Ubuntu-based Linux systems.
+
+## Environment Preparation and Installation
+
+Before starting, ensure your system packages are up to date and the hostname is properly configured.
+
+```bash
+## Update the system
+sudo apt update && sudo apt upgrade -y
+
+## Install OpenLDAP and management tools
+## slapd is the daemon, ldap-utils is the command-line client tool
+sudo apt install slapd ldap-utils -y
+```
+
+> During installation, you will be prompted to set the **LDAP administrator password**. Be sure to remember this password — it will be used frequently during configuration.
+
+## Configuring the OpenLDAP Server
+
+Although the installation performs some initial setup, we typically need to customise the configuration for a specific domain (e.g., `example.com`).
+
+### Reconfigure slapd
+
+Run the following command to enter the interactive configuration interface:
+
+```bash
+sudo dpkg-reconfigure slapd
+```
+
+**Configuration recommendations**:
+
+1. **Omit OpenLDAP server configuration?** Choose **No**.
+2. **DNS domain name:** Enter your domain (e.g., `centre.example.com`). This determines your Base DN, such as `dc=centre,dc=example,dc=com`.
+3. **Organization name:** Enter your organisation name.
+4. **Administrator password:** Enter the administrator password you set earlier.
+5. **Database backend:** **MDB** is recommended.
+6. **Remove database when slapd is purged?** Choose **No**.
+7. **Move old database?** Choose **Yes**.
+
+## Understanding the LDAP Hierarchy
+
+LDAP data is stored in a **tree structure**. To facilitate management, we typically create two "Organisational Units" (OUs): one for users (People) and one for groups (Groups).
+
+## Creating Organisational Units (OUs)
+
+In LDAP, we use **LDIF** (LDAP Data Interchange Format) files to add or modify directory entries.
+
+Create a file named `base.ldif`:
+
+```text
+## Create the users organisational unit
+dn: ou=people,dc=centre,dc=example,dc=com
+objectClass: organizationalUnit
+ou: people
+
+## Create the groups organisational unit
+dn: ou=groups,dc=centre,dc=example,dc=com
+objectClass: organizationalUnit
+ou: groups
+```
+
+**Import the data:**
+
+```bash
+## Import the LDIF file into the database as the administrator
+ldapadd -x -D "cn=admin,dc=centre,dc=example,dc=com" -W -f base.ldif
+```
+
+## Adding Users and Groups
+
+Create a file named `groups.ldif` to define a new group:
+
+```text
+## Define a new group
+dn: cn=developers,ou=groups,dc=centre,dc=example,dc=com
+objectClass: inetOrgGroup
+cn: developers
+```
+
+Create a file named `users.ldif` to define a new user:
+
+```text
+## Define a new user
+dn: uid=jbloggs,ou=people,dc=centre,dc=example,dc=com # The Distinguished Name (DN) of this entry.
+objectClass: inetOrgPerson # Object class — inetOrgPerson represents an internet organisation person. It enables common contact attributes such as email, displayName, telephoneNumber, etc.
+objectClass: posixAccount # Makes this entry compatible with Unix/Linux system accounts. With it, the user can log into Linux servers and has a UID, GID, and home directory.
+objectClass: shadowAccount # Used to manage password ageing (expiry, change warnings, etc.), corresponding to /etc/shadow functionality in Linux.
+uid: jbloggs # The user's login name (User ID). This is typically what you enter on the Linux login screen.
+sn: Bloggs # Surname. Required by the inetOrgPerson class.
+givenName: Joe # First name.
+cn: Joe Bloggs # Common Name. The standard display name for an LDAP entry.
+displayName: Joe Bloggs # The friendly name displayed in graphical interfaces or email clients.
+uidNumber: 10000 # The user's numeric ID in the Linux system.
+gidNumber: 5000 # The numeric ID of the user's primary group.
+userPassword: {SSHA}password-hash-or-plaintext # The user's encrypted password.
+homeDirectory: /home/jbloggs # The path to the user's home directory after logging into Linux.
+loginShell: /bin/bash # The shell environment the user gets after logging in.
+```
+
+> If you plan to integrate **GitLab**, **Jenkins**, or a **VPN** later, they typically search the `uid` attribute to verify login names.
+
+### FAQ
+
+#### If the user doesn't need server login permissions, can the `objectClass: posixAccount` be removed?
+
+**Yes, it can be completely removed**, but you need to be aware of the "binding relationships" between attributes.
+
+If you only need this user for web application logins (e.g., GitLab, Jenkins, Wiki) or as an email contact, and they don't need to log into a Linux server via SSH or console, removing `posixAccount` is the more standard approach.
+
+When you remove `objectClass: posixAccount`, the following attributes **must also be deleted**, as they belong to that class's mandatory or optional attributes:
+
+- `uidNumber`
+- `gidNumber`
+- `homeDirectory`
+- `loginShell`
+
+Additionally, `shadowAccount` is also typically associated with system logins — if you don't need to manage Linux password expiry policies, it can also be removed.
+
+## Follow-up Suggestions and Management Tools
+
+Command-line LDAP management can be cumbersome. The following tools are recommended for visual administration:
+
+- **phpLDAPAdmin**: A web-based management interface, ideal for quick onboarding.
+- **Apache Directory Studio**: A powerful cross-platform desktop client, suitable for complex architecture design.
+- **Security Hardening**: By default, LDAP transmits data in plain text. It is recommended to configure **LDAPS (LDAP over SSL/TLS)** to encrypt communication on port 636.
diff --git a/docs/en-gb/blog/contents/use-json-in-mysql.md b/docs/en-gb/blog/contents/use-json-in-mysql.md
new file mode 100644
index 0000000..b103dd4
--- /dev/null
+++ b/docs/en-gb/blog/contents/use-json-in-mysql.md
@@ -0,0 +1,89 @@
+---
+title: Using JSON in MySQL
+tags:
+ - mysql
+ - json
+ - database
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+MySQL (since version 5.7) **does not directly support a data type called `jsonb`**. `jsonb` is a data type specific to PostgreSQL, which stores JSON data in a binary format with pre-parsing for faster access and manipulation during queries.
+
+However, MySQL's `JSON` data type is functionally and internally similar to PostgreSQL's `jsonb` in many respects, particularly when it comes to querying data.
+
+The `JSON` data type in MySQL was introduced in MySQL 5.7 and has the following characteristics:
+
+1. **Binary Storage**: Like PostgreSQL's `jsonb`, MySQL's `JSON` type data is stored in an **internal binary format** rather than as a plain text string. This makes reading and manipulating JSON data more efficient, as the database does not need to parse text-format JSON strings on every query.
+2. **Automatic Validation**: When you insert or update a `JSON` column, MySQL automatically validates that its content is a valid JSON document. If not, it throws an error.
+3. **Optimised Storage**: The binary format is also space-optimised, typically more compact than storing JSON in raw text format.
+
+MySQL provides a powerful set of functions and operators for querying and manipulating `JSON` data, very similar to what you'd expect from `jsonb`:
+
+1. **`->` (JSON Extract Operator)**: Extracts a value from a JSON document. It returns a JSON value.
+
+ ```sql
+ SELECT my_json_column->'$.key' FROM my_table;
+ -- Example: extract the name property of a user object
+ -- Assuming my_json_column stores {'user': {'name': 'Alice'}}
+ SELECT json_data->'$.user.name' FROM my_table;
+ ```
+
+2. **`->>` (JSON Unquote Operator)**: Extracts a value from a JSON document and **automatically unquotes it**, typically returning a scalar value (e.g., string, number). This is equivalent to `JSON_UNQUOTE(JSON_EXTRACT(...))`.
+
+ ```sql
+ SELECT my_json_column->>'$.key' FROM my_table;
+ -- Example: extract the name property of a user object (returns the string 'Alice' directly)
+ SELECT json_data->>'$.user.name' FROM my_table;
+ ```
+
+3. **`JSON_EXTRACT(json_doc, path, ...)`**: Explicitly extracts data from a JSON document.
+
+ ```sql
+ SELECT JSON_EXTRACT(my_json_column, '$.key') FROM my_table;
+ ```
+
+4. **`JSON_CONTAINS(json_doc, candidate, path)`**: Checks whether a JSON document contains a specified value.
+
+ ```sql
+ -- Check whether the tags array contains 'backend'
+ -- Assuming my_json_column stores {'tags': ['frontend', 'backend']}
+ SELECT * FROM my_table WHERE JSON_CONTAINS(json_data->'$.tags', '"backend"');
+ ```
+
+5. **`JSON_SEARCH(json_doc, one_or_all, search_str, escape_char, path, ...)`**: Returns the path to a specified string within a JSON document.
+
+ ```sql
+ -- Find the path to a value of 'test'
+ SELECT JSON_SEARCH(my_json_column, 'one', 'test') FROM my_table;
+ ```
+
+6. **`JSON_TABLE(json_doc, path COLUMNS ... )` (MySQL 8.0 and later)**: A very powerful function that "expands" JSON data into relational rows and columns, ideal for complex queries and reporting.
+
+ ```sql
+ -- Assuming json_data stores {'items': [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}]}
+ SELECT *
+ FROM my_table,
+ JSON_TABLE(json_data, '$.items[*]' COLUMNS(
+ itemId INT PATH '$.id',
+ itemName VARCHAR(50) PATH '$.name'
+ )) AS jt;
+ ```
+
+Like PostgreSQL's `jsonb`, efficient querying on JSON fields typically requires indexing. Since the content of JSON fields is dynamic, MySQL does not directly support creating traditional B-tree indexes on a specific internal path of a JSON field. However, you can achieve this through **Virtual Generated Columns**:
+
+1. **Create a Virtual Column**: Define a virtual column whose value is extracted from a specific path in the JSON field.
+
+ ```sql
+ ALTER TABLE my_table
+ ADD COLUMN user_name VARCHAR(255) AS (json_data->>'$.user.name') VIRTUAL;
+ ```
+
+2. **Create an Index on the Virtual Column**: This way, when you query `WHERE json_data->>'$.user.name' = 'Alice'`, the MySQL optimiser can use the `idx_user_name` index, significantly improving query performance.
+
+ ```sql
+ CREATE INDEX idx_user_name ON my_table (user_name);
+ ```
+
+Although MySQL does not have the exact name `jsonb`, its `JSON` data type provides highly similar functionality: binary storage optimisation, automatic validation, and rich query operators and functions. By combining virtual columns with indexes, MySQL can deliver query performance and flexibility comparable to PostgreSQL's `jsonb` when working with JSON data.
diff --git a/docs/en-gb/blog/contents/version-control-and-code-review.md b/docs/en-gb/blog/contents/version-control-and-code-review.md
new file mode 100644
index 0000000..335a473
--- /dev/null
+++ b/docs/en-gb/blog/contents/version-control-and-code-review.md
@@ -0,0 +1,38 @@
+---
+title: Version Control and Code Review
+tags:
+ - git
+ - code-review
+ - best-practice
+ - workflow
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+## GitFlow Workflow
+
+Version control will use the GitFlow branching model, consisting of `main`, `develop`, `feature`, `release`, and
+`hotfix` branches.
+
+- `main`: Production-ready code. Only `release` and `hotfix` branches are merged into `main`.
+- `develop`: Integration branch for upcoming features.
+- `feature/*`: Branches for new features, branched off `develop`.
+- `release/*`: Branches for preparing new production releases, branched off `develop`.
+- `hotfix/*`: Branches for urgent production bug fixes, branched off `main`.
+
+## Pull Requests/Merge Requests
+
+All code changes (except direct pushes to feature branches) must be submitted via pull requests.
+
+## Code Review
+
+- Each pull request must be reviewed by at least one other developer.
+- Reviewers are responsible for checking compliance with these coding standards, code quality, logical correctness, and
+ test coverage.
+- IntelliJ IDEA's integrated code analysis tools should be run locally before creating a PR.
+
+## Commit Messages
+
+Write clear, concise, and descriptive commit messages that explain what was changed and why. If possible, follow the
+Conventional Commits format (e.g., `feat: add user registration endpoint`).
diff --git a/docs/zh-hans/blog/contents/cooking-seasoning-guide.md b/docs/zh-hans/blog/contents/cooking-seasoning-guide.md
new file mode 100644
index 0000000..2497008
--- /dev/null
+++ b/docs/zh-hans/blog/contents/cooking-seasoning-guide.md
@@ -0,0 +1,31 @@
+---
+title: 炒菜调料指南
+tags:
+ - cooking
+ - cheatsheet
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+## 调料投放时机
+
+| 调料类型 | 放调料时机 | 适用菜品 | 作用 |
+|--------------|----------|----------------|---------------------|
+| **盐** | 最后放 | 菜叶子 | 防止菜叶变软出水,保证口感干爽脆嫩 |
+| | 中间放 | 土豆丝、豆角、蒜苔等 | 更好入味 |
+| **味精、生抽、蚝油** | 偏后放 | 各类需要增鲜提香的菜品 | 增鲜提香,避免高温破坏鲜味和香味 |
+| **料酒** | 和食材一起放 | 需要去腥的食材 | 焯水时去腥效果更好 |
+| | 锅温最高的时候放 | 需要炒菜去腥的食材 | 炒菜时高温促进酒气挥发,炝锅去腥效果好 |
+| **醋** | 提前放 | 酸辣土豆丝、酸辣大白菜 | 使土豆丝变脆更入味 |
+| | 出锅前锅边醋 | 辣椒炒肉等需要猛火爆炒类菜品 | 大火炝锅增香 |
+| **老抽** | 炒半熟后放 | 需要上色的菜品 | 达到最佳上色效果 |
+
+## 快速参考
+
+| 调料 | 投放时机 | 作用 | 示例 |
+|-----------------|----------------|------------------------|------------------------|
+| **盐** | 出锅前 10 - 15 秒放 | 避免提前放盐导致菜叶出水、变软,保持脆嫩口感 | 炒生菜、菠菜时,关火前撒盐翻炒均匀 |
+| **蒜末 / 姜末** | 热油后先放 | 爆香提味,激发香味 | 油热后下蒜末炝锅,再放青菜翻炒 |
+| **生抽 / 蚝油**(可选) | 盐之后放 | 增鲜提味,少量即可,避免盖过蔬菜原味 | 炒上海青时,加盐后滴 1 - 2 滴生抽翻炒 |
+| **食用油** | 热锅热油 | 油热后快速炒,锁住水分 | 大火快炒时,油稍多一点,油温要高 |
diff --git a/docs/zh-hans/blog/contents/docker-deployment-standards.md b/docs/zh-hans/blog/contents/docker-deployment-standards.md
new file mode 100644
index 0000000..6ece16f
--- /dev/null
+++ b/docs/zh-hans/blog/contents/docker-deployment-standards.md
@@ -0,0 +1,16 @@
+---
+title: Docker 部署规范
+tags:
+ - docker
+ - deployment
+ - standards
+ - best-practice
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+- **Dockerfiles**: 为应用程序提供 `Dockerfile`,实现容器化部署。
+- **轻量级镜像**: 通过使用适当的基础镜像和多阶段构建,力求实现轻量级 Docker 镜像。
+- **配置**: 确保环境特定配置(例如,数据库连接字符串、外部服务 URL)通过注入到 Docker 容器中的环境变量进行管理。
+- **日志记录**: 配置容器化日志记录,将输出发送到 `stdout` 和 `stderr`,以便日志聚合系统轻松收集。
diff --git a/docs/zh-hans/blog/contents/ecmascript-2025-syntax-sugar.md b/docs/zh-hans/blog/contents/ecmascript-2025-syntax-sugar.md
new file mode 100644
index 0000000..066a1f2
--- /dev/null
+++ b/docs/zh-hans/blog/contents/ecmascript-2025-syntax-sugar.md
@@ -0,0 +1,55 @@
+---
+title: ECMAScript 2025 语法糖大全
+tags:
+ - javascript
+ - ecmascript
+ - pattern-matching
+ - frontend
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+## 模式匹配
+
+### 传统写法
+
+```javascript
+function processResponse(response) {
+ if (response.status === 200 && response.data) {
+ return { success: true, data: response.data };
+ } else if (response.status === 404) {
+ return { success: false, error: 'Not found' };
+ } else if (response.status >= 500) {
+ return { success: false, error: 'Server error' };
+ } else {
+ return { success: false, error: 'Unknown error' };
+ }
+}
+```
+
+### 模式匹配写法
+
+```javascript
+function processResponse(response) {
+ return match (response) {
+ when ({ status: 200, data }) -> ({ success: true, data })
+ when ({ status: 404 }) -> ({ success: false, error: 'Not found' })
+ when ({ status: status if status >= 500 }) -> ({ success: false, error: 'Server error' })
+ default -> ({ success: false, error: 'Unknown error' })
+ };
+}
+```
+
+### 数组长度分支也能优雅处理
+
+```javascript
+function handleArray(arr) {
+ return match (arr) {
+ when ([]) -> "Empty array"
+ when ([first]) -> `Only one element: ${first}`
+ when ([first, second]) -> `Two elements: ${first}, ${second}`
+ when ([first, ...rest]) -> `First element: ${first}, others: ${rest.length} items`
+ };
+}
+```
diff --git a/docs/zh-hans/blog/contents/email-like-a-boss.md b/docs/zh-hans/blog/contents/email-like-a-boss.md
new file mode 100644
index 0000000..1ebac29
--- /dev/null
+++ b/docs/zh-hans/blog/contents/email-like-a-boss.md
@@ -0,0 +1,40 @@
+---
+title: 像老板一样写邮件
+tags:
+ - communication
+ - email
+ - soft-skill
+ - career
+ - productivity
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+工作中的邮件沟通不仅仅是传递信息,更是建立信任、塑造专业形象的过程。同样一件事情,换一种表达方式,给人的印象可能是天壤之别。
+
+以下整理了 9 个常见邮件场景中「低姿态表达」与「高阶表达」的对比,让你的邮件读起来更自信、更专业。
+
+## 场景速查表
+
+| 场景 | ❌ 别用(听起来……) | ✅ 改用(听起来……) | 为什么有效 |
+|----------|--------------------------------------------------------------|----------------------------------------------------------|-----------------------------------------------|
+| 回复晚了 | **Sorry for the delay** ` 分割。
+
+ ```java
+ /**
+ * This is the first paragraph of the Javadoc.
+ *
+ * This is the second paragraph of the Javadoc.
+ */
+ ```
+
+ - 每个段落的内容必须是语法正确且含义完整的段落,遵循英文句子规范。
+ - 所有参数(`@param`)、返回值(`@return`)、异常抛出(`@throws`)及参考(`@see`)的解释需要遵循下面的规则:
+ - 无需使用大写字母开头
+ - 若描述的最后为陈述句,则无需使用标点符号结尾
+
+ ```java
+ /**
+ * Returns the greater of two {@code int} values. That is, the
+ * result is the argument closer to the value of
+ * {@link Integer#MAX_VALUE}. If the arguments have the same value,
+ * the result is that same value.
+ *
+ * @param a an argument
+ * @param b another argument
+ * @return the larger of {@code a} and {@code b}
+ */
+ public static int max(int a, int b) {
+ return (a >= b) ? a : b;
+ }
+ ```
+
+## 依赖管理 (Gradle)
+
+- **构建文件**: `build.gradle.kts` 必须组织良好,对插件、依赖项和任务有清晰的划分。
+- **依赖版本**: 必须在 `gradle/libs.versions.toml` 文件中集中管理依赖项版本,以确保一致性。
+- **插件管理**: 显式声明 Gradle 插件及其版本。
+- **避免不必要的依赖项**: 仅包含项目实际使用的依赖项。定期审查并清理未使用的依赖项。
+
+## API 设计 (RESTful)
+
+- **RESTful 原则**: 遵循 RESTful 原则:
+ - **资源**: 将数据建模为可通过 URI 标识的资源。
+ - **HTTP 方法**: 适当地使用标准 HTTP 方法(GET 用于检索,POST 用于创建,PUT 用于完全更新,PATCH 用于部分更新,DELETE 用于删除)。
+ - **无状态性**: API 应是无状态的;客户端向服务器发送的每个请求都必须包含理解请求所需的所有信息。
+- **URI**:
+ - 集合资源使用复数名词(例如,`/users`,`/products`)。
+ - URI 中使用连字符以提高可读性(例如,`/user-accounts`)。
+ - 避免在 URI 中使用动词(例如,使用 `/users` 而不是 `/getAllUsers`)。
+- **状态码**: 使用适当的 HTTP 状态码来指示 API 请求的结果(例如,`200 OK`、`201 Created`、`204 No Content`、`400 Bad Request`、`401 Unauthorized`、`403 Forbidden`、`404 Not Found`、`500 Internal Server Error`)。
+- **响应格式**: JSON 是首选的响应格式。
+- **版本控制**: 建议在需要版本控制的接口中使用 Header 参数 `X-Endpoint-Version` 控制接口版本。
+
+## Spring Boot 最佳实践与分层架构
+
+- **分层架构 (MVC 配合 Manager 层)**: 我们的后端应用程序遵循严格的多层架构,确保职责清晰分离,并提高可维护性和可测试性。各层及其职责如下:
+ - **控制器层 (Controller Layer)**: 位于 `controller` 包中。负责暴露 RESTful API,处理 HTTP 请求,并将请求参数/主体映射到服务层调用。控制器应保持轻量,主要关注输入验证(使用 DTOs)和协调对 `Service` 层的调用。
+ - **服务层 (Service Layer)**: 位于 `service` 包中。此层封装了核心业务逻辑。服务层向 `Controller` 层提供可以直接使用的 API,抽象业务流程和事务管理。服务层协调对 `Manager` 层的调用以执行业务操作。
+ - **管理器层 (Manager Layer)**: 位于 `manager` 包中。此层提供原子化的业务操作,可由 `Service` 层组合使用。管理器通常处理更复杂的业务逻辑,可能涉及在更细粒度级别上与多个仓库或其他外部系统进行交互。
+ - **仓库层 (Repository Layer) (MyBatis)**: 位于 `repository` 包和 `src/main/resources/repository`(用于 XML 映射文件)中。此层负责提供原子化的数据库交互操作。
+
+ **层间通信策略**:
+ - **每一层内的组件仅可调用直接位于其下方的层中的组件。**
+ - **严格禁止跨层调用(例如,Controller 直接调用 Manager,Service 直接调用 Repository)。**
+ - **严格禁止向上调用(例如,Service 调用 Controller)。**
+ - **横向调用(例如,Service A 调用 Service B 处理不同领域)应仔细考虑,通常表明需要将共享逻辑重构到 `Manager` 或为该共享关注点重构一个专用 `Service` 中。**
+
+ - **配置**: 优先选择 `application.yml` 进行配置属性,而不是 `application.properties`,以获得更好的可读性和分层结构。使用 `@ConfigurationProperties` 进行类型安全配置。
+ - **依赖注入**: 所有依赖项都使用构造函数(强制依赖)或 Setter(非强制依赖)注入。避免在字段上使用 `@Autowired`,因为它会使测试更困难并隐藏依赖项。
+ - **服务**: 业务逻辑类使用 `@Service` 进行注解。服务应保持精简,并专注于协调领域操作,这些操作通常涉及通过 `Manager` 层组件进行业务逻辑处理,以及通过 `Manager` 或直接与 MyBatis 仓库进行交互(如果该特定操作不需要中间 Manager 逻辑,尽管对于所有仓库交互,Manager 层是首选,符合分层架构定义)。
+
+- **仓库 (MyBatis 与 JPA)**:
+ - **项目使用 MyBatis 及 JPA 进行数据库操作**。`repository` 包及 `mapper` 包中的仓库接口定义了数据访问契约。
+ - 相应的 SQL 定义在位于 `src/main/resources/mapper` 的 XML 映射文件中管理。
+ - 数据操作约定:
+ - 对于简单数据库操作,使用 JPA。
+ - 对于复杂数据库操作,使用 MyBatis。
+ - 当进行分页查询时,页码应从 0 开始(*兼容 Spring Data JPA*)。
+ - **数据操作方法命名约定**:
+ - 对于**查询数据列表**:方法**必须**以 `selectListBy` 开头,紧随其后是筛选条件(例如,`selectListByUserId`、`selectListByDepartmentIdAndStatus`)。这些方法也必须包含一个 `PageRequest` 参数用于分页。
+ - 对于查询**单个数据记录**:方法**必须**以 `selectOne` 开头(例如,`selectOneById`、`selectOneByUsername`)。
+ - 对于**保存新数据**:方法**必须**命名为 `save`,Mapper 方法的返回值必须是 `int`(受影响的行数)。
+ - 对于**更新现有数据**:方法**必须**命名为 `update`,Mapper 方法的返回值必须是 `int`(受影响的行数)。
+ - 对于**删除数据**:方法**必须**以 `deleteBy` 开头,清晰地指明删除的依据(例如,`deleteById`)。Mapper 方法的返回值必须是 `int`(受影响的行数)。
+
+- **控制器**:
+ - 使用 `@RestController` 注解 REST 控制器。
+ - 使用 `@GetMapping`、`@PostMapping` 等将 HTTP 方法(GET、POST、PUT、DELETE)映射到适当的控制器方法。
+ - 确保请求和响应负载定义明确(DTOs)并有文档说明。
+ - 控制器应主要处理 HTTP 请求/响应映射,并将实际业务逻辑委托给服务层。
+
+- **DTOs (数据传输对象)**: 定义单独的 DTOs 用于请求和响应主体,以将内部领域模型与 API 契约解耦。在 DTOs 上使用验证注解(例如,`@Valid`、`@NotNull`、`@Size`)。
+
+- **日志 (Slf4j & Logback)**:
+ - 应用程序中的所有日志记录都使用 `org.slf4j.Logger`。
+ - 配置 `application-dev.yml` 以设置日志级别、Appender 和输出格式。
+ - 日志消息应具有描述性并提供足够的上下文。避免记录敏感信息。
+ - 使用参数化日志记录以提高性能并防止字符串拼接开销(例如,`log.debug("Processing user: {}", userId);`)。
+ - 标准日志级别:`ERROR`、`WARN`、`INFO`、`DEBUG`、`TRACE`。
+
+## 项目结构
+
+后端应用程序遵循结构化的 Gradle 项目布局。核心应用程序应清晰地划分为各种子包。
+
+```text
+backend-application
+├── build.gradle.kts // 项目的主 Gradle 构建脚本
+├── config // 外部配置目录
+│ ├── application-dev.yml // 开发环境的应用程序属性
+│ └── application-prod.yml.example // 生产环境属性示例(待复制和配置)
+├── database // 数据库相关文件
+│ └── init.d // 数据库初始化脚本
+│ └── init-en_GB.sql // 使用指定语言的数据库模式和初始数据的 SQL 脚本(英式英语区域设置)
+├── gradle // Gradle Wrapper 和配置文件
+│ ├── libs.versions.toml // 集中管理依赖版本(Gradle 版本目录)
+│ └── wrapper // Gradle Wrapper 文件
+│ ├── gradle-wrapper.jar
+│ └── gradle-wrapper.properties
+├── gradle.properties // 项目特定的 Gradle 属性
+├── gradlew // Gradle Wrapper 可执行文件 (Linux/macOS)
+├── gradlew.bat // Gradle Wrapper 可执行文件 (Windows)
+├── settings.gradle.kts // 多项目构建的 Gradle 设置(如果适用)
+└── src
+ ├── main
+ │ ├── java
+ │ │ └── com/onixbyte/application // 应用程序的根包
+ │ │ ├── Application.java // Spring Boot 应用程序主入口点
+ │ │ ├── config // Spring 配置类
+ │ │ ├── constant // 定义应用程序范围常量的类
+ │ │ ├── controller // REST API 端点
+ │ │ ├── domain // 核心领域模型和相关类型
+ │ │ │ ├── common // 通用领域对象/工具类
+ │ │ │ ├── entity // 表示数据库表的 JPA/MyBatis 实体
+ │ │ │ ├── model // 通用的实体类模型
+ │ │ │ ├── view // 专门用于只读操作的数据传输对象(例如,查询结果、报告结构)
+ │ │ │ └── web // 专门用于 Web 请求/响应体的数据传输对象
+ │ │ │ ├── request // 请求 DTO
+ │ │ │ └── response // 响应 DTO
+ │ │ ├── exception // 自定义应用程序特定异常
+ │ │ ├── extension // 扩展点或自定义功能
+ │ │ │ ├── jackson // Jackson 序列化/反序列化扩展
+ │ │ │ └── redis // Redis 相关扩展
+ │ │ │ └── serializer
+ │ │ ├── filter // Servlet 过滤器或 Spring Security 过滤器
+ │ │ ├── manager // 业务逻辑协调器,通常协调多个服务或仓库
+ │ │ ├── mapper // 数据访问层 (MyBatis 接口)
+ │ │ ├── processor // 通用处理组件或业务工作流
+ │ │ ├── properties // 用于类型安全配置属性的类 (`@ConfigurationProperties`)
+ │ │ ├── repository // 数据访问层 (Spring Data JPA 接口)
+ │ │ ├── security // Spring Security 特定组件
+ │ │ │ ├── authentication // 自定义认证机制
+ │ │ │ └── provider // 自定义认证提供者
+ │ │ ├── service // 核心业务逻辑(事务层)
+ │ │ ├── utils // 通用工具类
+ │ │ └── validation // 自定义验证逻辑
+ │ │ └── group // 针对不同上下文(例如,创建、更新)的验证分组
+ │ └── resources
+ │ ├── application.yml // 默认应用程序属性
+ │ └── mapper // MyBatis XML 映射文件
+ └── test
+ └── java
+ └── com/onixbyte/helix
+ └── HelixApplicationTests.java // Spring Boot 集成测试
+```
+
+**关键观察与具体指令:**
+
+- **外部 `config` 目录**
+ - 环境配置 (`application-dev.yml`、`application-prod.yml.example`) 在顶层 `config` 目录中管理,与 `src/main/resources` 分开。这促进了特定于环境的属性管理,允许在部署时挂载或链接不同的配置。
+ - **禁止上传除 `src/main/resources/application.yml` 之外的任何配置文件到 Git 仓库。**
+- **数据库初始化**: `database/init.d` 目录保留用于 SQL 脚本,特别是数据库模式初始化 (`init-en_GB.sql`),这对于环境设置和 CI/CD 流水线至关重要。这种结构暗示了"模式优先"或"代码驱动的模式演进"方法。
+- **`client` 包**: 该包用于向应用提供所有中间件的服务,如 HTTP、S3 存储、Redis 调用等。对于需要添加到 Spring 上下文中的,自行编码实现的功能(如 JSON Web Token 生成与解析)也推荐放到该包中。
+- **MyBatis 与 Spring Data JPA 集成**
+ - `src/main/java/.../mapper` 包包含 MyBatis mapper 接口,而实际的 SQL 定义位于 `src/main/resources/mapper/*.xml` 文件中。这种分离是保持代码整洁同时利用 MyBatis 强大 XML 映射能力的关键。
+ - `src/main/java/.../repository` 包包含 Spring Data JPA 接口。
+- **`domain` 包的粒度**:
+ - `domain.entity`: 保留用于直接映射到数据库表的类(MyBatis 的 POJO)。
+ - `domain.model`: 用于不直接与单个表一对一映射的更通用领域对象或聚合根。
+ - `domain.view`: 专门用于在只读场景(例如,查询结果、报告结构)中呈现数据的数据传输对象 (DTO)。
+ - `domain.web.request` / `domain.web.response`: 明确分离的用于传入 API 请求和传出 API 响应的 DTO,严格遵守 API 契约并与内部领域实体解耦。
+- **`manager` 和 `processor` 包**: 这些包暗示了一个分层架构,其中"管理器"协调涉及多个服务或仓库的操作,而"处理器"可能处理业务流程的特定方面。强制明确定义这些包中类的职责,以防止出现"贫血领域模型"或"上帝对象"等反模式。
+- **`security` 包**: 此子包包含除初始配置之外的自定义 Spring Security 组件,例如自定义认证类型和提供者,表明了定制的安全实现。
+- **`properties` 包**: 此包用于自定义 `@ConfigurationProperties` 类,促进对 YML 文件中定义的应用程序设置进行类型安全访问,位置得当。
+- **`extension` 包**: 这是一个灵活的区域,用于应用程序特定的扩展,例如自定义 Jackson 序列化器或 Redis 定制。应谨慎使用,以防止成为"杂项"的堆放地。
+
+## 安全性 (Spring Security)
+
+- **强制使用**: Spring Security 在所有 Spring Boot Web 应用程序中都是强制的。
+- **认证与授权**: 在 `SecurityConfig.java` 中配置认证机制(例如,OAuth 2.0、JWT、基于会话)和授权规则。
+- **CSRF 保护**: 确保对修改状态的操作启用 CSRF 保护,除非有充分的理由禁用它(例如,已存在其他机制的无状态 API)。
+- **CORS**: 根据前端部署要求正确配置跨域资源共享 (CORS)。
+- **第三方身份提供者**: 在与第三方身份提供者(例如 Microsoft Entra ID)集成时,遵循安全令牌处理和用户配置的最佳实践。敏感凭据必须安全管理(例如,环境变量、Vault)。
+- **输入验证**: 始终在服务器端验证所有用户输入,以防止常见的漏洞,如 SQL 注入、XSS 等。
+- **内容安全策略 (CSP)**: 考虑为前端实施强大的 CSP 以减轻 XSS 攻击。
diff --git a/docs/zh-hans/blog/contents/minio-admin-guide.md b/docs/zh-hans/blog/contents/minio-admin-guide.md
new file mode 100644
index 0000000..2386316
--- /dev/null
+++ b/docs/zh-hans/blog/contents/minio-admin-guide.md
@@ -0,0 +1,200 @@
+---
+title: MinIO 新版本管理中心
+tags:
+ - minio
+ - storage
+ - s3
+ - devops
+ - cheatsheet
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+MinIO 在新版本中将管理功能从 Web UI 中移除了。现在需要使用 **MinIO Client (mc)** 命令行工具来进行管理操作。
+
+## 安装 MinIO Client (mc)
+
+### Windows:
+
+```powershell
+# 下载 mc.exe
+Invoke-WebRequest -Uri "https://dl.min.io/client/mc/release/windows-amd64/mc.exe" -OutFile "mc.exe"
+
+# 或使用 Chocolatey
+choco install minio-client
+```
+
+### Linux/macOS:
+
+```bash
+# Linux
+wget https://dl.min.io/client/mc/release/linux-amd64/mc
+chmod +x mc
+sudo mv mc /usr/local/bin/
+
+# macOS
+brew install minio/stable/mc
+```
+
+## 配置 MinIO Client
+
+```bash
+# 添加 MinIO 服务器别名
+mc alias set myminio http://localhost:9000 minioadmin minioadmin
+
+# 验证连接
+mc admin info myminio
+```
+
+## 用户管理操作
+
+### 创建用户
+
+```bash
+# 创建新用户
+mc admin user add myminio newuser newpassword
+
+# 查看所有用户
+mc admin user list myminio
+```
+
+### 创建 Access Key 和 Secret Key
+
+```bash
+# 为用户创建服务账户(生成 AccessKey/SecretKey)
+mc admin user svcacct add myminio newuser
+
+# 或者指定自定义的 AccessKey
+mc admin user svcacct add myminio newuser --access-key "MYACCESSKEY123" --secret-key "MYSECRETKEY456"
+
+# 查看用户的服务账户
+mc admin user svcacct list myminio newuser
+```
+
+## 权限管理
+
+### 创建策略
+
+```bash
+# 创建策略文件 policy.json
+cat > policy.json << EOF
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject"
+ ],
+ "Resource": [
+ "arn:aws:s3:::mybucket/*"
+ ]
+ }
+ ]
+}
+EOF
+
+# 添加策略
+mc admin policy add myminio mypolicy policy.json
+
+# 将策略分配给用户
+mc admin policy set myminio mypolicy user=newuser
+```
+
+## 存储桶管理
+
+```bash
+# 创建存储桶
+mc mb myminio/mybucket
+
+# 列出存储桶
+mc ls myminio
+
+# 设置存储桶策略
+mc policy set public myminio/mybucket
+```
+
+## 常用管理命令
+
+```bash
+# 查看服务器信息
+mc admin info myminio
+
+# 查看服务器配置
+mc admin config get myminio
+
+# 重启服务器
+mc admin service restart myminio
+
+# 查看日志
+mc admin logs myminio
+
+# 查看统计信息
+mc admin prometheus metrics myminio
+```
+
+## 实用脚本示例
+
+创建一个管理脚本 `setup-minio.sh`:
+
+```bash
+#!/bin/bash
+
+MINIO_ALIAS="myminio"
+MINIO_URL="http://localhost:9000"
+ADMIN_USER="minioadmin"
+ADMIN_PASS="minioadmin"
+
+# 配置 MinIO 客户端
+mc alias set $MINIO_ALIAS $MINIO_URL $ADMIN_USER $ADMIN_PASS
+
+# 创建应用用户
+APP_USER="appuser"
+APP_PASS="apppassword"
+mc admin user add $MINIO_ALIAS $APP_USER $APP_PASS
+
+# 创建服务账户并获取 AccessKey/SecretKey
+echo "Creating service account for $APP_USER..."
+CREDENTIALS=$(mc admin user svcacct add $MINIO_ALIAS $APP_USER --json)
+ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.accessKey')
+SECRET_KEY=$(echo $CREDENTIALS | jq -r '.secretKey')
+
+echo "Generated credentials:"
+echo "Access Key: $ACCESS_KEY"
+echo "Secret Key: $SECRET_KEY"
+
+# 创建存储桶
+mc mb $MINIO_ALIAS/app-bucket
+
+# 设置只读策略
+mc policy set download $MINIO_ALIAS/app-bucket
+```
+
+## Web Console 访问
+
+虽然管理功能被移除,但您仍然可以通过以下方式访问 MinIO Console:
+
+```bash
+# 启动 MinIO Console(如果单独安装)
+mc admin console myminio
+```
+
+或者在启动 MinIO 服务器时指定 Console 地址:
+
+```bash
+minio server /data --console-address ":9001"
+```
+
+## 总结
+
+新版 MinIO 的管理完全依赖 `mc` 命令行工具:
+
+1. **安装 mc 客户端**
+2. **配置服务器别名**
+3. **使用 `mc admin` 命令进行用户、权限、存储桶管理**
+4. **通过 `mc admin user svcacct` 生成 AccessKey/SecretKey**
+
+这种方式虽然需要命令行操作,但提供了更强大和灵活的管理能力,特别适合自动化部署和脚本化管理。
diff --git a/docs/zh-hans/blog/contents/mybatis-flex.md b/docs/zh-hans/blog/contents/mybatis-flex.md
new file mode 100644
index 0000000..6c22aad
--- /dev/null
+++ b/docs/zh-hans/blog/contents/mybatis-flex.md
@@ -0,0 +1,31 @@
+---
+title: MyBatis Flex
+tags:
+ - java
+ - mybatis
+ - spring-boot
+ - orm
+ - framework
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+> 本文仅针对在 Spring Boot 3 中使用 `MyBatis Flex`
+
+## 安装与配置
+
+### 安装
+
+在 `gradle` 目录下的 `libs.versions.toml` 中添加如下代码:
+
+```toml
+[versions]
+mybatisFlexVersion = "X.Y.Z"
+hikariVersion = "X.Y.Z"
+
+[libraries]
+hikari = { group = "com.zaxxer", name = "HikariCP", version.ref = "hikariVersion" }
+mybatisFlex-processor = { group = "com.mybatis-flex", name = "mybatis-flex-processor", version.ref = "mybatisFlexVersion" }
+mybatisFlex-starter = { group = "com.mybatis-flex", name = "mybatis-flex-spring-boot3-starter", version.ref = "mybatisFlexVersion" }
+```
diff --git a/docs/zh-hans/blog/contents/postgresql-zhparser-fuzzy-search.md b/docs/zh-hans/blog/contents/postgresql-zhparser-fuzzy-search.md
new file mode 100644
index 0000000..783ef92
--- /dev/null
+++ b/docs/zh-hans/blog/contents/postgresql-zhparser-fuzzy-search.md
@@ -0,0 +1,212 @@
+---
+title: 使用分词在 PostgreSQL 中加速模糊查询
+tags:
+ - postgresql
+ - zhparser
+ - full-text-search
+ - performance
+author:
+ name: Siu Jam Oh
+ email: jamo.siu@gmail.com
+---
+
+## 背景与挑战
+
+随着业务数据量突破 **200 万行**,传统的 `LIKE '%关键词%'` 模糊查询导致数据库 I/O 频繁告警,查询响应时间从毫秒级退化至秒级。为提升检索效率并支持中文语义,我们决定引入 `zhparser` 插件实现全文检索。
+
+## 演进路线与环境适配
+
+本次技术落地经历了四个关键阶段,每个阶段解决了不同的技术核心:
+
+### CentOS 7.9 虚拟机(可行性验证)
+
+- **目标**:验证 `SCWS` + `zhparser` 在旧版系统下的兼容性。
+- **核心操作**:在 CentOS 7.9 环境下手动编译 `postgresql-16.2` 源码,完成插件初步跑通。
+
+**结论**:确认了分词方案对中文检索性能的显著提升。
+
+### 本地 Docker 容器(容器化探索)
+
+- **目标**:在本地的完整系统进行初步测试。
+- **核心操作**:通过 `docker cp` 注入二进制 `.so` 文件,解决 `ldconfig` 动态链接库路径可见性问题。
+- **发现**:识别出 **"词典文件缺失"** 会导致分词退化为单字(助词)的故障点。
+
+### EulerOS 2.0 测试服(自编译环境适配)
+
+- **目标**:适配生产环境的 OS 架构(x86_64)与自编译安装的 PostgreSQL。
+- **核心问题**:解决了 `libscws.so.1` 无法加载的报错。
+- **关键方案**:
+ - 明确了 `postgres` 运行用户对 `/usr/local/scws/lib` 的访问权限需求。
+ - 通过修改 `systemd` 服务环境变量或创建 `/usr/lib64` 软链接强制刷新库搜索路径。
+
+### 生产部署预备(最终调优)
+
+- **目标**:确保 200w+ 数据量下的查询稳定性。
+- **优化点**:针对"非语义片段(如:古唐合)"查询不到的问题,制定了"全文检索优先 + `pg_trgm` 索引辅助"的降级查询策略。
+
+## 核心安装与配置步骤 (自编译环境)
+
+### 安装 `SCWS` 分词引擎
+
+SCWS 是 `zhparser` 依赖的底层核心,必须先行安装。
+
+1. **下载并解压**:下载源码包(如 `scws-1.2.3`)。
+2. **编译安装**:
+
+ ```bash
+ ./configure --prefix=/usr/local/scws
+ make && make install
+ ```
+
+3. **验证库文件**:确保 `/usr/local/scws/lib/libscws.so.1` 存在。
+
+### 编译与安装 `zhparser`
+
+这一步需要用到 PostgreSQL 自编译产生的 `pg_config`。
+
+1. **获取源码**:从 GitHub 克隆 `zhparser` 项目。
+2. **指定路径编译**:
+
+ ```bash
+ # 确保 pg_config 在 PATH 中,或手动指定
+ make USE_PGXS=1 PG_CONFIG=/usr/local/pgsql/bin/pg_config
+ make USE_PGXS=1 PG_CONFIG=/usr/local/pgsql/bin/pg_config install
+ ```
+
+ *注:`install` 步骤会自动将 `zhparser.so` 放入 PG 的 `pkglibdir`,将脚本放入 `extension` 目录。*
+
+### 解决动态链接库依赖
+
+1. **刷新系统缓存**:
+
+ ```bash
+ echo "/usr/local/scws/lib" > /etc/ld.so.conf.d/scws.conf
+ ldconfig
+ ```
+
+2. **权限检查**:确保运行 `postgres` 的 OS 用户对 `/usr/local/scws/lib` 有 `rx` 权限。
+3. **强制软链 (备选)**:若 `ldconfig` 失效,可将库文件软链至 `/usr/lib64`。
+
+### 重启数据库
+
+修改完系统共享库配置后,必须重启 PostgreSQL 进程以重新加载环境变量和链接库。
+
+```bash
+## 使用 pg_ctl 重启(自编译路径需根据实际情况调整)
+/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data restart
+
+## 或通过 systemd 重启(如果已注册服务)
+systemctl restart postgresql
+```
+
+### 数据库内初始化
+
+连接到 `psql`,执行逻辑配置:
+
+```sql
+-- 创建扩展
+CREATE EXTENSION zhparser;
+
+-- 创建全文检索配置并绑定分词器
+CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
+
+-- 添加 Token 映射
+ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l,t,b WITH simple;
+
+-- 【可选】指定自编译路径下的词典位置
+-- ALTER DATABASE postgres SET zhparser.dict_path = '/usr/local/scws/etc/dict.utf8.xdb';
+```
+
+## 性能分析与避坑指南
+
+### 索引性能瓶颈分析
+
+在测试中发现,即使是精确查询,由于使用了不当的联合索引(`create_time` 在首列),导致产生 `Bitmap Index Scan`,耗时高达 **482ms**。
+
+- **改进**:对检索高频列建立单列 **B-tree** 索引,利用 `Index Scan` 将响应降至 **10ms** 以内。
+
+### GIN 索引与非语义匹配
+
+- **跨词截断问题**:分词引擎基于语义,类似"古唐合"这种截断词可能因为分词边界导致 `@@` 无法命中。
+- **应对方案**:采用"瀑布式搜索"。全文检索(FTS)优先;若结果为空,自动降级为 `LIKE` 模糊查询,并配合 `pg_trgm` 索引加速。
+
+## 终极部署方案:双轨并行检索
+
+经过对数据的分析,发现对于账户名称中出现了约 1.24% 的非标准简体中文的数据,并且数据库中也存在部分因为公司名称怪异而导致数据查询不出来的问题,决定采取"分步降级"策略:
+
+- **第一步:全文检索(Fast Track):** 利用 GIN 索引进行 `@@` 匹配。
+- **第二步:结果评估:** 若返回结果为空,且搜索词包含字母或疑似繁体字符。
+- **第三步:模糊兜底(Safe Fallback):** 执行 `LIKE '%关键词%'`。虽然速度较慢,但由于其作为"补漏"逻辑,触发频率仅为 1% 左右,不会对数据库造成整体压力。
+
+## 搜索优化:集成自定义业务词库
+
+为了解决全文检索中公司品牌名被误切(如"元一"被切分为数词/量词)的问题,需构建一套从数据提取到索引重建的自动化维护链路。
+
+### 词库提取与预处理
+
+利用 **`companynameparser`** 的结构化解析能力剥离地名与行业后缀,并结合 **`jieba`** 进行语义复核,确保核心品牌词的完整性:
+
+- **提取逻辑**:通过 Python 脚本遍历全量 `buyer_unique_name`,提取核心 `brand` 字段。
+- **权重补偿**:针对包含"元"、"一"、"三"等易碎词条,手动将 TF(词频权重)提升至 **50.0 - 60.0**,确保其优先级高于内置量词规则。
+- **输出规范**:输出符合 SCWS 标准的 4 字段 `UTF-8` 文本(WORD, TF, IDF, ATTR),建议使用制表符 `\t` 分隔以规避解析异常。
+
+### 词库编译与部署
+
+:::tip
+对于使用 Windows 进行编译 `xdb` 二进制词典文件的用户,可以前往 OnixByte 的 [GitHub](https://github.com/onixbyte/scws/releases/tag/1.2.3) 或 [GitLab](https://git.onixbyte.cn/onixbyte/scws/-/releases/1.2.3) 页面下载使用 MingW 预编译好的,适用于 Windows 的原生 scws 命令行工具。
+:::
+
+将文本词典转换为 SCWS 高效二进制格式(XDB):
+
+1. **编译二进制词典**:
+
+ ```bash
+ # 使用 scws-gen-dict 工具生成加密二进制词库
+ /usr/local/scws/bin/scws-gen-dict -i custom_company.txt -o /usr/local/scws/etc/custom_company.xdb -c utf8
+ ```
+
+2. **文件分发与权限**:将生成的 `.xdb` 文件移动至分词数据目录,并确保 `postgres` 用户具备读取权限:
+
+ ```bash
+ cp custom_company.xdb /usr/local/pgsql/share/tsearch_data/
+ chown postgres:postgres /usr/local/pgsql/share/tsearch_data/custom_company.xdb
+ ```
+
+### 数据库参数固化
+
+修改 `postgresql.conf` 配置文件,强制加载 `zhparser` 及其自定义扩展词库:
+
+```plain text
+## 预加载插件库(必须重启生效)
+shared_preload_libraries = 'zhparser'
+
+## 加载自定义外部词典(需使用相对 tsearch_data 的路径)
+zhparser.extra_dicts = 'custom_company.xdb'
+```
+
+### 索引热更新与验证
+
+由于分词规则变动,存量数据必须通过重建索引实现语义同步:
+
+**物理重启服务**:
+
+```bash
+su - postgres -c "/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data restart"
+```
+
+**在线重建索引**:利用 `CONCURRENTLY` 关键字,在不阻塞 40 万条数据 DML 操作的前提下刷新 GIN 索引:
+
+```bash
+REINDEX INDEX CONCURRENTLY index_name;
+```
+
+**分词效能验证**:
+
+```sql
+-- 预期结果词性应显示为 n (noun),而非 x (unknown)
+SELECT * FROM ts_debug('chinese', '元一能源');
+```
+
+**优化建议:**
+- **显式提及权重补偿**:这是解决"元一"分词失败(显示为 `x`)的关键技术点。
+- **区分重启与重载**:明确 `shared_preload_libraries` 必须通过 `restart` 激活。
diff --git a/docs/zh-hans/blog/contents/quartile-method.md b/docs/zh-hans/blog/contents/quartile-method.md
new file mode 100644
index 0000000..db80f03
--- /dev/null
+++ b/docs/zh-hans/blog/contents/quartile-method.md
@@ -0,0 +1,22 @@
+---
+title: 四分位法
+tags:
+ - statistics
+ - algorithm
+ - data-analysis
+ - math
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+四分位法是统计学中的一种常用方法,主要用于数据的分析和表示。这种方法涉及将一组数据分为四个等分,每份包含四分之一的数据量。主要的统计量包括第一四分位数(Q1)、第二四分位数(Q2),即中位数和第三四分位数(Q3)。
+
+- 第一四分位数(`Q1`),也称为下四分位数,是指数据集中所有数值按大小排列后位于第 25% 位置的数值。
+- 第二四分位数(`Q2`),即中位数,是指数据集中所有数值按大小排列后位于第 50% 位置的数值。
+- 第三四分位数(`Q3`),也称为上四分位数,是指数据集中所有数值按大小排列后位于第 75% 位置的数值。
+- 四分位距(`IQR`),即第三四分位数与第一四分位数之间的差值,用于表示数据集中间50%数据的离散程度。四分位距的计算公式为 IQR = Q3 - Q1。四分位距常用于构建箱形图,是一种描述数据分布的有效方式,特别适用于识别数据中的异常值。
+
+上界值 = Q3 + 1.5 IQR。
+
+下界值 = Q1 - 1.5 IQR。
diff --git a/docs/zh-hans/blog/contents/setup-ldap-service.md b/docs/zh-hans/blog/contents/setup-ldap-service.md
new file mode 100644
index 0000000..2509f9b
--- /dev/null
+++ b/docs/zh-hans/blog/contents/setup-ldap-service.md
@@ -0,0 +1,140 @@
+---
+title: 搭建 LDAP 服务
+tags:
+ - ldap
+ - openldap
+ - authentication
+ - linux
+ - devops
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+搭建 LDAP(轻型目录访问协议)服务器是实现企业级**集中身份认证**和**权限管理**的核心步骤。最常用的开源实现是 **OpenLDAP**。
+
+以下是在基于 Debian/Ubuntu 的 Linux 系统上搭建 OpenLDAP 服务器的详细步骤。
+
+## 环境准备与安装
+
+在开始之前,请确保你的系统软件包是最新的,并设置好主机名。
+
+```bash
+## 更新系统
+sudo apt update && sudo apt upgrade -y
+
+## 安装 OpenLDAP 及管理工具
+## slapd 是守护进程,ldap-utils 是命令行客户端工具
+sudo apt install slapd ldap-utils -y
+```
+
+> 在安装过程中,系统会提示你设置 **LDAP 管理员密码**。请务必记住这个密码,稍后配置时会频繁使用。
+
+## 配置 OpenLDAP 服务器
+
+虽然安装时已经初始化了部分设置,但通常我们需要根据具体的域名(如 `example.com`)进行自定义配置。
+
+### 重新配置 slapd
+
+执行以下命令进入交互式配置界面:
+
+```bash
+sudo dpkg-reconfigure slapd
+```
+
+**配置建议**:
+
+1. **Omit OpenLDAP server configuration?** 选择 **No**。
+2. **DNS domain name:** 输入你的域名(例如 `centre.example.com`)。这将决定你的基准识别名(Base DN),如 `dc=centre,dc=example,dc=com`。
+3. **Organization name:** 输入你的组织名称。
+4. **Administrator password:** 输入之前设置的管理员密码。
+5. **Database backend:** 建议选择 **MDB**。
+6. **Remove database when slapd is purged?** 选择 **No**。
+7. **Move old database?** 选择 **Yes**。
+
+## 理解 LDAP 层级结构
+
+LDAP 的数据是以**树状结构**存储的。为了方便管理,我们通常会创建两个"组织单元"(Organizational Units, OU):一个存放用户(Users),一个存放组(Groups)。
+
+## 创建组织单元 (OU)
+
+在 LDAP 中,我们使用 **LDIF** (LDAP Data Interchange Format) 文件来添加或修改目录。
+
+创建一个名为 `base.ldif` 的文件:
+
+```text
+## 创建用户组 OU
+dn: ou=people,dc=centre,dc=example,dc=com
+objectClass: organizationalUnit
+ou: people
+
+## 创建用户组别 OU
+dn: ou=groups,dc=centre,dc=example,dc=com
+objectClass: organizationalUnit
+ou: groups
+```
+
+**导入数据:**
+
+```bash
+## 使用管理员身份将 LDIF 文件导入数据库
+ldapadd -x -D "cn=admin,dc=centre,dc=example,dc=com" -W -f base.ldif
+```
+
+## 添加用户和组
+
+创建一个名为 `groups.ldif` 的文件来定义一个新组:
+
+```text
+## 定义一个新组
+dn: cn=developers,ou=groups,dc=centre,dc=example,dc=com
+objectClass: inetOrgGroup
+cn: developers
+```
+
+创建一个名为 `users.ldif` 的文件来定义一个新用户:
+
+```text
+## 定义一个新用户
+dn: uid=jbloggs,ou=people,dc=centre,dc=example,dc=com # 该条目的身份证号,即 Distinguished Name (DN)。
+objectClass: inetOrgPerson # 对象类,inetOrgPerson 代表这是一个互联网机构人员。它允许你使用 email、displayName、telephoneNumber 等常见的联系人属性
+objectClass: posixAccount # 它使该条目兼容 Unix/Linux 系统账号。有了它,用户才能登录 Linux 服务器,并拥有 UID、GID 和家目录。
+objectClass: shadowAccount # 用于管理密码老化(如过期、更改警告等),对应 Linux 中的 /etc/shadow 文件功能。
+uid: jbloggs # 用户的登录名(User ID)。在 Linux 登录界面输入的通常就是这个。
+sn: Bloggs # 姓(Surname)。inetOrgPerson 类要求必须填写。
+givenName: Joe # 名(First Name)。
+cn: Joe Bloggs # 全名(Common Name)。这是 LDAP 条目的标准显示名称。
+displayName: Joe Bloggs # 在图形界面或邮件客户端显示的友好名称。
+uidNumber: 10000 # Linux 系统中的用户 ID 数字
+gidNumber: 5000 # 用户主组的 ID 数字。
+userPassword: {SSHA}密码哈希值或明文 # 存储用户的加密密码。
+homeDirectory: /home/jbloggs # 用户登录 Linux 后的家目录路径。
+loginShell: /bin/bash # 用户登录后使用的 Shell 环境。
+```
+
+> 如果您将来要集成 **GitLab**、**Jenkins** 或 **VPN**,它们通常会搜索 `uid` 属性来验证登录名。
+
+### FAQ
+
+#### 如果不需要为该用户授予服务器的登录权限,是不是可以移除 objectClass: posixAccount?
+
+**是的,完全可以移除**,但你需要注意属性之间的"绑定关系"。
+
+如果你只需要这个用户用于 Web 应用登录(如 GitLab, Jenkins, Wiki)或作为电子邮件联系人,而不需要他通过 SSH 或控制台登录 Linux 服务器,移除 `posixAccount` 是更规范的做法。
+
+当你移除 `objectClass: posixAccount` 时,以下属性**必须一并删除**,因为它们属于该类定义的"强制或可选属性":
+
+- `uidNumber`
+- `gidNumber`
+- `homeDirectory`
+- `loginShell`
+
+此外, `shadowAccount` 通常也与系统登录挂钩,如果不需要管理 Linux 密码过期策略,也可以一并移除。
+
+## 后续建议与管理工具
+
+命令行管理 LDAP 较为繁琐,建议使用以下工具进行可视化操作:
+
+- **phpLDAPAdmin**: 基于 Web 的管理界面,适合快速上手;
+- **Apache Directory Studio**: 强大的跨平台桌面客户端,适合复杂的架构设计。
+- **安全加固**: 默认情况下 LDAP 是明文传输的,建议配置 **LDAPS (LDAP over SSL/TLS)** 来加密 636 端口的通信。
diff --git a/docs/zh-hans/blog/contents/use-json-in-mysql.md b/docs/zh-hans/blog/contents/use-json-in-mysql.md
new file mode 100644
index 0000000..1ebb922
--- /dev/null
+++ b/docs/zh-hans/blog/contents/use-json-in-mysql.md
@@ -0,0 +1,89 @@
+---
+title: 在 MySQL 中使用 JSON
+tags:
+ - mysql
+ - json
+ - database
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+MySQL (自 5.7 版本开始) **不直接支持名为 `jsonb` 的数据类型**。`jsonb` 是 PostgreSQL 数据库特有的数据类型,它以二进制格式存储 JSON 数据,并对其进行预解析,以便在查询时更快地访问和操作。
+
+然而,MySQL 提供的 `JSON` 数据类型在功能和内部实现上与 PostgreSQL 的 `jsonb` 有很多相似之处,尤其是在查询数据方面。
+
+MySQL 的 `JSON` 数据类型于 MySQL 5.7 版本引入,其特点如下:
+
+1. **二进制存储**:与 PostgreSQL 的 `jsonb` 类似,MySQL 的 `JSON` 类型数据也是以**内部二进制格式**存储的,而不是简单的文本字符串。这使得 JSON 数据的读取和操作效率更高,因为数据库不必在每次查询时都解析文本格式的 JSON 字符串。
+2. **自动验证**:当您插入或更新 `JSON` 列时,MySQL 会自动验证其内容是否是有效的 JSON 文档。如果不是,则会抛出错误。
+3. **优化存储**:二进制格式的存储也对空间进行了优化,通常比存储原始文本格式的 JSON 更加紧凑。
+
+MySQL 提供了一系列强大的函数和操作符来查询和操作 `JSON` 数据,这些功能与您对 `jsonb` 的期望非常相似:
+
+1. **`->` (JSON Extract Operator)**:用于从 JSON 文档中提取值。它返回一个 JSON 值。
+
+ ```sql
+ SELECT my_json_column->'$.key' FROM my_table;
+ -- 示例:提取 user 对象的 name 属性
+ -- 假设 my_json_column 存储 {'user': {'name': 'Alice'}}
+ SELECT json_data->'$.user.name' FROM my_table;
+ ```
+
+2. **`->>` (JSON Unquote Operator)**:用于从 JSON 文档中提取值并**自动取消引用 (unquote)**,通常返回一个标量值(如字符串、数字)。这等同于 `JSON_UNQUOTE(JSON_EXTRACT(...))`。
+
+ ```sql
+ SELECT my_json_column->>'$.key' FROM my_table;
+ -- 示例:提取 user 对象的 name 属性(直接返回字符串 'Alice')
+ SELECT json_data->>'$.user.name' FROM my_table;
+ ```
+
+3. **`JSON_EXTRACT(json_doc, path, ...)`**:显式地从 JSON 文档中提取数据。
+
+ ```sql
+ SELECT JSON_EXTRACT(my_json_column, '$.key') FROM my_table;
+ ```
+
+4. **`JSON_CONTAINS(json_doc, candidate, path)`**:检查 JSON 文档中是否包含指定的值。
+
+ ```sql
+ -- 检查tags数组是否包含 'backend'
+ -- 假设 my_json_column 存储 {'tags': ['frontend', 'backend']}
+ SELECT * FROM my_table WHERE JSON_CONTAINS(json_data->'$.tags', '"backend"');
+ ```
+
+5. **`JSON_SEARCH(json_doc, one_or_all, search_str, escape_char, path, ...)`**:返回指定字符串在 JSON 文档中的路径。
+
+ ```sql
+ -- 查找值为 'test' 的路径
+ SELECT JSON_SEARCH(my_json_column, 'one', 'test') FROM my_table;
+ ```
+
+6. **`JSON_TABLE(json_doc, path COLUMNS ...) ` (MySQL 8.0 及更高版本)**:这是一个非常强大的函数,可以将 JSON 数据 "展开" 成关系型的行和列,非常适合进行复杂查询和报表。
+
+ ```sql
+ -- 假设 json_data 存储 {'items': [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}]}
+ SELECT *
+ FROM my_table,
+ JSON_TABLE(json_data, '$.items[*]' COLUMNS(
+ itemId INT PATH '$.id',
+ itemName VARCHAR(50) PATH '$.name'
+ )) AS jt;
+ ```
+
+像 PostgreSQL 的 `jsonb` 一样,为了对 JSON 字段进行高效查询,您通常需要创建索引。由于 JSON 字段的内容是动态的,MySQL 不直接支持在 JSON 字段的某个内部路径上直接创建传统 B-tree 索引。但是,可以通过 **虚拟列 (Virtual Generated Columns)** 来实现:
+
+1. **创建虚拟列**:定义一个虚拟列,其值是从 JSON 字段中提取的特定路径。
+
+ ```sql
+ ALTER TABLE my_table
+ ADD COLUMN user_name VARCHAR(255) AS (json_data->>'$.user.name') VIRTUAL;
+ ```
+
+2. **在虚拟列上创建索引**:这样,当您查询 `WHERE json_data->>'$.user.name' = 'Alice'` 时,MySQL 优化器可以选择使用 `idx_user_name` 索引,从而大大提高查询性能。
+
+ ```sql
+ CREATE INDEX idx_user_name ON my_table (user_name);
+ ```
+
+尽管 MySQL 没有 `jsonb` 这个名字,但其 `JSON` 数据类型提供了高度相似的功能:二进制存储优化、自动验证和丰富的查询操作符及函数。通过结合虚拟列和索引,MySQL 可以在处理 JSON 数据时提供与 PostgreSQL 的 `jsonb` 相似的查询性能和灵活性。
diff --git a/docs/zh-hans/blog/contents/version-control-and-code-review.md b/docs/zh-hans/blog/contents/version-control-and-code-review.md
new file mode 100644
index 0000000..83a6e76
--- /dev/null
+++ b/docs/zh-hans/blog/contents/version-control-and-code-review.md
@@ -0,0 +1,36 @@
+---
+title: 版本控制与代码审查
+tags:
+ - git
+ - code-review
+ - best-practice
+ - workflow
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+## GitFlow 工作流
+
+版本控制将使用 GitFlow 分支模型,包括 `main`、`develop`、`feature`、`release` 和 `hotfix` 分支。
+
+- `main`: 生产就绪代码。只有 `release` 和 `hotfix` 分支会合并到 `main`。
+- `develop`: 即将开发的功能集成分支。
+- `feature/*`: 用于新功能的分支,从 `develop` 分支出来。
+- `release/*`: 用于准备新生产版本的分支,从 `develop` 分支出来。
+- `hotfix/*`: 用于紧急生产错误修复的分支,从 `main` 分支出来。
+
+## 拉取请求 (PRs)
+
+所有代码更改(直接推送到功能分支除外)都必须通过拉取请求提交。
+
+## 代码审查
+
+- 每个拉取请求必须由至少一名其他开发人员进行审查。
+- 审查者负责检查是否符合本代码标准、代码质量、逻辑正确性和测试覆盖率。
+- 在创建 PR 之前,应在本地运行 IntelliJ IDEA 的集成代码分析工具。
+
+## 提交消息
+
+编写清晰、简洁、描述性的提交消息,解释更改了什么以及为什么进行更改。如果可能,遵循约定式提交格式(例如,
+`feat: add user registration endpoint`)。
(抱歉回复晚了) | **Thanks for your patience**
(感谢你的耐心等待) | 前者在道歉,后者在感谢——从「我做错了」转变为「你太好了」,既表达了歉意又让对方感到被尊重 |
+| 约时间 | **What works best for you?**
(你什么时候方便?) | **Could you do …?**
(你可以在某某时间吗?) | 前者把决定权完全推给对方,后者主动给出选项,减少来回沟通的成本 |
+| 帮助了别人之后 | **No problem / No worries**
(没问题 / 别担心) | **Always happy to help**
(乐于效劳) | 前者暗示这件事"本来可能是个问题",后者传递出你乐在其中、下次还愿意帮 |
+| 提出建议 | **I think maybe we should …**
(我觉得也许我们应该……) | **It'd be best if we …**
(最好是……) | 前者透着犹豫和不自信,后者直接给出判断——像有经验的人在做决策 |
+| 文字沟通费劲 | **_花 30 分钟反复修改一封邮件_** | **It'd be easier to discuss in person**
(当面/电话聊会更轻松) | 意识到沟通渠道本身就是问题,果断切换方式反而是效率最高的选择 |
+| 确认对方是否理解 | **Hopefully that makes sense?**
(希望我说清楚了?) | **Let me know if you have questions**
(有问题随时问我) | 前者在怀疑自己的表达能力,后者把责任合理地分担给对方,姿态更稳 |
+| 催进度 | **Just wanted to check in**
(只是想确认一下) | **When can I expect an update?**
(我什么时候可以收到更新?) | 前者显得小心翼翼不敢打扰,后者直接问时间节点——清楚、礼貌、专业 |
+| 犯了小错 | **Ahh sorry my bad totally missed that**
(啊啊抱歉我的错,完全漏掉了) | **Thanks for letting me know**
(感谢提醒) | 前者过度道歉反而让对方尴尬,后者承认了问题但把焦点放在了"解决"上 |
+| 需要早退 | **Could I possibly leave early?**
(我能提前走吗?) | **I will need to leave at …**
(我需要在某某时间离开) | 前者在请求批准,后者在陈述安排——你是专业人士,不需要为合理需求道歉 |
+
+## 核心原则
+
+写好邮件的关键不在于词汇量,而在于**姿态**。时刻提醒自己三条规则:
+
+1. **用陈述代替请求** —— 「我需要……」比「我能不能……」更有分量
+2. **用感谢代替道歉** —— 把焦点从「我的过失」转移到「对方的支持」
+3. **用明确代替模糊** —— 给出具体的时间、选项、行动项,而不是把球踢回给对方
+
+下次打开邮箱,花 5 秒想一想:这句话能不能说得更像一个做决定的人?
diff --git a/docs/zh-hans/blog/contents/fix-macos-monterey-sleep-wake.md b/docs/zh-hans/blog/contents/fix-macos-monterey-sleep-wake.md
new file mode 100644
index 0000000..eefd685
--- /dev/null
+++ b/docs/zh-hans/blog/contents/fix-macos-monterey-sleep-wake.md
@@ -0,0 +1,26 @@
+---
+title: 解决 macOS Monterey+ 设备休眠频繁自动唤醒的问题
+tags:
+ - macos
+ - sleep
+ - power-management
+ - bug
+---
+
+> 本文由 **落格博客** 原创撰写:[落格博客](https://www.logcg.com/) » [升级 macOS Monterey 后设备休眠半夜频繁唤醒问题](https://www.logcg.com/archives/3528.html)
+
+更新到了 macOS Monterey,半夜总会被屏幕照醒,就觉得很诡异,以前也有过,但都是有通知的时候才会点亮屏幕,现在是没有任何理由的自己点亮,硬件还是那个硬件,那就应该是软件的锅了。
+
+在网上查了一圈,先是找到了[苹果官方的教程](https://support.apple.com/zh-cn/guide/mac-help/mchlp2995/mac)。写的很详细,但显然是没有任何用处的。
+
+于是继续深挖,还真找到了原因,使用命令 **`pmset -g log | grep DarkWake`** 就可以看到,在你睡觉的过程中,你的 Mac 并没有歇着……
+
+看看输出,这几个比较典型,大部分都是这样的,一个 DarkWake, 一个 Wake, 两个仅仅相连,那么问题就出来了, DarkWake 是给电脑在后台唤醒来更新数据的,但不知怎么的,外设被触发,从而导致了全局唤醒。
+
+总之,我并不想要这个功能, 就那个 PowerNap,对我来说,我更希望它能给我多省点电,于是大概解决思路就这么多:关掉网络访问唤醒,关掉 PowerNap……不过问题来了,在 m1 设备上,其实是没有 PowerNap 选项的……(显然,苹果对自己的续航很有信心,但他们忽略了Bug的威力)
+
+于是对于 PowerNap 这个功能来说,我们只能从命令行下手,首先使用 **`pmset -g`** 命令查看当前状态,找到 **`powernap`** 的值,如果不是 0 ,说明是启用的状态,使用命令 **`sudo pmset -a powernap 0`** 关掉它。
+
+同时,还有另外一个 **`tcpkeepalive`** ,这个默认应该也不是 0 ,也要关掉,它决定了你的 rmbp 在休眠时是否要保持 tcp 连接。 **`sudo pmset -a tcpkeepalive 0`** ,执行这条命令会导致终端提示:***Warning: This option disables TCP Keep Alive mechanism when system is sleeping. This will result in some critical features like 'Find My Mac' not to function properly.***
+
+大概是说关了的话某些功能会受到限制,其实就是系统功能不能休眠时联网了,我相信真有人偷了你 Mac,它也连不上网的。
diff --git a/docs/zh-hans/blog/contents/font-size-conversion-table.md b/docs/zh-hans/blog/contents/font-size-conversion-table.md
new file mode 100644
index 0000000..35cd1b4
--- /dev/null
+++ b/docs/zh-hans/blog/contents/font-size-conversion-table.md
@@ -0,0 +1,30 @@
+---
+title: 字号榜值转换表
+tags:
+ - typography
+ - font
+ - cheatsheet
+ - design
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+| 中文字号 | 英文字号(磅)/pt | 毫米/mm | 像素/px |
+|------|------------|-------|-------|
+| 初号 | 42 | 14.82 | 56 |
+| 小初 | 36 | 12.7 | 48 |
+| 一号 | 26 | 9.17 | 34.7 |
+| 小一 | 24 | 8.47 | 32 |
+| 二号 | 22 | 7.76 | 29.3 |
+| 小二 | 18 | 6.35 | 24 |
+| 三号 | 16 | 5.64 | 21.3 |
+| 小三 | 15 | 5.29 | 20 |
+| 四号 | 14 | 4.94 | 18.7 |
+| 小四 | 12 | 4.23 | 16 |
+| 五号 | 10.5 | 3.7 | 14 |
+| 小五 | 9 | 3.18 | 12 |
+| 六号 | 7.5 | 2.56 | 10 |
+| 小六 | 6.5 | 2.29 | 8.7 |
+| 七号 | 5.5 | 1.94 | 7.3 |
+| 八号 | 5 | 1.76 | 6.7 |
diff --git a/docs/zh-hans/blog/contents/frontend-development-standards.md b/docs/zh-hans/blog/contents/frontend-development-standards.md
new file mode 100644
index 0000000..1c682c7
--- /dev/null
+++ b/docs/zh-hans/blog/contents/frontend-development-standards.md
@@ -0,0 +1,42 @@
+---
+title: 前端开发规范
+tags:
+ - frontend
+ - react
+ - standards
+ - best-practice
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+## 依赖管理 (pnpm)
+
+- **严格性**: 利用 pnpm 的严格依赖管理,以确保更确定性的 `node_modules` 结构和高效的磁盘空间使用。
+- **工作区**: 如果使用 monorepo 方法,配置 pnpm 工作区以简化多个前端包的依赖管理。
+- **审计**: 定期使用 `pnpm audit` 审计前端依赖项是否存在已知漏洞。
+
+## API 通信 (Axios)
+
+- **Axios 实例**: 创建一个集中的 Axios 实例用于 API 调用,以应用通用配置(基本 URL、请求头、拦截器)。
+- **拦截器**: 使用 Axios 拦截器进行以下操作:
+ - 向传出请求添加认证令牌。
+ - 处理全局错误响应(例如,显示 `401 Unauthorized` 的通知)。
+ - 在开发环境中记录请求/响应。
+- **错误处理**: 在 Axios 拦截器或自定义工具函数中集中处理 API 错误,以提供一致的用户反馈。
+
+## React 与组件标准
+
+- **函数组件与 Hooks**: 对于新开发,优先使用带有 React Hooks 的函数组件,而非类组件。
+- **Props**:
+ - 为组件 props 定义 `interface` 或 `type` 以确保类型安全。
+ - 在组件入口处解构 props 以提高清晰度。
+- **状态管理 (Redux)**:
+ - 使用 Redux Toolkit 进行高效且减少样板代码的 Redux 开发。
+ - 使用 `createSlice` 将 Redux 逻辑组织成"切片"(特定功能的 reducer、action 和 selector)。
+ - 遵循"ducks"模式或"slices"方法来协同定位 Redux 逻辑。
+- **组件组合**: 将复杂的 UI 分解为更小、可重用且职责单一的组件。
+- **Ant Design**:
+ - 利用 Ant Design 组件以实现一致的 UI/UX。
+ - 如果需要,使用 CSS-in-JS 解决方案在整个应用程序中一致地定制 Ant Design 主题和样式。
+- **可访问性**: 从一开始就设计和实现考虑到 Web 可访问性 (a11y) 的组件。
diff --git a/docs/zh-hans/blog/contents/frontend-tips-and-solutions.md b/docs/zh-hans/blog/contents/frontend-tips-and-solutions.md
new file mode 100644
index 0000000..dc4a760
--- /dev/null
+++ b/docs/zh-hans/blog/contents/frontend-tips-and-solutions.md
@@ -0,0 +1,75 @@
+---
+title: 前端开发技巧与方案速查手册
+tags:
+ - frontend
+ - react
+ - ant-design
+ - tailwind
+ - best-practice
+author:
+ name: Zihlu Wang
+ email: real@zihluwang.me
+---
+
+## 表单组件的解耦
+
+将表单组件拆分为 UI 组件和逻辑组件,并在逻辑组件中使用 UI 组件渲染样式。
+
+## React 入口组件顺序
+
+```typescript
+import { StrictMode } from "react"
+import { createRoot } from "react-dom/client"
+import { Provider as ReduxProvider } from "react-redux"
+import { PersistGate } from "redux-persist/integration/react"
+import { RouterProvider } from "react-router"
+import { App as AntApp, ConfigProvider as AntConfigProvider } from "antd"
+import { StyleProvider } from "@ant-design/cssinjs"
+import AntSimplifiedChinese from "antd/locale/zh_CN"
+import "./index.css"
+import "@/config/dayjs-config"
+import store, { persistor } from "@/store"
+import router from "@/router"
+
+createRoot(document.getElementById("root")!).render(
+