feat(zero): admin panel section + site /zero page + autogen card

Admin (/admin/zero):
  - new AdminZero with list, status filters, generate button (bucket + allow_dup)
  - per-note actions: approve, edit inline, regenerate (bucket pick), skip,
    'publish now' (approve + scheduled_at=now → runner picks up within 1m)
  - config panel: toggle on/off, generate/approve/publish hour MSK, site URL base
  - new pin 'Зеро' () in AdminNav

Site (zeropost.ru):
  - ZeroBlock — feed of last 3-6 Zero notes, rendered on home next to Серии
  - /zero — full Zero notes list page with character bio block (avatar + bullets)

Autogen integration:
  - ZeroAutogenCard on /admin/autogen — amber card with on/off, hour pickers,
    'generate now' and last-3 preview, link to full section

Plumbing:
  - lib/engine.js: listZeroNotes(), getZeroCharacter()
  - app/admin/api/zero/[...path]/route.js: catch-all proxy with cookie auth
This commit is contained in:
Aleksei Pavlov
2026-06-19 11:17:19 +03:00
parent cbcc8177f6
commit 8700b8fc69
10 changed files with 904 additions and 6 deletions
+14 -3
View File
@@ -6,12 +6,13 @@ import HeroImage from '@/components/HeroImage';
import Stats from '@/components/Stats';
import NowBlock from '@/components/NowBlock';
import NotesBlock from '@/components/NotesBlock';
import ZeroBlock from '@/components/ZeroBlock';
import SeriesGrid from '@/components/SeriesGrid';
import CategoryRow from '@/components/CategoryRow';
import PopularBlock from '@/components/PopularBlock';
import RecentBlock from '@/components/RecentBlock';
import Reveal from '@/components/Reveal';
import { getHomeData, listTags, getStats, getLive, listNotes, listSeries, listCategories } from '@/lib/engine';
import { getHomeData, listTags, getStats, getLive, listNotes, listSeries, listCategories, listZeroNotes } from '@/lib/engine';
import { Sparkles, ArrowRight } from 'lucide-react';
export const dynamic = 'force-dynamic';
@@ -20,10 +21,10 @@ const CATEGORY_ORDER = ['ai-tools', 'ai-dev', 'automation', 'cybersec'];
export default async function HomePage() {
let home = { hero: null, byCategory: {}, popular: [], recent: [] };
let tags = [], stats = null, live = null, notes = [], series = [], categories = [];
let tags = [], stats = null, live = null, notes = [], series = [], categories = [], zeroNotes = [];
try {
[home, tags, stats, live, notes, series, categories] = await Promise.all([
[home, tags, stats, live, notes, series, categories, zeroNotes] = await Promise.all([
getHomeData(),
listTags(),
getStats(),
@@ -31,6 +32,7 @@ export default async function HomePage() {
listNotes({ limit: 6 }),
listSeries(),
listCategories(),
listZeroNotes({ limit: 6 }),
]);
} catch (err) {
console.error('Home load failed:', err.message);
@@ -131,6 +133,15 @@ export default async function HomePage() {
</Reveal>
)}
{/* ЗЕРО — короткие заметки AI-персонажа */}
{zeroNotes.length > 0 && (
<Reveal>
<div className="reveal">
<ZeroBlock notes={zeroNotes} compact />
</div>
</Reveal>
)}
{/* КАТЕГОРИЙНЫЕ РЯДЫ */}
{CATEGORY_ORDER.map(cat => (
<Reveal key={cat}>