diff options
| author | Bertrand Yuan <me@bertyuan.com> | 2026-04-27 20:52:54 +0800 |
|---|---|---|
| committer | Bertrand Yuan <me@bertyuan.com> | 2026-04-27 20:53:14 +0800 |
| commit | dbb5e791f0c228369605d126dd590962ebe1eddc (patch) | |
| tree | 8c83fc84bd9547630e6733929dec77e102e055a8 /Documentation/source/architecture | |
| parent | 658798b3a2378bb6df16cfbb16d707c6fb719e1e (diff) | |
docs: add comprehensive documentation for operations
This commit introduces a complete set of documentation files
covering various aspects of the project, including environment
setup, quality checks, command references, and architecture.
The documentation is structured to assist developers and
contributors in understanding the project's configuration,
workflow, and best practices.
Additionally, translations for Simplified and Traditional
Chinese have been added to ensure accessibility for a wider
audience. This enhances the overall usability and
maintainability of the project.
Signed-off-by: Bertrand Yuan <github@bertyuan.com>
Diffstat (limited to 'Documentation/source/architecture')
| -rw-r--r-- | Documentation/source/architecture/content-model.rst | 65 | ||||
| -rw-r--r-- | Documentation/source/architecture/data-and-auth.rst | 72 | ||||
| -rw-r--r-- | Documentation/source/architecture/distribution.rst | 45 | ||||
| -rw-r--r-- | Documentation/source/architecture/index.rst | 15 | ||||
| -rw-r--r-- | Documentation/source/architecture/risks.rst | 55 | ||||
| -rw-r--r-- | Documentation/source/architecture/system-overview.rst | 61 |
6 files changed, 313 insertions, 0 deletions
diff --git a/Documentation/source/architecture/content-model.rst b/Documentation/source/architecture/content-model.rst new file mode 100644 index 0000000..12ed092 --- /dev/null +++ b/Documentation/source/architecture/content-model.rst @@ -0,0 +1,65 @@ +Content Model +============= + +Payload CMS is configured in ``payload.config.ts`` and collection definitions +live under ``src/payload/collections``. + +Collections +----------- + +.. list-table:: + :header-rows: 1 + :widths: 18 58 + + * - Collection + - Purpose + * - ``Posts`` + - Blog entries with slug, summary, rich text body, status, tags, + publication time, author, and optional featured image. + * - ``Users`` + - Admin users for Payload and shared user representation. + * - ``Media`` + - Uploaded images and assets used by posts and the admin. + +Post Lifecycle +-------------- + +Posts are authored in Payload and exposed publicly only when their status is +``published``. Public queries in ``src/lib/payload-posts.ts`` consistently +filter on this status before returning data to pages, feeds, search, or tag +views. + +The normalized frontend shape is ``BlogPost``. It includes: + +* ``id`` and ``slug`` for stable identity; +* ``url`` for public route generation; +* ``title`` and ``description`` for listing and metadata; +* ``content`` for Lexical rich text rendering; +* ``image`` for cover or preview assets; +* ``author`` and dates for byline display; +* ``tags`` for topic navigation. + +Tag Strategy +------------ + +Tags are currently embedded in post documents and counted in memory by +``getAllTags``. This is simple and sufficient for a small blog. If content +volume grows, tag aggregation should move closer to the database or a cached +index. + +MDX Content +----------- + +The ``content`` directory is processed by Fumadocs through ``source.config.ts``. +Its frontmatter includes date, author, tags, and optional image fields. Treat +MDX content as local authored pages, distinct from Payload-managed posts. + +Generated Types +--------------- + +Payload writes generated TypeScript types to ``payload-types.ts``. Regenerate +them after collection schema changes: + +.. code-block:: bash + + pnpm payload:generate diff --git a/Documentation/source/architecture/data-and-auth.rst b/Documentation/source/architecture/data-and-auth.rst new file mode 100644 index 0000000..44736bd --- /dev/null +++ b/Documentation/source/architecture/data-and-auth.rst @@ -0,0 +1,72 @@ +Data, Auth, and Comments +======================== + +Database Ownership +------------------ + +The repository uses PostgreSQL for both CMS data and application-owned data. +The separation is logical: + +* Payload stores CMS data in the ``payload`` schema. +* Application auth and comments use Drizzle schema objects and ``blog_*`` + tables. + +This keeps CMS-managed structures separate from reader interaction data and +allows application migrations to evolve without coupling every change to +Payload internals. + +Authentication +-------------- + +Authentication is configured in ``src/server/auth/index.ts`` with better-auth +and the Drizzle adapter. Current providers: + +* Google OAuth; +* GitHub OAuth. + +The user model includes an additional ``role`` field with a default value of +``user``. Session lookup is wrapped by ``getSession`` so route and component +code does not need to call the better-auth API directly. + +Comments +-------- + +Comments are configured in ``src/server/comments/config.ts``. The Fuma Comments +storage adapter receives the Drizzle database connection and these schemas: + +* ``comments``; +* ``rates``; +* ``roles``; +* ``users``. + +The comment API route is mounted under ``/api/comments/[...comment]``. Frontend +comment rendering belongs on post detail pages, while moderation and role +policy should remain server-controlled. + +Migration Commands +------------------ + +.. list-table:: + :header-rows: 1 + :widths: 26 50 + + * - Command + - Use + * - ``pnpm db:generate`` + - Generate Drizzle migration files after schema changes. + * - ``pnpm db:migrate`` + - Apply Drizzle migrations. + * - ``pnpm db:push`` + - Push schema changes directly during local development. + * - ``pnpm payload:migrate`` + - Run Payload migrations. + * - ``pnpm payload:migrate:create`` + - Create a new Payload migration. + +Implementation Rule +------------------- + +When adding data-backed features, decide first whether the data is editorial or +application-owned. Editorial content should be modeled in Payload collections. +Account, interaction, moderation, and operational records should be modeled in +Drizzle. diff --git a/Documentation/source/architecture/distribution.rst b/Documentation/source/architecture/distribution.rst new file mode 100644 index 0000000..80b87d0 --- /dev/null +++ b/Documentation/source/architecture/distribution.rst @@ -0,0 +1,45 @@ +Search, Feeds, and Metadata +=========================== + +The application exposes several distribution surfaces in addition to HTML +pages. These endpoints help readers, search clients, crawlers, and social +previews consume the site. + +Search +------ + +The search index endpoint lives at ``src/app/(main)/api/search/route.ts`` and +is served from ``/api/search``. It is intended for the Fumadocs search UI and +should return normalized, public, published content only. + +Feeds +----- + +The feed route lives at ``src/app/(main)/rss.xml/route.ts`` and is exposed as +``/rss.xml``. Keep this canonical path consistent in page metadata, sitemap +configuration, and external documentation. + +Open Graph Images +----------------- + +Dynamic image generation is implemented under: + +* ``src/app/(main)/banner.png`` for site-level banner output; +* ``src/app/(main)/og/[...slug]`` for post-specific Open Graph output. + +The font JSON assets in these folders support image rendering. Treat them as +runtime assets for the route handlers. + +Metadata +-------- + +Metadata helpers live in ``src/lib/metadata.ts`` and page-level JSON-LD +rendering is handled by ``src/components/json-ld.tsx``. New public routes +should define metadata intentionally instead of relying on generic defaults. + +Sitemap +------- + +``next-sitemap.config.cjs`` controls sitemap generation after application +builds. Generated ``public/robots.txt`` and ``public/sitemap*.xml`` are ignored +by Git and should be regenerated by the build pipeline. diff --git a/Documentation/source/architecture/index.rst b/Documentation/source/architecture/index.rst new file mode 100644 index 0000000..34d2630 --- /dev/null +++ b/Documentation/source/architecture/index.rst @@ -0,0 +1,15 @@ +Architecture +============ + +This section documents how the major subsystems fit together: the public +frontend, Payload CMS, database-backed application services, content rendering, +and distribution endpoints. + +.. toctree:: + :maxdepth: 2 + + system-overview + content-model + data-and-auth + distribution + risks diff --git a/Documentation/source/architecture/risks.rst b/Documentation/source/architecture/risks.rst new file mode 100644 index 0000000..604bc78 --- /dev/null +++ b/Documentation/source/architecture/risks.rst @@ -0,0 +1,55 @@ +Risks and Technical Debt +======================== + +This page tracks known architectural risks and follow-up work. Keep entries +short, actionable, and tied to repository evidence. + +Current Risk Register +--------------------- + +.. list-table:: + :header-rows: 1 + :widths: 10 26 28 30 + + * - Priority + - Finding + - Evidence + - Recommendation + * - P0 + - Email utility type dependency should be verified. + - ``src/lib/resend.ts`` imports project-local types. + - Keep type sources explicit and covered by type checks. + * - P0 + - Payload secret fallback is unsafe for production. + - ``payload.config.ts`` falls back to ``your-secret-key``. + - Fail fast in production when ``PAYLOAD_SECRET`` is missing. + * - P1 + - RSS canonical path must stay consistent. + - Route is ``/rss.xml``. + - Use the same path in metadata, README, docs, and sitemap config. + * - P1 + - In-memory aggregation can become expensive. + - Search, RSS, and tag counts read batches of posts. + - Add caching or database-side aggregation when content volume grows. + * - P1 + - Canonical URL configuration needs production hardening. + - Deployment URL handling depends on environment conventions. + - Prefer an explicit public site URL for production. + * - P2 + - Comment role governance needs policy tests. + - Comment storage includes roles. + - Define moderation behavior before adding privileged comment actions. + +Roadmap +------- + +Phase 1: correctness and configuration hardening + Fix production secret handling, verify email types, and align feed paths. + +Phase 2: scalability + Cache expensive public indexes, move tag aggregation closer to storage, and + add clear revalidation boundaries. + +Phase 3: governance + Add architecture decision records, route-level integration tests, and CI + checks for type safety, tests, linting, and documentation links. diff --git a/Documentation/source/architecture/system-overview.rst b/Documentation/source/architecture/system-overview.rst new file mode 100644 index 0000000..c876096 --- /dev/null +++ b/Documentation/source/architecture/system-overview.rst @@ -0,0 +1,61 @@ +System Overview +=============== + +Layered View +------------ + +.. list-table:: + :header-rows: 1 + :widths: 22 34 44 + + * - Layer + - Main Files + - Responsibility + * - Presentation + - ``src/app/(main)``, ``src/components`` + - Render public pages, route handlers, shared UI, rich text, and layout. + * - Content access + - ``src/lib/payload-posts.ts`` + - Query Payload and normalize CMS documents into frontend-friendly types. + * - CMS admin + - ``payload.config.ts``, ``src/payload``, ``src/app/(payload)`` + - Define editorial collections and expose the admin experience. + * - Auth and comments + - ``src/server/auth``, ``src/server/comments`` + - Authenticate users and persist comment data. + * - Data + - ``src/server/db``, ``src/migrations`` + - Own Drizzle schema, connection setup, and application migrations. + * - Content pipeline + - ``content``, ``source.config.ts`` + - Build local MDX content through Fumadocs. + +Request Flow: Reading a Post +---------------------------- + +1. A route under ``src/app/(main)/(home)/posts/[slug]`` receives a slug. +2. The server component calls ``getPostBySlug``. +3. ``src/lib/payload-posts.ts`` obtains a Payload client and queries + ``posts`` where ``status`` is ``published``. +4. The raw Payload document is transformed into ``BlogPost``. +5. The page renders rich text content and mounts client-side interactions such + as sharing and comments. + +Request Flow: Writing a Comment +------------------------------- + +1. The post detail page renders the Fuma Comments client component. +2. The client calls ``/api/comments/[...comment]``. +3. The route delegates to the Fuma Comments Next.js handler. +4. better-auth validates the session. +5. The Drizzle adapter writes comment, rate, and role data to application-owned + tables. + +Boundaries +---------- + +Payload owns editorial content and media metadata. The application owns auth, +comments, UI state, route behavior, and integration logic. Keep that boundary +clear when adding features: editorial fields belong in Payload collections; +reader interaction and account behavior belong in ``src/server`` and the app +routes. |
