Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ You are working in Newsletter Maker, a Django + DRF + Celery + Qdrant backend wi
- The frontend uses Next.js App Router.
- Shared backend-facing types belong in `frontend/src/lib/types.ts`.
- Shared backend-facing data access belongs in `frontend/src/lib/api.ts` unless there is a clear reason to add a route handler under `frontend/src/app/api/`.
- Keep reusable UI in `frontend/src/components/` and page assembly in `frontend/src/app/`.
- Keep reusable components in `frontend/src/components/`, provider-style wrappers in `frontend/src/providers/`, and page assembly in `frontend/src/app/`.
- Use `frontend/src/components/elements/` for app-owned components that combine shadcn primitives with project-specific functionality.
- Use `frontend/src/components/layout/` for shared navigation, page chrome, and structural layout components.
- Use `frontend/src/components/ui/` only for shadcn components installed by `npx shadcn@latest add <component>`; do not move custom app components into that folder.
- Use `frontend/src/providers/` for provider-style wrappers and context composition such as theme or query providers.
- For component folders under `frontend/src/components/elements/`, `frontend/src/components/layout/`, `frontend/src/providers/`, or `frontend/src/app/**/_components/`, let the folder carry the component name and use `index.tsx`, `index.test.tsx`, and `index.stories.tsx` inside that folder instead of repeating the component name in each file.
- Do not add barrel `index.ts` files inside those component or provider folders unless the task explicitly requires one.
- Frontend tests should live beside the files they cover in `frontend/src/app/` and `frontend/src/components/` rather than in separate `__tests__/` folders.
- When adding or changing a frontend route, page, or component, add or update direct colocated Vitest coverage in the same change. If a file is a pure framework re-export or adapter and a dedicated test is intentionally skipped, call that out explicitly.
- Preserve existing backend payload shapes in TypeScript types and UI code unless the backend contract is intentionally changing.

## Documentation Standards
Expand All @@ -45,6 +53,7 @@ You are working in Newsletter Maker, a Django + DRF + Celery + Qdrant backend wi
- Add or improve module docstrings plus public classes, public functions, and non-obvious helpers.
- Do not add noisy boilerplate to trivial `__str__` methods, simple properties, or obvious one-line helpers unless the surrounding file genuinely benefits.
- TypeScript and React code should use JSDoc for exported utilities, hooks, route handlers, and non-trivial components when behavior is not obvious from the type signature alone.
- For React components, providers, and App Router pages, keep the component JSDoc to a short summary paragraph and document prop fields on the props type or interface. Avoid `@param` and `@returns` tags on React components because Storybook Autodocs flattens them poorly.
- If architecture or workflow behavior changes, update the most relevant docs in `docs/`, especially `docs/DEVELOPER_GUIDE.md`, `docs/IMPLEMENTATION_OVERVIEW.md`, `docs/MODELS.md`, `docs/RELEVANCE_SCORING.md`, or `docs/LOGGING.md`.

## Prompt Skill Conventions
Expand Down
6 changes: 5 additions & 1 deletion .github/instructions/frontend-app.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ applyTo:
- This frontend uses Next.js App Router, not the Pages Router.
- Keep backend-facing types in `frontend/src/lib/types.ts` and shared server-side API access in `frontend/src/lib/api.ts` unless a route handler in `frontend/src/app/api/` is the correct boundary.
- Reuse the existing backend contract. This repo currently consumes `snake_case` fields from Django; do not silently rename payload keys in the frontend.
- Keep reusable UI in `frontend/src/components/` and page composition in `frontend/src/app/`.
- Keep reusable components in `frontend/src/components/`, provider-style wrappers in `frontend/src/providers/`, and page composition in `frontend/src/app/`.
- Keep Vitest files beside the route page, route-local component, or shared component they exercise instead of creating separate `__tests__/` folders.
- Add or update a colocated `*.test.ts` or `*.test.tsx` file in the same change when introducing or modifying a route handler, page, or component. If the file is only a framework passthrough, document why dedicated coverage is omitted.
- Prefer strong explicit types over loose `Record<string, unknown>` shapes when the contract is known.
- Add JSDoc for exported utilities, route handlers, hooks, and non-trivial components when behavior is not obvious from the signature.
- For React components, providers, and App Router pages, keep the component JSDoc to a short summary paragraph and put prop descriptions on the props type or interface fields. Avoid `@param` and `@returns` tags on React components because Storybook Autodocs flattens them into a single block.
- When a change depends on new backend fields or endpoints, update the corresponding types and API helpers in the same change.

## Validation
Expand All @@ -29,3 +32,4 @@ applyTo:
- `frontend/src/lib/api.ts`
- `frontend/src/app/`
- `frontend/src/components/`
- `frontend/src/providers/`
81 changes: 81 additions & 0 deletions .github/instructions/frontend-component-structure.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
name: "Frontend Component Structure Guidelines"
description: "Use when creating, moving, or refactoring React components, Storybook stories, or frontend tests in frontend/src/. Covers the preferred elements/layout/ui/providers/app _components directory structure and colocated naming conventions."
applyTo:
- "frontend/src/**/*.ts"
- "frontend/src/**/*.tsx"
---

# Frontend Component Structure Guidelines

- Avoid growing a flat `frontend/src/components/` directory.
- Put app-owned presentational or interactive components that combine shadcn primitives with project-specific functionality in `frontend/src/components/elements/`.
- Put shared structural components in `frontend/src/components/layout/`.
- Keep `frontend/src/components/ui/` for shadcn components installed directly by `npx shadcn@latest add <component>`.
- Put provider-style wrappers and context composition in `frontend/src/providers/`.
- Put route-local components in `frontend/src/app/**/_components/` when they are only used by a single route.
- Put route page tests beside the page or route-local component they cover within the same `frontend/src/app/**` directory.
- For app-owned folders under `frontend/src/components/elements/`, `frontend/src/components/layout/`, `frontend/src/providers/`, and `frontend/src/app/**/_components/`, let the folder name carry the component or provider name and use `index.tsx`, `index.test.tsx`, and `index.stories.tsx` for colocated files.
- Do not add barrel `index.ts` files inside those component or provider folders unless a task explicitly needs a separate module boundary.
- Preserve shadcn's generated file naming and structure inside `frontend/src/components/ui/`; do not wrap those generated components in extra folders just to match the app-owned component pattern.
- For new Storybook stories that use `tags: ["autodocs"]`, set `parameters.docs` to the shared compact docs helper in `frontend/src/lib/storybook-docs.tsx` so the Docs tab omits the default `Stories` block and uses the reduced primary canvas height.

## Preferred Shapes

Shared reusable component:

```text
frontend/src/components/elements/StatusBadge/
index.tsx
index.stories.tsx
index.test.tsx
```

Shadcn-installed primitive:

```text
frontend/src/components/ui/button.tsx
```

Shared provider:

```text
frontend/src/providers/ThemeProvider/
index.tsx
index.test.tsx
```

Route-local component:

```text
frontend/src/app/projects/[id]/_components/MemberInviteCard/
index.tsx
index.stories.tsx
index.test.tsx
```

Route page with colocated test:

```text
frontend/src/app/admin/sources/
page.tsx
page.test.tsx
```

## Placement Heuristics

- If the component is a shadcn primitive created by the CLI, keep it under `components/ui/` with the generated naming.
- If the component is app-owned and composes shadcn primitives with project-specific behavior or presentation, place it under `components/elements/`.
- If the component primarily arranges shared navigation or page chrome, place it under `components/layout/`.
- If the module primarily provides context or wraps app trees with provider logic, place it under `providers/`.
- If the component is only consumed by one route segment, keep it under that route's `_components/` folder instead of promoting it to `components/`.
- Prefer folder-level naming over duplicate file naming. For example, prefer `OriginalContentIdeaCard/index.tsx` over `OriginalContentIdeaCard/OriginalContentIdeaCard.tsx`.
- When extracting from a large page, prefer moving the smallest reusable visual leaves first, then larger feature sections, while keeping the page as the orchestration layer.
- Prefer `*.test.tsx` files beside the owning page or component over `__tests__/` directories for new frontend tests.

## Notes

- Preserve the existing backend contract and keep frontend payloads in `snake_case`.
- Follow the repo's colocated story convention for Storybook.
- Reuse `frontend/src/lib/storybook-docs.tsx` for compact Docs tabs in new stories instead of re-declaring the same docs page JSX in each file.
- Do not move files only to satisfy the structure guideline unless the current task already touches that area.
4 changes: 2 additions & 2 deletions .github/skills/coverage-auditor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Use this skill to add the smallest effective tests around the changed behavior.
## Rules

- **Backend:** Use `pytest` with the existing patterns in `core/tests/` and `tests/`.
- **Frontend:** Use `vitest` and the existing co-located `__tests__` structure under `frontend/src/`.
- **Frontend:** Use `vitest` with colocated `*.test.ts` and `*.test.tsx` files beside the route, page, or component under `frontend/src/`.
- Mock external integrations such as feed parsing, Reddit, email providers, Qdrant, or LLM calls instead of relying on live services.
- Prefer focused behavior tests over broad snapshot-style tests.
- For defensive branches that are intentionally unreachable, document exclusions explicitly with `# pragma: no cover` or `/* v8 ignore next */` only when justified.
Expand All @@ -24,7 +24,7 @@ Use this skill to add the smallest effective tests around the changed behavior.
- `core/tests/test_tasks.py`
- `core/tests/test_newsletters.py`
- `core/tests/test_pipeline.py`
- For frontend work, extend the nearest existing `__tests__` file under `frontend/src/components/` or `frontend/src/lib/`.
- For frontend work, add or extend the nearest colocated `*.test.ts` or `*.test.tsx` file beside the owning route, page, or component.
- When adding new frontend tests, keep imports sorted to satisfy the repo's ESLint import-order rules. If you hit `Run autofix to sort these imports!`, fix the import block or run file-scoped ESLint before moving on.
- After changing tests, run the narrowest relevant validation command first.
- For Provider/Wrapper components, do not test state or initialization. Instead, render a consumer child component and assert that the context values or library configurations (like QueryClient options) match the expected project defaults.
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ frontend/coverage/
frontend/node_modules/

docs/

*storybook.log
storybook-static
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"nodeenv",
"noinput",
"nomic",
"oklch",
"OLLAMA",
"ormsgpack",
"PRAW",
Expand Down
72 changes: 0 additions & 72 deletions SESSION.md
Original file line number Diff line number Diff line change
@@ -1,73 +1 @@
# Session Restore Point

## Current focus

Phase 3 WP5: original content idea generation in `trends/`.

## What landed today

- Added `OriginalContentIdeaStatus` and `OriginalContentIdea` to `trends/models.py`.
- Added migration `trends/migrations/0005_original_content_idea.py`.
- Added new prompt skill folder `skills/original_content_ideation/` with:
- `SKILL.md`
- `resources/gap_detect.md`
- `resources/generate.md`
- `resources/critique.md`
- Added partial WP5 task implementation in `trends/tasks.py`:
- `run_all_original_content_idea_generations`
- `generate_original_content_ideas`
- workflow helpers for accept / dismiss / mark written
- heuristic gap detection + fallback generation + heuristic critique
- optional OpenRouter-backed prompt-resource calls for gap detect / generate / critique
- Added partial task coverage in `trends/tests/test_tasks.py` for:
- pending-idea creation
- weekly cap
- mark-written workflow

## What was validated

- `python manage.py check`
- `python manage.py makemigrations --check --dry-run trends`

Both passed after naming the new model index `core_idea_project_7f21_idx`.

## Known incomplete state

- WP5 is not finished.
- No serializer/API route/test work has been added yet for `OriginalContentIdea`.
- `docs/IMPLEMENTATION_PHASE_3.md` still needs a current implementation note for WP5 once the backend slice is complete.
- The focused task validation was interrupted:
- first `pytest trends/tests/test_tasks.py -q` failed on a duplicate `_build_theme_cluster_context` definition introduced during editing
- that duplicate definition was removed
- the rerun was cancelled because we paused for shutdown
- After that, additional external edits were reported in:
- `docs/IMPLEMENTATION_PHASE_3.md`
- `trends/tasks.py`
- `trends/tests/test_tasks.py`
Re-read those files before making new edits tomorrow.

## First steps tomorrow

1. Confirm the active branch. The repo attachment reported `maintenance/finish-core-refactor`, but an earlier terminal action created `feature/original-content-idea-generation`, so verify before continuing.
2. Re-read:
- `trends/tasks.py`
- `trends/tests/test_tasks.py`
- `docs/IMPLEMENTATION_PHASE_3.md`
3. Run the focused validation that was interrupted:
- `pytest trends/tests/test_tasks.py -q`
4. If task tests pass, finish the remaining WP5 slice:
- `trends/serializers.py`
- `trends/api.py`
- `trends/api_urls.py`
- `trends/tests/test_api.py`
- optional admin only if needed
- add WP5 implementation note to `docs/IMPLEMENTATION_PHASE_3.md`
5. After API work, run focused validation again:
- `pytest trends/tests/test_tasks.py trends/tests/test_api.py -q`
- `python3 -m mypy trends/tasks.py`

## Likely follow-up checks

- Watch for unused imports in `trends/tasks.py` (`build_skill_user_prompt` / `get_skill_definition` may no longer be needed for WP5 helpers).
- Confirm the new heuristic tests still pass after any formatter changes.
- Keep WP5 scoped to backend + docs for now; frontend `/ideas` work belongs to WP6.
19 changes: 19 additions & 0 deletions frontend/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { StorybookConfig } from "@storybook/nextjs-vite"

const config: StorybookConfig = {
stories: ["../src/**/*.stories.@(ts|tsx|js|jsx|mjs)"],
addons: [
"@storybook/addon-themes",
"@storybook/addon-a11y",
"@storybook/addon-vitest",
"@chromatic-com/storybook",
"@storybook/addon-docs",
],
framework: {
name: "@storybook/nextjs-vite",
options: {},
},
staticDirs: ["../public"],
}

export default config
40 changes: 40 additions & 0 deletions frontend/.storybook/manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { addons } from "storybook/manager-api"
import { create } from "storybook/theming"

const shadcnTheme = create({
base: "light",

fontBase: '"Geist Sans", sans-serif',
fontCode: '"Geist Mono", monospace',

brandTitle: "My Component Library",
brandUrl: "/",
brandTarget: "_self",

// Storybook manager theme colors must stay in formats polished can parse.
colorPrimary: "#06b6d4",
colorSecondary: "#06b6d4",

appBg: "#f5f5f5",
appContentBg: "#fafafa",
appPreviewBg: "#fafafa",
appBorderColor: "#e4e4e7",
appBorderRadius: 10,

textColor: "#18181b",
textInverseColor: "#fafafa",

barTextColor: "#71717a",
barSelectedColor: "#06b6d4",
barHoverColor: "#06b6d4",
barBg: "#fafafa",

inputBg: "#fafafa",
inputBorder: "#e4e4e7",
inputTextColor: "#18181b",
inputBorderRadius: 8,
})

addons.setConfig({
theme: shadcnTheme,
})
64 changes: 64 additions & 0 deletions frontend/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import "../src/app/globals.css"

import { withThemeByClassName } from "@storybook/addon-themes"
import type { Preview } from "@storybook/nextjs-vite"
import type { ReactNode } from "react"

import { QueryProvider } from "../src/providers/QueryProvider"

export const decorators = [
withThemeByClassName({
themes: {
light: "",
dark: "dark",
},
defaultTheme: "light",
}),
]

function StorybookProviders({ children }: { children: ReactNode }) {
return (
<QueryProvider>
<div className="min-h-screen bg-background p-6 text-foreground">{children}</div>
</QueryProvider>
)
}

const preview: Preview = {
tags: ["autodocs"],
parameters: {
options: {
storySort: {
order: [
"Pages",
["*", ["Components", "Views", "*"]],
"Layout",
"Features",
["*", ["Components", "*"]],
"UI",
["*"],
"*",
],
},
},
layout: "padded",
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
nextjs: {
appDirectory: true,
},
},
decorators: [
(Story) => (
<StorybookProviders>
<Story />
</StorybookProviders>
),
],
}

export default preview
1 change: 1 addition & 0 deletions frontend/.storybook/shims.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "*.css"
9 changes: 9 additions & 0 deletions frontend/.storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"include": [
"./*.d.ts",
"./*.ts",
"./*.tsx",
"../storybook.shims.d.ts"
]
}
25 changes: 25 additions & 0 deletions frontend/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
Loading
Loading