# Blog with Admin
## What this builds
A public blog with paginated listing and post detail pages, plus a JWT-protected admin panel for creating, editing, and deleting posts. Posts stored in Sekejap.
---
## Pipelines
1. `GET /blog` → list posts → render listing page
2. `GET /blog/:slug` → fetch post by slug → render detail page
3. `GET /admin/posts` → auth check → list all posts → render admin panel
4. `POST /api/posts` → auth check → upsert post → return JSON
5. `DELETE /api/posts/:slug` → auth check → delete post → return JSON
6. `POST /auth/login` → validate credentials → issue JWT → redirect
---
## DSL
### blog-list — public post listing
```
| trigger.webhook --path /blog --method GET
| sekejap.query --table posts --op scan
| script -- "return { posts: input.filter(p => p.published).sort((a,b)=>b.created_at-a.created_at).slice(0,20) }"
| web.response --template pages/blog-home.tsx --route /blog
```
### blog-detail — single post
```
| trigger.webhook --path /blog/:slug --method GET
| sekejap.query --table posts --op get --key "{{input.params.slug}}"