Files
sase.tr/apps/web/package.json
Semih Yesilyurt e5c852b537 feat(blog): data-driven blog API + DB for content-pipeline publishing
Makes the blog publishable from the Süper Panel content pipeline (via n8n).
Backend mirrors the changelog module; frontend keeps the existing hand-authored
posts and merges in API-backed ones (no content migration, no regression).

API (apps/api):
- blog_posts Drizzle table (slug unique, title, meta_description, body_markdown,
  tags, cover_image, status, source, published_at)
- blog module: GET /blog/posts (public list), GET /blog/posts/:slug (public),
  POST /blog/posts/internal (Bearer BLOG_AUTOMATION_TOKEN, mirrors
  changelog/internal) — returns { ...post, url }
- BlogService: Drizzle + Redis cache, defensive Turkish-aware slugify +
  uniqueness; registered in app.module

Web (apps/web):
- use-blog hooks (list + by-slug, react-query, 30m staleTime)
- blog list: static + API merged, dedup by slug, newest first
- blog detail: static post renders as before; API post renders body_markdown
  via react-markdown (remark-gfm) styled to match existing prose
- add react-markdown + remark-gfm

Deploy: set BLOG_AUTOMATION_TOKEN (and optional PUBLIC_WEB_URL) on the api,
run drizzle-kit db:push to create blog_posts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 01:48:10 +03:00

63 lines
1.8 KiB
JSON

{
"name": "web",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"generate-routes": "tsr generate",
"build": "tsr generate && tsc -b && vite build",
"prerender": "node scripts/prerender.mjs",
"preview": "vite preview --port 3000",
"lint": "biome check src/",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests",
"test:watch": "vitest",
"clean": "rm -rf dist"
},
"dependencies": {
"@cardog-icons/react": "^1.1.1",
"@grafana/faro-web-sdk": "^2.2.4",
"@grafana/faro-web-tracing": "^2.2.4",
"@remotion/player": "^4.0.422",
"@sase/shared": "workspace:*",
"@sase/ui": "workspace:*",
"@tanstack/react-query": "^5.62.0",
"@tanstack/react-router": "^1.120.0",
"better-auth": "^1.2.0",
"canvas-confetti": "^1.9.4",
"clsx": "^2.1.0",
"lucide-react": "^0.468.0",
"posthog-js": "^1.347.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-markdown": "^9.1.0",
"remark-gfm": "^4.0.1",
"remotion": "^4.0.422",
"sileo": "^0.0.7",
"tailwind-merge": "^2.6.0",
"zod": "^3.24.0",
"zustand": "^5.0.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.0.0",
"@tailwindcss/vite": "^4.0.0",
"@tanstack/react-router-devtools": "^1.120.0",
"@tanstack/router-cli": "^1.159.4",
"@tanstack/router-plugin": "^1.120.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/canvas-confetti": "^1.9.0",
"@types/node": "^22.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.5.0",
"jsdom": "^28.0.0",
"postcss": "^8.4.0",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.0",
"vite": "^6.3.0",
"vitest": "^3.2.4"
}
}