diff options
| author | Bertrand Yuan <189593334+bertyuan@users.noreply.github.com> | 2026-04-27 20:54:16 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-27 20:54:16 +0800 |
| commit | 85b6fb59db5fe1112c58eff9d02ae4f9c9b6456d (patch) | |
| tree | 8c83fc84bd9547630e6733929dec77e102e055a8 /Documentation/source/architecture | |
| parent | 658798b3a2378bb6df16cfbb16d707c6fb719e1e (diff) | |
| parent | dbb5e791f0c228369605d126dd590962ebe1eddc (diff) | |
Merge pull request #21 from bertyuan/Documentationv1.2
docs: add comprehensive documentation for operations
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. |
