yufan.me has strict architecture conventions enforced by the layer model and documented inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/syhily/yufan.me/llms.txt
Use this file to discover all available pages before exploring further.
AGENTS.md files throughout the codebase. These rules exist to keep the import graph acyclic, bundles analyzable, and server-only code out of the browser. This page summarises every rule you must follow before opening a pull request.
Import layer rules
Five top-level layers undersrc/ form a one-way import graph. Violating this graph is caught at review time by the import/no-cycle lint rule and at build time by Vite’s module boundary checks.
| Layer | May import | Must NOT import |
|---|---|---|
routes/* | Any layer | — |
server/* | shared/*, other server/* | client/*, ui/* |
client/*, ui/* | shared/*, ui/*, client/* | server/*, any .server.* file |
shared/* | shared/* only | Everything else |
server/* domain files.
File naming rules
Thesrc/server/domains/ tree uses a locked vocabulary. Every domain folder may contain only these filenames:
| Filename | Purpose |
|---|---|
schema.ts | Drizzle table definitions and column types |
repo.ts | Database queries (reads and writes) |
service.ts | Business logic that coordinates repo + cache calls |
projection.ts | Read-model projections (query-side shaping) |
cache.ts | Redis cache helpers scoped to this domain |
- No barrel
index.tsfiles anywhere in the project. The oxlint ruleoxc/no-barrel-fileis set toerror. Import from the specific file directly. - Do not use the
.server.tssuffix insidesrc/server/. The suffix is redundant there and misleading. It is only meaningful insrc/routes/andsrc/shared/where a file must be excluded from the browser bundle. - Path alias:
@/*maps to./src/*. Always use the alias for cross-directory imports; never use relative../chains that cross a layer boundary.
What NOT to add
The following patterns were removed from the codebase deliberately. Do not reintroduce them:- Forbidden directories:
src/actions,src/middleware,src/layouts,src/services,src/hooks,src/db,src/assets/scripts,src/content - Forbidden files/names:
src/blog.config.ts, any export namedDEFAULT_SETTINGS,BlogConstants, or a per-section “reset to defaults” action - Monolithic config context: no
BlogConfigContextor<BlogConfigProvider>. Manage settings state with per-section hooks instead - Parallel lib directory: no
src/lib/alongside@/ui/lib. Shared utilities belong insrc/shared/orsrc/ui/lib/as appropriate - Preserved routes: do NOT remove or rename public URLs, feed URLs, image endpoints, WordPress compatibility routes, or pagination routes unless explicitly asked to do so
Git commit format
Commits must follow semantic commit conventions and be written in English:feat, fix, docs, refactor, test, chore
Good examples:
TypeScript and tooling conventions
- React 19 TSX/TS only. No
.jsor.jsxfiles. - React Router 7 framework mode with SSR —
appDirectory: 'src'inreact-router.config.ts. Do not reach outside the framework abstractions. - Formatting is handled by Oxfmt (via
vp check): 2-space indent, single quotes, no semicolons, trailing commas, LF line endings, print width 120. - Linting is handled by Oxlint with the configuration in
oxlint.config.ts. Runvp lintto check. Notable enforced rules:oxc/no-barrel-file(error),import/no-cycle(warn),typescript/no-floating-promises(error). - Imports are sorted automatically by Oxfmt. The order is: type imports → built-ins and external → internal type → internal value → parent/sibling/index.
Adding an oRPC endpoint
Follow these three steps when adding a new API procedure:Define the shared contract
Add or extend the Zod schema in
src/shared/contracts/<domain>.ts. Include a compile-time parity assertion against the matching type in src/shared/types/ to ensure the DTO stays in sync with the database model.If the procedure is small and self-contained, you may define the schema inline next to the procedure definition instead.Add a procedure to the controller
Add the procedure to the matching controller file in
src/server/http/controllers/. Pick the correct base procedure for the required permission level:| Base procedure | Who can call it |
|---|---|
publicProc | Any visitor, unauthenticated |
authedProc | Any signed-in user |
authorProc | Users with the Author role |
adminProc | Users with the Admin role |
Audit log rule
Every admin operation that mutates state (create, update, delete, publish, unpublish) must emit an audit event:list, get, search) must NOT emit audit events. This rule is not lint-enforced — it is a code review requirement.