Skip to content

Remove auth/backend; convert entire site to static MDX blog#80

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/remove-auth-and-backend
Draft

Remove auth/backend; convert entire site to static MDX blog#80
Copilot wants to merge 3 commits intomainfrom
copilot/remove-auth-and-backend

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

Eliminates all runtime dependencies (database, auth, R2 storage, dashboard) and converts the site to a fully static MDX blog driven by files in public/posts/.

Core changes

  • REQUIREMENTS.md — RFC 2119 spec for the static blog (content format, file naming, rendering, no-auth constraints)
  • src/lib/posts.ts — new file-based post layer; reads public/posts/**/*.md, parses YAML frontmatter via yaml, filters to state: published, extracts slug/date from filename convention
    YYYY_MM_DD_slug.md          → flat post
    YYYY_MM_DD_slug/document.md → post with media assets
    
    Exports: getAllPosts, getPostBySlug, getPostsByTag, getPostImagePath

Rendering

  • posts/[slug]/page.tsx uses generateStaticParams — all post pages are now SSG
  • Post.tsx converted to RSC using next-mdx-remote/rsc; inline Image MDX component resolves to /posts/{dirName}/media/{src}
  • Category pages (/posts/tech, /travel, /food) use getPostsByTag
  • Removed force-dynamic from home and posts list pages

Deleted

  • src/app/auth.ts, src/app/api/auth/, src/lib/auth.* — NextAuth
  • src/database/, src/models/, drizzle/, drizzle.config.ts — Drizzle + LibSQL
  • src/app/dashboard/ — entire admin UI
  • src/app/api/posts/{uploads,sync}/ — R2 upload and sync endpoints
  • src/lib/r2/, bin/ — R2 utilities and CLI scripts
  • playwright.fixtures.ts, auth/journal/CRUD tests

Dependencies

  • Removed: next-auth, drizzle-orm, @libsql/client, sonner, react-highlight, react-markdown, @aws-sdk/client-s3, posthog-node, drizzle-kit, sqld
  • Upgraded React 18 → 19 (required: Next.js 15.4.8 bundles React 19 canary; mismatched $$typeof symbols caused RSC prerender failures with next-mdx-remote/rsc)
  • Fixed malformed YAML frontmatter in one post (title: Scytale: … → quoted)

Config

  • wrangler.jsonc — removed TURSO_*, AUTH_*, NEXT_PUBLIC_R2_DOMAIN vars and R2 bucket binding
  • next.config.js — removed serverExternalPackages, serverRuntimeConfig, remote image patterns for gravatar/R2

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Mar 19, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
ncrmro-website 5cb47e6 Mar 19 2026, 04:20 AM

…ePath helpers

Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com>
Copilot AI changed the title [WIP] Remove authentication and backend systems for MDX site Remove auth/backend; convert entire site to static MDX blog Mar 19, 2026
Copilot AI requested a review from ncrmro March 19, 2026 04:24
@ncrmro ncrmro requested a review from Copilot March 27, 2026 17:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Converts the site from an authenticated, database-backed app into a fully static, file-driven MDX blog with published posts sourced from public/posts/.

Changes:

  • Remove auth, database, dashboard UI, and content-mutation APIs/utilities (including R2 upload/sync tooling).
  • Add a filesystem-based posts layer (src/lib/posts.ts) and update post listing/tag pages + post detail rendering to use it.
  • Update runtime/config/tests/deps to reflect static operation (wrangler vars, Next config, Playwright tests, React 19).

Reviewed changes

Copilot reviewed 61 out of 67 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
wrangler.jsonc Remove DB/auth/R2 vars and bucket bindings.
tests/posts.spec.ts Replace CRUD/admin E2E with static blog smoke tests.
tests/journal_entry.spec.ts Remove journal/dashboard E2E test.
tests/example.spec.ts Remove login E2E test.
tests/admin_access.spec.ts Remove dashboard access-control E2E tests.
src/models/posts.ts Remove DB-backed post/tag/journal model layer.
src/lib/r2/upload.ts Remove R2 upload utilities.
src/lib/r2/image-url.ts Remove R2 image URL helpers.
src/lib/r2/check.ts Remove R2 existence/listing utilities.
src/lib/posts.ts Add filesystem-backed post loader/filtering/tag helpers.
src/lib/database.ts Remove database re-export shim.
src/lib/auth.ts Remove password/gravatar/auth helpers.
src/lib/auth.config.ts Remove NextAuth edge config.
src/database/schema.users.ts Remove Drizzle user/session schema.
src/database/schema.ts Remove schema re-export entrypoint.
src/database/schema.posts.ts Remove Drizzle posts/tags schema.
src/database/schema.journal.ts Remove Drizzle journal schema.
src/database/index.ts Remove DB client creation and helpers.
src/app/sitemap.xml/route.ts Generate sitemap from filesystem posts instead of DB.
src/app/posts/types.ts Update post type to match filesystem-backed shape.
src/app/posts/travel/page.tsx Render travel tag page from filesystem posts.
src/app/posts/tech/page.tsx Render tech tag page from filesystem posts (deduping tags).
src/app/posts/page.tsx Make posts index no longer force dynamic rendering.
src/app/posts/food/page.tsx Render food tag page from filesystem posts.
src/app/posts/actions.ts Remove server action for MDX serialization.
src/app/posts/[slug]/page.tsx Switch post page to SSG (generateStaticParams) + filesystem lookup.
src/app/posts/[slug]/Post.tsx Convert post rendering to RSC MDX (next-mdx-remote/rsc) + local media paths.
src/app/posts/Posts.tsx Use filesystem posts for the posts list.
src/app/posts/PostItem.tsx Simplify post list items for the static blog.
src/app/page.tsx Remove forced dynamic home rendering.
src/app/layout.tsx Remove toast provider tied to removed dashboard flows.
src/app/dashboard/posts/page.tsx Remove dashboard posts list UI.
src/app/dashboard/posts/new/page.tsx Remove dashboard “new post” UI/action.
src/app/dashboard/posts/layout.tsx Remove dashboard posts layout wrapper.
src/app/dashboard/posts/form_media.tsx Remove dashboard media UI (R2-backed).
src/app/dashboard/posts/form_fields.tsx Remove dashboard post metadata form fields.
src/app/dashboard/posts/form.tsx Remove dashboard post editor form.
src/app/dashboard/posts/[slug]/page.tsx Remove dashboard post edit page.
src/app/dashboard/posts/PostsFilters.tsx Remove dashboard posts filtering UI.
src/app/dashboard/page.tsx Remove dashboard landing page.
src/app/dashboard/layout.tsx Remove dashboard auth-gated layout.
src/app/dashboard/layout.client.tsx Remove dashboard client layout.
src/app/dashboard/journal/page.tsx Remove journal UI/page.
src/app/dashboard/journal/layout.tsx Remove journal layout.
src/app/dashboard/journal/form.tsx Remove journal entry form.
src/app/auth.ts Remove NextAuth setup and helpers.
src/app/api/posts/uploads/route.ts Remove uploads API route.
src/app/api/posts/sync/route.ts Remove posts sync API route.
src/app/api/auth/[...nextauth]/route.ts Remove NextAuth route handler.
public/posts/2020_08_23_scytale-automated-private-key-infrastructure.md Fix YAML frontmatter quoting for title.
playwright.fixtures.ts Remove DB/auth-based Playwright fixtures.
package.json Remove DB/auth/R2 deps; move to React 19/types.
next.config.js Remove server runtime config and remote image patterns tied to auth/R2.
drizzle/meta/_journal.json Remove Drizzle migration metadata.
drizzle/meta/0002_snapshot.json Remove Drizzle schema snapshot.
drizzle/meta/0001_snapshot.json Remove Drizzle schema snapshot.
drizzle/meta/0000_snapshot.json Remove Drizzle schema snapshot.
drizzle/0002_cultured_marvel_apes.sql Remove Drizzle migration SQL.
drizzle/0001_demonic_madelyne_pryor.sql Remove Drizzle migration SQL.
drizzle/0000_lame_wendell_vaughn.sql Remove Drizzle migration SQL.
drizzle.config.ts Remove Drizzle kit configuration.
bin/sync-posts.ts Remove posts sync CLI.
bin/migrate-images.ts Remove R2 image migration script.
bin/generate-password.ts Remove password generation/admin script.
bin/claude Remove local Claude/MCP helper script.
REQUIREMENTS.md Add RFC2119 requirements for the static filesystem-driven blog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +52 to +53
export function getAllPosts(): PostData[] { const entries = fs.readdirSync(POSTS_DIR);
const posts: PostData[] = [];
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 52 has export function getAllPosts(): PostData[] { const entries = ... on one line. This looks like an accidental formatting issue and may violate repo lint/prettier rules; please split the function body onto a new line for readability.

Copilot uses AI. Check for mistakes.
Comment on lines 45 to +53
code: (p: any) => {
// Check if this is a code block (has language class) or inline code
const isCodeBlock = p.className && p.className.startsWith('language-');

const isCodeBlock =
p.className && p.className.startsWith("language-");
if (isCodeBlock) {
// Use Highlight for syntax-highlighted code blocks with vertical spacing
return (
<div className="my-4">
<Highlight className={p.className}>{p.children}</Highlight>
</div>
<code
className="font-mono text-gray-800 dark:text-gray-200"
{...p}
/>
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the MDX code renderer, className is set and then {...p} is spread after it, which will override className (and any other props you set) when p.className exists. Spread props first or explicitly merge className values so code blocks keep the intended styling.

Copilot uses AI. Check for mistakes.
Comment on lines 75 to 81
Image: (p: any) => (
<div style={{ display: "flex", justifyContent: "center" }}>
{/*// @ts-ignore/*/}
<NextImage
{...props}
<img
alt={p.alt}
width={500}
height={500}
src={`https://r2.ncrmro.com/uploads/posts/${props.post.id}/${p.src}`}
style={{ maxWidth: "100%", height: "auto" }}
src={getPostImagePath(props.post, p.src)}
/>
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MDX Image component renders an <img> with alt={p.alt}. If alt isn’t provided in MDX, this produces a missing/undefined alt attribute; for accessibility it’s better to default to an empty string (decorative) or require alt text. Also consider adding loading="lazy"/decoding="async" since this bypasses next/image optimizations.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to 21
function TechnologyPosts() {
const postsList = getPostsByTag("food");

return (
<div></div>
// <PageLayout>
// <Posts posts={props.posts} />
// </PageLayout>
<ul role="list" className="-mb-8">
{postsList.map((post, index: number) => (
<PostItem
key={post.slug}
post={post}
evenRow={index !== postsList.length - 1}
/>
))}
</ul>
);
}
// export const getStaticProps: GetStaticProps = async (context) => {
// return {
// props: { posts: [], }
// };
// };

export default TechnologyPosts;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page is for the food category, but the component is still named TechnologyPosts/exported as TechnologyPosts, which is misleading for future maintenance. Rename the component/export to something food-specific (e.g., FoodPosts).

Copilot uses AI. Check for mistakes.
Comment on lines 17 to 22
<a
href={
props.dashboard
? `/dashboard/posts/${props.post.slug}`
: `/posts/${props.post.slug}`
}
href={`/posts/${props.post.slug}`}
className="font-medium text-gray-900 dark:text-white"
>
{props.post.title}
</a>
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostItem uses a plain <a href> for internal navigation to /posts/[slug]. In Next.js app router, using next/link avoids full page reloads and preserves client-side navigation behavior. Consider switching this to <Link href={...}> for consistency with other internal links (e.g., Navbar/projects pages).

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +93
tags: frontmatter.tags
? frontmatter.tags.split(",").map((t) => t.trim())
: [],
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tags parsing currently does split(',').map(trim) but doesn’t filter out empty strings, so frontmatter like tags: tech, will produce an empty tag entry. Consider adding a .filter(Boolean) after trimming to keep tag lists clean.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
import fs from "fs";
import path from "path";
import YAML from "yaml";
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this module imports Node fs and should never be bundled into client code, consider adding import "server-only"; at the top. This prevents accidental client imports that would break builds/runtime when fs is unavailable.

Copilot uses AI. Check for mistakes.
Comment on lines 12 to +18
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;

const [postResult] = await db
.select({
id: posts.id,
title: posts.title,
description: posts.description,
slug: posts.slug,
publishDate: posts.publishDate,
})
.from(posts)
.where(eq(posts.slug, slug));
const post = getPostBySlug(slug);
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page props type uses params: Promise<{ slug: string }> and then await params. In Next.js, params is passed as a plain object; await works but the typing is misleading and can confuse future changes. Consider typing params as { slug: string } and removing the unnecessary await.

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +60
1. The site MUST NOT require authentication to view any public page.
2. The site MUST NOT require a database connection at runtime.
3. The site MUST NOT expose any login, dashboard, or admin routes.
4. The site MUST NOT include any server-side API routes for content mutation
(e.g. creating, editing, or deleting posts).
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUIREMENTS.md states the site MUST NOT expose any dashboard/admin routes, but the UI still conditionally renders a Dashboard link in src/components/Navbar.tsx when a viewer_session cookie exists. To align the implementation with these requirements (and the PR’s stated removal of auth/admin), that link/cookie check should be removed as part of this change set.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +49
function parseFrontmatter(content: string): {
frontmatter: PostFrontmatter;
body: string;
} {
if (!content.startsWith("---")) {
return { frontmatter: {}, body: content };
}
const end = content.indexOf("---", 3);
if (end === -1) {
return { frontmatter: {}, body: content };
}
const yamlStr = content.slice(3, end).trim();
const body = content.slice(end + 3).trim();
const frontmatter = (YAML.parse(yamlStr) as PostFrontmatter) ?? {};
return { frontmatter, body };
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseFrontmatter() finds the closing delimiter via content.indexOf('---', 3), which can terminate early if --- appears in YAML values or near the top of the body (e.g., a Markdown horizontal rule). Consider matching the closing delimiter only when it appears on its own line (e.g., \n---\n) or using a frontmatter regex/parser so MDX content can safely include ---.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants