English | 简体中文
A modern, configurable, and self-hostable content platform built with Astro, React, Tailwind CSS, and TypeScript.
RefactX provides a structured foundation for publishing long-form content, maintaining project and link data, and managing content through an integrated CMS. The project combines a high-density editorial interface with a component-oriented architecture intended for individual developers, technical writers, and content-focused personal websites.
- Astro 6 — application framework, routing, and static generation
- React 19 — interactive interfaces such as the administration panel
- TypeScript — static typing and application contracts
- Tailwind CSS 4 — styling and design tokens
- Nano Stores — lightweight client-side state management
- Vercel Serverless APIs — authentication and CMS operations
- Pagefind — production-only site search
- Waline — comments and message board
- Notion API — dynamic feed synchronization
- GitHub API (Octokit) — repository-backed content management
- Markdown-based article publishing with typed content collections
- Configurable post layouts, pagination, tags, authors, and featured content
- Integrated CMS for creating, editing, and deleting repository-backed content
- Support for structured JSON data, including projects, friends, and about-page content
- Multi-user administration with bcrypt password hashing and JWT-based authentication
- Repository-backed publishing through the GitHub API
- Author ownership validation for editorial content
- Configurable site metadata, navigation, social links, comments, and page content
- Light and dark themes, seasonal themes, and optional visual effects
- GitHub contribution activity display
- Skills showcase and build information sections on the homepage
- Pagefind site search (available in production builds only)
- RSS, sitemap, robots.txt, and SEO metadata
- Responsive layouts designed for desktop and mobile environments
- Vercel deployment support
| Dependency | Requirement |
|---|---|
| Node.js | 22.12 or later |
| pnpm | 7.1 or later |
| Git | Any supported version |
Astro 6 requires Node.js
>=22.12.0. Earlier versions may fail to build the project.
Clone the repository and install the dependencies:
git clone https://github.com/Refac7/RefactX.git
cd RefactX
pnpm installCopy the environment template and fill in the required values:
cp example.env .envStart the development server:
pnpm devBy default, the development server is available at http://localhost:4321.
Create a production build:
pnpm buildThis command runs type checking, builds the Astro application, and generates the Pagefind search index for .vercel/output/static.
Preview the production build locally:
pnpm previewRefactX/
├── src/
│ ├── assets/ # Static and application assets
│ ├── components/ # Astro and React components
│ │ ├── admin/ # CMS administration interface
│ │ ├── base/ # Shared base components (search, header, contributions, etc.)
│ │ ├── dynamic/ # Dynamic feed components
│ │ ├── posts/ # Post cards, layouts, table of contents, and comments
│ │ ├── projects/ # Project presentation components
│ │ ├── theme/ # Theme controls
│ │ └── ui/ # General-purpose UI components
│ ├── content/
│ │ ├── data/ # Structured JSON content
│ │ └── posts/ # Markdown articles
│ ├── layouts/ # Application layouts (Header, Footer, Layout)
│ ├── lib/ # Utilities, authentication, and rate limiting
│ ├── pages/ # Routes and API endpoints
│ │ └── api/ # Server-side endpoints
│ ├── stores/ # Client-side state
│ ├── styles/ # Global and typography styles
│ ├── config.ts # Central site configuration
│ ├── content.config.ts # Content collection schemas
│ └── types.ts # Type definitions
├── plugins/ # Remark and Rehype extensions
├── scripts/ # Development and administration utilities
├── public/ # Public static files
├── astro.config.mjs # Astro configuration
├── package.json # Project dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── vercel.json # Deployment and cache header configuration
Primary site configuration is defined in src/config.ts. The configuration module controls site metadata, navigation, social links, post presentation, tag and author pages, project displays, the dynamic feed, message board, friends page, comments, CMS behavior, GitHub integration, and optional seasonal themes.
Typical site metadata:
export const SITE = {
title: 'RefactX Project',
description: 'A concise description of the site.',
website: 'https://example.com',
base: '/',
author: 'Author',
ogImage: '/og-image.webp',
version: '1.9',
footerText: 'Footer text',
footerText2: 'Secondary footer text',
}Review src/config.ts before deployment and replace the example values with values appropriate for the target site. Commonly used configuration exports include:
| Configuration | Purpose |
|---|---|
SITE |
Site title, description, domain, author, and OG image |
HEADER_LINKS / FOOTER_LINKS |
Header and footer navigation |
SOCIAL_LINKS |
Social platform links and icons |
POSTS_CONFIG |
Post list density, layout, default cover, and button labels |
TAGS_CONFIG / AUTHORS_CONFIG |
Tag and author page copy |
PROJECTS_CONFIG / DYNAMIC_CONFIG |
Project and dynamic feed page copy |
FRIENDS_CONFIG / FRIENDS_CONTACT |
Friends page and site owner card |
WALINE_CONFIG |
Comment server, CAPTCHA, and image upload settings |
CMS_CONFIG |
CMS toggle, GitHub repository, branch, and path prefix |
HOLIDAY_THEMES / HOLIDAY_EFFECTS |
Holiday theme dates and visual effects |
PAGE_LOADER_CONFIG |
Page transition loading animation |
Articles are stored as Markdown files in src/content/posts/. Each article uses YAML frontmatter to define its metadata:
---
title: Article Title
description: A concise summary of the article.
pubDate: 2026-01-01
updatedDate: 2026-01-02
author: Author Name
tags:
- Astro
- TypeScript
heroImage: cover.webp
heroImageLayout: right
heroImageAspectRatio: '16/9'
recommend: true
postType: jap
contentWarning: Content warning text
---Field reference:
| Field | Required | Description |
|---|---|---|
title |
Yes | Article title |
description |
Yes | Article summary used in listings and SEO |
pubDate |
Yes | Publication date |
updatedDate |
No | Last updated date |
author |
No | Author name; defaults to POSTS_CONFIG.author |
tags |
Yes | Array of tags |
heroImage |
No | Cover image. Local filenames resolve to /hero-images/; full URLs are used as-is; none disables the image |
ogImage |
No | OG image. Local filenames resolve to /og-images/; full URLs are used as-is; none disables the image |
heroImageLayout |
No | Cover layout, such as right |
heroImageAspectRatio |
No | Cover aspect ratio; defaults to 16/9 |
recommend |
No | Whether to feature the article; defaults to false |
postType |
No | Post layout variant, such as jap |
contentWarning |
No | Content warning notice |
Markdown files beginning with _ are excluded from the content collection and can be used for drafts or partial content.
The rendering pipeline lives in plugins/ and supports:
- Reading time estimation and low-quality image placeholders (LQIP)
- Custom directives for badges, links with favicons, and Bilibili embeds
- Math rendering via
remark-mathandrehype-katex - Callout blocks via
rehype-callouts - Heading anchors, external link handling, image unwrapping, and table wrappers
- Expressive Code blocks with collapsible sections and line numbers
Non-article content is stored as JSON under src/content/data/. The friends and projects collections are registered through a custom loader, while about.json is imported directly by the about page:
friends.json— friend linksprojects.json— project informationabout.json— about-page content
Structured data is not treated as an article and does not require post-specific fields such as author or pubDate.
Example friend entry:
{
"name": "Site Name",
"author": "Site Owner",
"url": "https://example.com",
"avatar": "https://example.com/avatar.png",
"description": "A concise description."
}Example project entry:
{
"name": "Project Name",
"description": "A concise project description.",
"githubUrl": "https://github.com/user/repository",
"website": "https://example.com",
"type": "icon",
"icon": "icon-[mdi--github]",
"star": 0,
"fork": 0
}githubUrl and website are optional; star and fork are required and may be provided as strings or numbers.
| Route | Description |
|---|---|
/ |
Homepage with navigation cards, recent posts, contributions, skills, and build information |
/posts |
Paginated post list |
/posts/[slug] |
Individual post |
/tags |
Tag overview |
/tags/[tag] |
Posts filtered by tag |
/authors |
Author overview |
/authors/[author] |
Posts by a specific author |
/projects |
Project showcase |
/dynamic |
Notion-backed dynamic feed with CAPTCHA verification |
/messageboard |
Message board |
/friends |
Friend links |
/about |
About page |
/admin |
CMS administration panel |
/api/auth |
Login and JWT issuance |
/api/captcha |
Proof-of-work CAPTCHA challenge and verification |
/api/dynamic |
Notion dynamic feed proxy |
/api/get-content, /api/list-files, /api/batch-commit, /api/next-filename, /api/repo-stats |
CMS repository operations |
/rss.xml |
RSS feed |
/404 |
Not found page |
Server-side endpoints must set export const prerender = false so they run as Vercel Serverless Functions.
The CMS is configured through CMS_CONFIG and uses a GitHub repository as its content store by default. Authentication supports multiple administrative users through the ADMIN_USERS environment variable.
Generate a password hash with:
# Default username: admin
node scripts/gen-hash.js <password>
# Specify a username
node scripts/gen-hash.js <username> <password>Add the result to .env:
ADMIN_USERS='{"username":"bcrypt-hash"}'
ADMIN_JWT_SECRET=<secure-random-secret>
CAPTCHA_SECRET=<secure-random-secret>CMS publishing also requires repository access:
GITHUB_TOKEN=<github-personal-access-token>The token must have permission to modify the repository and branch configured in CMS_CONFIG. Hashes may also be stored as base64 to avoid dotenv $ variable expansion; the server detects and decodes them automatically.
Authentication flow:
- The user enters a username and password.
- The client completes a proof-of-work CAPTCHA (SHA-256 difficulty check).
- The server verifies the CAPTCHA token, username, and bcrypt password hash.
- On success, the server issues a JWT valid for 2 hours; subsequent CMS requests use
Authorization: Bearer <token>. - Failed logins are rate-limited (5 failures lock the client IP for 15 minutes by default).
For full authentication, CAPTCHA, and rate-limiting details, see scripts/README.md.
Copy example.env to .env and fill in the required values.
| Variable | Required When | Purpose |
|---|---|---|
ADMIN_USERS |
CMS is enabled | Administrative users and bcrypt password hashes (JSON) |
ADMIN_JWT_SECRET |
CMS is enabled | JWT signing secret |
CAPTCHA_SECRET |
CAPTCHA is enabled | CAPTCHA HMAC signing secret |
GITHUB_TOKEN |
CMS publishing is enabled | GitHub repository access |
NOTION_API_KEY |
Dynamic feed is enabled | Notion API key |
NOTION_DATABASE_ID |
Dynamic feed is enabled | Notion database ID |
PUBLIC_WALINE_SERVER_URL |
Comments are enabled | Waline server endpoint |
PUBLIC_UPLOAD_TOKEN |
Image upload is enabled | Upload service credential |
PUBLIC_IMG_BED_URL |
Image upload is enabled | Image hosting endpoint |
Generate a random secret with:
openssl rand -hex 32Variables prefixed with PUBLIC_ are exposed to the client. Never put private credentials in them.
Never commit production credentials, access tokens, or private signing keys to the repository.
RefactX uses the @astrojs/vercel adapter by default and can be deployed to Vercel or other environments capable of running the Astro site and its server-side API endpoints.
- Fork or clone the repository.
- Import the project into Vercel.
- Configure the required environment variables.
- Review
src/config.ts,CMS_CONFIG, and the site domain. - Deploy the project.
Use pnpm build as the build command. Static assets are emitted to .vercel/output/static, and the Pagefind index is generated at the end of the build.
vercel.json configures baseline security headers and cache policies:
/_astro/*and/fonts/*use one-year immutable caching/pagefind/*uses a one-hour cache withstale-while-revalidate
Comment functionality is configured through WALINE_CONFIG and is available on post pages and the message board. Image uploads, Notion synchronization, and other integrations are enabled through public environment variables and site configuration.
External services are deployment dependencies. Their availability, security, and operational configuration are the responsibility of the site operator. Before deploying to production, verify that:
- The Waline server is deployed and connected to a database
- The Notion integration has access to the target database
- The image upload token and endpoint are valid
- The GitHub token uses the minimum required permissions
RefactX supports application-wide theme configuration, including light and dark modes. Optional date-based themes and seasonal effects can be configured through HOLIDAY_THEMES and HOLIDAY_EFFECTS.
The page transition loading animation is controlled by PAGE_LOADER_CONFIG and can be disabled for a simpler browsing experience.
Theme-related styles live in src/styles/global.css, and the holiday component is located at src/components/base/HolidayTheme.astro.
Before submitting changes, ensure that the project builds successfully:
pnpm buildOther common commands:
pnpm dev # Start the development server
pnpm format # Check formatting with Prettier
pnpm format:write # Automatically fix formattingDevelopment guidelines:
- Preserve the existing TypeScript contracts, content schemas, authentication boundaries, and repository-backed CMS behavior.
- Distinguish editorial posts from structured data. Post-specific validation must not be applied to JSON configuration or data entries that do not use article metadata.
- Pagefind search loads only when
import.meta.env.PRODis true and is unavailable in development mode. - React components are used as Astro islands; choose
client:load,client:visible, or another hydration directive as appropriate. - Inline scripts that rely on
is:inline(such as theme initialization) are emitted before bundling; take care when modifying them. - Content collections use Astro's loader-based API rather than the legacy
src/content/config.tspattern.
Contributions are welcome through issues and pull requests. Please keep changes focused, document behavior that affects configuration or deployment, and verify the production build before submitting a pull request.
For substantial changes, opening an issue before implementation is recommended so that the proposed approach can be discussed.
This project is distributed under the MIT License. See the repository license file for details.
RefactX is provided on an "AS IS" basis, without warranties or guarantees of any kind, express or implied. The repository maintainer is not obligated to provide continuous maintenance, support, or compatibility updates.
Operators are responsible for reviewing configuration, credentials, third-party integrations, and deployment security before using the project in production.