Your task is to serve as an AI code generator responsible for systematically implementing a web application, one step at a time, based on a provided technical specification and implementation plan.
You will:
- Identify which step in the plan is next.
- Write or modify the code files necessary for that specific step.
- Provide the complete contents of each file, following strict documentation and formatting rules.
- IMPLEMENTATION_PLAN
- A step-by-step plan (checklist) for building the application, indicating completed and remaining tasks.
- TECHNICAL_SPECIFICATION
- A detailed technical spec containing system architecture, features, and design guidelines.
- PROJECT_REQUEST
- A description of the project objectives or requirements.
- PROJECT_RULES
- Any constraints, conventions, or “rules” you must follow.
- EXISTING_CODE
- Any existing codebase or partial implementation.
When this prompt runs, you will:
- Review the provided inputs (Project Request, Rules, Spec, Plan, Code).
- Identify the next incomplete step in the IMPLEMENTATION_PLAN (marked
- [ ]
). - Generate all the code required to fulfill that step.
- Each modified or created file must be shown in full, wrapped in a code block.
- Precede each file with “Here’s what I did and why:” to explain your changes.
- Apply thorough documentation:
- File-level doc comments describing purpose and scope.
- Function-level doc comments detailing inputs, outputs, and logic flow.
- Inline comments explaining complex logic or edge cases.
- Type definitions and error handling as needed.
- End with:
- “STEP X COMPLETE. Here’s what I did and why:” summarizing changes globally.
- “USER INSTRUCTIONS:” specifying any manual tasks (e.g., installing libraries).
- If you update the plan, return the modified steps in a code block.
Throughout, maintain compliance with PROJECT_RULES and align with the TECHNICAL_SPECIFICATION.
- Read All Inputs
- Confirm you have the full
project_request
,project_rules
,technical_specification
,implementation_plan
, andexisting_code
.
- Confirm you have the full
- Find Next Step
- Look for the next bullet in the
implementation_plan
marked- [ ]
.
- Look for the next bullet in the
- Generate/Update Files
- For each file required, create or update it with comprehensive code and documentation.
- Limit yourself to changing no more than 20 files per step to keep changes manageable.
- Document Thoroughly
- Provide an explanation (“Here’s what I did and why”) before each file.
- Output complete file contents in a Markdown code block.
- Finalize
- End with “STEP X COMPLETE” summary.
- Provide any USER INSTRUCTIONS for manual tasks.
- If you adjust the plan, include the updated steps in a Markdown code block.
Below is an example of how your output should look once you implement the next step:
STEP X COMPLETE. Here's what I did and why:
- [Summarize the changes made across all files.]
- [Note any crucial details or known issues.]
USER INSTRUCTIONS: Please do the following:
1. [Manual task #1, e.g., install library or environment variable config]
2. [Manual task #2, e.g., run migration or set up .env file]
If you updated the implementation plan, record it here:
# Updated Implementation Plan
## [Section Name]
- [x] Step 1: [Completed or updated step with notes]
- [ ] Step 2: [Still pending]
The fundamental principle underlying these guidelines is context-driven design differentiation. Rather than applying a one-size-fits-all approach, the design strategy adapts to the specific purpose and constraints of each project type. This creates optimal user experiences by aligning visual choices with functional requirements and user expectations.
For complex applications like Three.js scenes, games, and simulations, performance isn't just a consideration—it's the foundation upon which all other decisions rest. This means:
- Target 60 fps:
requestAnimationFrame
, object pooling, LOD, and regular profiling. - Memory: dispose of unused assets, choose lean data structures, off-load heavy work to Web Workers.
- Rendering: batch draws, instanced geometry, frustum culling, lightweight shaders/textures.
Complex applications require cognitive load reduction through thoughtful interface design:
- Clear hierarchies, progressive disclosure, consistent spacing.
- Instant feedback, accessible controls, debounced rapid inputs.
- Error-proof defaults, undo/redo, descriptive messages.
The visual design should support rather than compete with functionality:
- Neutral palettes, legible type, supportive icons.
- Responsive, space-efficient layouts; collapsible panels; multi-monitor awareness.
For landing pages, marketing sites, and presentational content, the goal shifts to emotional engagement and memorability:
- 3-second hook: bold visuals, smooth entry motion.
- Story-driven flow with strategic “delight” moments.
- Hierarchies and CTAs tested for conversion.
Rather than following trends, aim to anticipate and set them:
- Study emerging design patterns from leading agencies and startups
- Experiment with new CSS features as they become available
- Incorporate elements from other design disciplines (architecture, fashion, industrial design)
- Balance innovation with usability principles
- Use advanced CSS features like custom properties, grid, and container queries
- Implement complex animations using CSS transforms and keyframes
- Create custom SVG illustrations that align with brand identity
- Develop unique color palettes that evoke specific emotions
Animations should serve functional and emotional purposes simultaneously:
- Motion clarifies loading, transitions, and hovers; micro-interactions add personality.
- Prefer transform-based animations, judicious
will-change
, and “reduce motion” support.
Every interactive element should provide clear feedback about its functionality:
- Subtle scale or color changes for clickable elements
- Revealing additional information on hover
- Smooth transitions that feel natural and responsive
- Consistent behavior patterns across similar elements
- Design for finger-friendly touch targets (minimum 44px)
- Implement appropriate touch gestures for different actions
- Consider haptic feedback where available
- Ensure hover effects translate meaningfully to touch interfaces
- CSS Grid for complex, two-dimensional layouts
- Flexbox for one-dimensional alignment and distribution
- Container queries for truly responsive component design
- CSS custom properties for dynamic theming and state management
- CSS filters and backdrop-filter for sophisticated visual effects
- Transform3d for hardware-accelerated animations
- CSS shapes for non-rectangular layouts
- Blend modes for creative color and texture combinations
- CSS scroll-snap for controlled scrolling experiences
- CSS logical properties for internationalization
- CSS aspect-ratio for consistent proportions
- CSS clamp() for fluid typography and spacing
- Implement gesture recognition for touch interfaces
- Use Intersection Observer for scroll-based animations
- Create custom event systems for component communication
- Implement keyboard navigation patterns for accessibility
- Design reactive systems that update UI based on data changes
- Implement efficient re-rendering strategies
- Use debouncing and throttling for performance optimization
- Create predictable state transitions for complex interactions
Accessibility shouldn't be an afterthought but integrated into the design process from the beginning:
WCAG-AA contrast, multi-cue interactivity, visible focus, keyboard paths, skip links, minimal cognitive load.
Semantic HTML headings, ARIA where needed, labeled forms. Base experience works without JS; enhancements layered and tested with assistive tech.
- Clean, documented code; descriptive commits; version control.
- Cross-browser/device testing and analytics-driven iteration.
- Modular architecture, design tokens, readiness for new standards with graceful degradation.
This comprehensive approach to design principles creates a framework for making informed decisions that serve both users and business objectives while pushing the boundaries of what's possible in web design and development.
<implementation_plan>
Package manager: npm (≥ v9) with native work-spaces.
All workspace-specific commands are executed with
npm run <script> --workspace <package>
.
-
Step 1.1 Init mono-repo
- Task:
git init
, rootpackage.json
with"workspaces"
. - Files
package.json
{ "private": true, "workspaces": ["frontend", "worker", "packages/*", "scripts"], "scripts": { "bootstrap": "npm install", "lint": "eslint . --ext .ts,.tsx", "test": "npm run test --workspaces" } }
- Dependencies: None
- User Instructions: Make sure Node ≥ 18 & npm ≥ 9 are installed, then run
npm run bootstrap
.
- Task:
-
Step 1.2 Configure TypeScript & linting
- Task: Shared
tsconfig.base.json
, ESLint + Prettier, Husky pre-commit hook. - Files:
tsconfig.base.json
.eslintrc.cjs
.prettierrc
.husky/*
(set up vianpx husky-init && npm install
)
- Dependencies: Step 1.1
- Task: Shared
-
Step 2.1 Wrangler config
- Task:
wrangler.toml
withdev
,staging
,production
envs; D1 & Images bindings. - Files:
wrangler.toml
- Dependencies: Step 1.2
- User Instructions: Fill real CF account IDs & tokens later.
- Task:
-
Step 2.2 Hello-World Worker
- Task: Create workspace
worker
:Addmkdir -p worker && cd worker && npm init -y
/worker/index.ts
responding{ ok: true }
; build script using esbuild. - Files:
worker/package.json
(scripts:dev
,build
)worker/index.ts
worker/bindings.d.ts
- Dependencies: Step 2.1
- User Instructions:
npm run dev --workspace worker
opens http://localhost:8787.
- Task: Create workspace
-
Step 3.1 Initial schema migration
- Task:
/worker/migrations/001_init.sql
definingposts
,tags
,post_tags
. - Files:
worker/migrations/001_init.sql
- Dependencies: Step 2.2
- User Instructions:
npx wrangler d1 migrations apply gm_dev
.
- Task:
-
Step 3.2 DB utility layer
- Task:
packages/db
workspace (npm init -y
) exporting typed queries via@cfql/client
. - Files:
packages/db/index.ts
packages/types/post.ts
- Dependencies: Step 3.1
- Task:
-
Step 4.1 Create Vite React app
- Task:
npm create vite@latest frontend -- --template react-ts
; install Mantine, Lexend font, set yellow theme. - Files: ≤15 under
/frontend
. - Dependencies: Step 1.2
- User Instructions:
npm run dev --workspace frontend
.
- Task:
-
Step 4.2 Routing & Layout
- Task: Add React Router,
MainLayout
, placeholder pages (Index
,Tag
,Post
,Admin
). - Files:
/frontend/src/pages/*
/frontend/src/App.tsx
- Dependencies: Step 4.1
- Task: Add React Router,
- Step 5.1 zustand stores & fetch client
- Task:
api/client.ts
(fetch wrapper),postsSlice
,tagsSlice
. - Files:
/frontend/src/store/index.ts
/frontend/src/api/client.ts
- Dependencies: Step 4.2
- Task:
-
Step 6.1 GET endpoints
- Task:
/worker/api/posts.ts
,/worker/api/tags.ts
with Hono, Zod, edge caching. - Files: 4 under
/worker/api
. - Dependencies: Step 3.2
- Task:
-
Step 6.2 Fetch hooks & PostCard
- Task:
usePosts
,PostCard
with<img srcSet>
. - Files:
/frontend/src/hooks/usePosts.ts
/frontend/src/components/PostCard.tsx
- Dependencies: Step 6.1
- Task:
-
Step 7.1 react-virtuoso index
- Task: Infinite list, “Back to top” FAB.
- Files:
/frontend/src/pages/Index.tsx
/frontend/src/components/BackToTop.tsx
- Dependencies: Step 6.2
-
Step 7.2 Tag page
- Task:
/frontend/src/pages/Tag.tsx
reuse hook; 404 fallback. - Files: 1–2 modified.
- Dependencies: Step 7.1
- Task:
-
Step 8.1 SSR HTML for single post
- Task: Worker template + OG meta.
- Files:
/worker/templates/post.html
/worker/api/renderPost.ts
- Dependencies: Step 6.1
-
Step 8.2 CSR hydration
- Task:
/frontend/src/pages/Post.tsx
centered layout. - Files: 1 modified
- Dependencies: Step 8.1
- Task:
- Step 9.1 Utility functions
- Task:
/packages/utils/cfImages.ts
withgetVariantUrl
, signed upload. - Files: 1 util
- Dependencies: Step 6.1
- Task:
-
Step 10.1 Access JWT middleware
- Task:
/worker/middleware/auth.ts
. - Files: 1
- Dependencies: Step 2.2
- Task:
-
Step 10.2 Route guard on front-end
- Task:
<AuthGate>
+ lazy-loaded admin bundle. - Files: 2–3
- Dependencies: Step 10.1
- Task:
-
Step 11.1 POST/PUT/DELETE endpoints
- Task: Extend
/worker/api/posts.ts
with mutations + tag upsert. - Files: ≤3
- Dependencies: Step 10.1
- Task: Extend
-
Step 11.2 Mantine DataTable
- Task:
AdminPostsTable
with pagination + filters. - Files: several under
/frontend/src/pages/admin
- Dependencies: Step 11.1
- Task:
-
Step 11.3 CRUD modals & Dropzone
- Task:
PostModal
(Formik + Zod) with signed upload. - Files: 2 components
- Dependencies: Step 9.1
- Task:
- Step 12.1 Multi-delete & tag ops
- Task: API + UI batch actions.
- Files: extend ≤4 files
- Dependencies: Step 11.2
- Step 13.1 scripts/import.ts
- Task: Stream JSON dump, upload images, insert rows.
- Files:
/scripts/import.ts
,scripts/package.json
- Dependencies: Steps 3.2, 9.1
- User Instructions:
npx ts-node scripts/import.ts --dump ./dump.json --images ./images
.
- Step 14.1 XML generators
- Task:
/worker/api/rss.ts
,/worker/api/sitemap.ts
. - Files: 2
- Dependencies: Step 6.1
- Task:
-
Step 15.1 Plausible script & hook
- Task: Add
<script>
infrontend/index.html
,useTrackEvent
. - Files: 2
- Dependencies: Step 4.1
- Task: Add
-
Step 15.2 Logpush + Sentry
- Task: README snippet,
@sentry/react
installation. - Files: README, 1 config
- Dependencies: Step 15.1
- Task: README snippet,
-
Step 16.1 Vitest setup
- Task:
vitest.config.ts
, sample db util test. - Files: 2
- Dependencies: Step 3.2
- Task:
-
Step 16.2 Playwright scenarios
- Task: E2E tests for public flow + admin CRUD.
- Files:
/tests/e2e/*.spec.ts
- Dependencies: Step 11.2
-
Step 16.3 Lighthouse-CI budget
- Task:
lighthouserc.js
, GH Action step. - Files: 2
- Dependencies: Step 14.1
- Task:
-
Step 17.1 GitHub Actions
- Task:
.github/workflows/ci.yml
(lint, test, build),.github/workflows/deploy.yml
(wrangler pages deploy). - Files: 2 workflows
- Dependencies: Steps 16.*
- Task:
-
Step 17.2 Secrets & Pages project
- Task: README guide +
scripts/set-secrets.sh
. - Files: README update,
scripts/set-secrets.sh
- Dependencies: Step 17.1
- User Instructions: Run script; configure CF Pages in dashboard.
- Task: README guide +
-
Step 18.1 Accessibility sweep
- Task: Run axe; fix color contrast or aria labels.
- Files: minor tweaks (<5)
- Dependencies: Steps 7–8
-
Step 18.2 Final docs & governance
- Task: Finish
README.md
, addCODEOWNERS
, LICENSE. - Files: 3
- Dependencies: All prior
- Task: Finish
- Workspaces declared in root
package.json
. - Commands use
npm run … --workspace <pkg>
andnpm install
for bootstrapping. - One-off scripts executed with
npx
, e.g.npx ts-node …
.
Follow steps sequentially; each touches ≤20 files and isolates concerns, enabling a code-generation AI (or human developers) to implement the micro-blog efficiently on the Cloudflare stack. </implementation_plan>
<technical_specification>
Item | Detail |
---|---|
Core Purpose | A personal micro-blog that reproduces the feel of Tumblr for a single author, optimized for thousands of image-heavy posts and smooth infinite scrolling. |
Primary Goals | • Zero-friction posting and management for the author • Fast, mobile-first consumption for visitors • Low-ops, CDN-backed delivery using Cloudflare edge platform |
Primary Use-Cases | 1. Author signs in via Google, creates or edits a post with an image and tags. 2. Visitor lands on the index, scrolls endlessly through GIFs without jank. 3. Visitor clicks a tag to view a filtered timeline. 4. RSS consumers poll /rss.xml for latest entries. |
High-Level Architecture | Client (React + Mantine) delivered from Cloudflare Pages → fetch() calls to Cloudflare Worker API. Worker connects to D1 (SQLite) and Cloudflare Images. Assets cached at Cloudflare edge. Plausible script loaded on every page. |
Client (Vite → Pages) ──▶ Worker API ──▶ D1
▲ │
│ └─▶ Cloudflare Images (variants)
└── Plausible (analytics endpoint)
Layer | Stack |
---|---|
Languages | TypeScript 5.x (strict), SQL (D1), Bash |
Frontend | React 18, Mantine 7, Vite 5, React Router v6, zustand (state) |
Backend | Cloudflare Workers (Service Workers API), Hono v4 (router), Zod (runtime validation) |
Database | Cloudflare D1 (SQLite) accessed via @cfql/client |
Media | Cloudflare Images (1x1xs , 1x1sm , 1x1md , 1x1lg , 1x1xl ) |
DevOps | GitHub + GitHub Actions, Wrangler v3, npm, Conventional Commits, Semantic-release |
CI/CD | PR lint + unit tests → preview deploy to Pages preview env; merge to main → staging; tag v* → prod |
Testing | Vitest (unit), Playwright (E2E), Lighthouse-CI (perf), tsc --noEmit |
Observability | Cloudflare Logpush (API requests), Sentry (client errors), Plausible (usage) |
/frontend
/src
/components
/pages
/hooks
/styles
vite.config.ts
/worker
/api
posts.ts
tags.ts
auth.ts
bindings.d.ts
wrangler.toml
/scripts
import.ts
/packages
/types # shared DTOs & Zod schemas
/utils
.eslintrc.cjs
.prettierrc
npm-workspace.yaml
- Naming · kebab-case filenames, Pascal components,
useX
hooks. - Path Aliasing ·
@/components
,@/types
viatsconfig.paths
.
Requirement | Implementation Detail | Edge Cases / Errors | UX |
---|---|---|---|
Infinite-Scroll Index | react-virtuoso list; fetch /api/posts?cursor=<id> (50 posts) |
Network fail → toast “Offline – retrying” | “Back to top” FAB appears after 3× viewport |
Tag Page | Same component with /api/posts?tag=<slug>&cursor=… |
Tag not found → 404 page | Title bar shows #<tag> |
Permalink | SSR: Worker renders HTML w/ OG meta; CSR hydration | Post ID missing → 404 | Centered 640 px column |
RSS & Sitemap | Worker routes /rss.xml , /sitemap.xml (edge-cached) |
n/a | n/a |
OG/Twitter Meta | <meta property="og:image" content="https://imagedelivery.net/<hash>/cf_image_id/1x1lg"> |
Animated GIFs auto-play preview disabled by specifying content-type gif |
n/a |
Requirement | Details | Edge Cases |
---|---|---|
Auth | Cloudflare Access (Google) → CF_Authorization header forwarded to Worker; Worker verifies JWT via Access public keys |
Token expired → redirect to Access login |
Post Table | Mantine DataTable w/ server-side pagination (page , size ) |
Empty list shows “No posts yet” |
CRUD Modal | Formik + Zod schema: description (markdown textarea), image (Dropzone), tags (multi-select) |
Missing image → validation error |
Bulk Ops | Checkbox column; actions “Delete”, “Add Tag”, “Remove Tag” | Confirm modal; cascade delete ensures post_tags rows removed |
- Usage:
npm ts-node scripts/import.ts --dump ./dump.json --images ./images
- Steps:
- Read JSON, iterate posts.
- Upload each local image ⇒ Cloudflare Images; record returned
id
+ variants URL list. - Insert into D1 with
title = NULL
. - Upsert tags, populate
post_tags
.
- Performance: Stream-based reading; concurrent uploads limited to 10.
-- posts
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT, -- nullable; shown as "(untitled)" if NULL
description TEXT NOT NULL,
cf_image_id TEXT NOT NULL UNIQUE,
cf_variants TEXT NOT NULL, -- JSON string mapping size→URL
tumblr_url TEXT,
tags_count INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_posts_created ON posts(created_at DESC);
-- tags
CREATE TABLE tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE
);
-- post_tags (M2M)
CREATE TABLE post_tags (
post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (post_id, tag_id)
);
CREATE INDEX idx_post_tags_tag ON post_tags(tag_id);
Migrations managed via wrangler d1 migrations apply
.
Method | Path | Auth | Description |
---|---|---|---|
GET | /api/posts |
Public | Params: cursor , size=50 , tag? |
GET | /api/posts/:id |
Public | Single post |
GET | /api/tags |
Public | List all tags + counts |
POST | /api/post |
Admin | Body: description, imageId, tags[] |
PUT | /api/post/:id |
Admin | Update |
DELETE | /api/post/:id |
Admin | Remove |
- Caching: Public GETs wrapped with
caches.default.match/put
(5 min, SWR 10 min). - Validation: Zod schema per route; errors →
400 JSON {error}
.
- Image Upload Proxy: Signed URL from Worker → client uploads direct to Cloudflare Images.
- Edge Redirect (optional): If request path matches scraped Tumblr slug, return 301 to
/post/:id
(feature-flag). - Scheduled Cleanup: Cron triggers weekly to purge orphaned images (not referenced in
posts
).
Token | Value |
---|---|
Primary BG | #FFE627 |
Primary Text | #1A1A1A |
Font Family | "Lexend", sans-serif |
Radius | 8 px |
Spacing Scale | 4 px · 8 px · 16 px · 32 px |
Component | States |
---|---|
Button | default, hover, focus, disabled |
Card (Post) | idle, hover (lift), focus-within |
Tag Chip | default, selected |
Dialog | open/close, error shake |
All components built on Mantine primitives; custom styles via Mantine createStyles
.
┌──────────────────────────┐
│ Hono Router (Worker) │
├──────────────┬───────────┤
│ Controllers │ /api/... │
│ Services │ DB logic │
│ Lib │ cf-images │
└──────────────┴───────────┘
- State Layer: zustand store
postsSlice
,tagsSlice
,uiSlice
. - Routes:
/
(index),/tag/:slug
,/post/:id
,/admin/*
(lazy). - Code-Splitting:
React.lazy
for Admin bundle. - Types: Shared DTOs in
@gm/types
.
-
Flow:
/admin
→ Cloudflare Access Google OAuth.- On success, browser receives
CF_Authorization
cookie. - Worker validates JWT on each admin request using Access JWKS.
-
Roles:
admin
(single email allow-list). All other traffic is anonymous. -
Session Length: 24 h; forced re-auth thereafter.
- Index Load → Client SSR fallback HTML from Worker (empty list).
- Hydration → React fetches first batch
/api/posts
. - Scroll event threshold triggers next fetch with
cursor
(last id). - Images load via
srcset
(browser picks variant). - Plausible event
post_view
fires via IntersectionObserver when post 50 % visible.
Not applicable.
-
Tool: Plausible self-hosted.
-
Events:
post_view
{ id }
tag_view
{ tag }
-
Implementation: Use
plausible()
global inuseEffect
. -
Dashboard Access: Author only (basic auth).
Threat | Mitigation |
---|---|
XSS | DOMPurify on description render; Markdown limited to inline tags |
CSRF | API only via fetch with same-origin; admin endpoints require Access JWT |
Rate Limit | Cloudflare WAF rule: 1 000 requests / 10 min per IP |
GDPR | No PII stored; Plausible is cookieless |
Secrets stored in Cloudflare environment variables (IMAGES_TOKEN
, PLAUSIBLE_DOMAIN
).
Stage | Domain | Images Namespace | D1 DB |
---|---|---|---|
Local | localhost:5173 |
dev | dev |
Staging | staging.example.com |
staging | staging |
Production | example.com |
prod | prod |
wrangler.toml
defines three environments.- GitHub Actions matrix deploys on push → branch
staging
,main
. - Logpush to R2 bucket; alerts via Slack webhook.
Layer | Tool | Coverage Target |
---|---|---|
Unit | Vitest + jsdom | ≥ 90 % lines |
API Integration | Vitest (Miniflare) | CRUD happy-path + auth failures |
E2E | Playwright (Chromium, WebKit) | Index scroll, tag filter, admin CRUD |
Performance | Lighthouse-CI budget: < 1 s TTFB, < 2.5 s LCP | |
Accessibility | @axe-core/playwright on index & post pages |
|
Visual Regression | Playwright screenshots (admin index) |
</technical_specification>
<project_request> Draft Spec v1.0 (final).
# Single-User Micro-Blog
A lightweight, Tumblr-style site for one author, serving ~2 000 image-centric posts with fast infinite scrolling.
**Stack**: React + TypeScript + Mantine · Vite · Cloudflare Pages + Workers · D1 · Cloudflare Images · Plausible Analytics
---
## Target Audience
| Role | Needs |
|------|-------|
| **Owner/Admin** | Quick CRUD, one-time import, Google login |
| **Visitors** | Smooth endless feed, tag browsing, fast images |
---
## Desired Features
### 1 · Public Frontend
- **Infinite-Scroll Index**
Virtualized; “Back to top” button after 3× viewport.
- **Tag Pages** — `/tag/:slug` (same endless UX).
- **Permalink** — `/post/:id` (numeric).
Meta tags use original image as OG/Twitter card.
- **RSS & Sitemap**
`/rss.xml` (20 latest), `/sitemap.xml`.
- **Plausible Analytics**
Script + events `post_view`, `tag_view`.
- **Performance**
`<img srcset>` referencing Cloudflare Images variants (`1x1xs … 1x1xl`); lazy-load except first screen.
### 2 · Admin UI `/admin`
| Feature | Details |
|---------|---------|
| **Auth** | Cloudflare Access (Google OIDC) — prod & staging |
| **Post Table** | Paginated, sortable, filter by tag |
| **CRUD** | Mantine modal forms, Zod validation |
| **Uploads** | Drag-drop ➜ Cloudflare Images · returns image ID |
| **Bulk Ops** | Multi-delete, tag add/remove (nice-to-have) |
### 3 · Data Layer
| Item | Tech / Fields |
|------|---------------|
| **DB** | Cloudflare D1 |
| **Tables** | `posts(id, title?, description, cf_image_id, cf_variants JSON, tumblr_url, tags_count, created_at, updated_at)`<br>`tags(id, name)`<br>`post_tags(post_id, tag_id)` |
| **Images** | Cloudflare Images originals + pre-defined variants `1x1xs / sm / md / lg / xl` |
| **API** | Worker routes: public `GET /api/posts`, `GET /api/tags`; auth-gated `POST /api/post` etc. |
| **Caching** | `Cache-Control: s-maxage=300, stale-while-revalidate=600` on public GETs |
### 4 · Import Script
node import.js --dump ./dump.json --images ./images
- Reads Tumblr JSON + local image folder.
- Uploads each image to Cloudflare Images, records variant IDs.
- Inserts rows; sets `title` = null (display as “(untitled)”) and stores original `tumblr_url`.
---
## Design Requests
| Element | Spec |
|---------|------|
| **Palette** | Full-bleed yellow `#FFE627`; deep gray/black text for AA contrast |
| **Logo** | Supplied sun SVG/PNG in sticky top-header |
| **Typography** | Google Font **Lexend** — 1.4 rem base, 700 for titles |
| **Layout** | 640 px max-width column, centered; mobile-first |
| **Mode** | Light-only |
| **Accessibility** | Alt text required; focus states via Mantine defaults |
---
## Dev-Ops & Repo
| Item | Detail |
|------|--------|
| **Mono-repo (GitHub)** | `/frontend` (Vite React) ➜ Cloudflare Pages<br>`/worker` (API + SSR) ➜ Wrangler deploy |
| **Shared Code** | `/packages/types` for DTOs & Zod schemas |
| **CI** | GitHub Actions → lint, test, build, deploy-to-staging, promote on `main` |
| **Secrets** | D1 binding, Images token, Plausible domain |
---
## Notes & Final Checks
- No titles in legacy data: UI shows “(untitled)” or first 50 chars of description; titles required on new posts.
- Permalinks are new (`/post/:id`); original Tumblr URLs stored for potential 301 Worker if ever needed.
- OG/Twitter meta simply references original image URL (often animated GIF). No dynamic image generation for now.
**All outstanding questions resolved. Spec is ready for implementation.** 🚀
</project_request>
---
🤯