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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ COPY alembic.ini ./
COPY migrations ./migrations
RUN mkdir -p /app/assets/generated

EXPOSE 8000 8501
EXPOSE 8000

CMD ["uvicorn", "ecommerce_agent.api.main:app", "--host", "0.0.0.0", "--port", "8000"]
9 changes: 3 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ TEST_DATABASE_URL ?= postgresql+asyncpg://ecommerce:ecommerce@postgres:5432/$(TE

.DEFAULT_GOAL := help

.PHONY: help env install install-hooks lock up down restart build ps logs logs-api logs-dashboard \
.PHONY: help env install install-hooks lock up down restart build ps logs logs-api \
migrate lint typecheck format format-check test test-unit \
test-smoke test-integration test-all shell-api db-shell health openapi \
reset-local-data
Expand Down Expand Up @@ -59,9 +59,6 @@ logs: ## Follow logs for all services.
logs-api: ## Follow FastAPI logs.
$(COMPOSE) logs -f --tail=200 api

logs-dashboard: ## Follow Streamlit logs.
$(COMPOSE) logs -f --tail=200 dashboard

migrate: env ## Apply application database migrations.
$(COMPOSE) run --rm migrate alembic upgrade head

Expand Down Expand Up @@ -115,10 +112,10 @@ shell-api: ## Open a shell in a one-off API container.
db-shell: ## Open psql in the local application database.
$(COMPOSE) exec postgres psql -U ecommerce -d ecommerce

health: ## Check local API and dashboard HTTP endpoints.
health: ## Check the local API and web UI HTTP endpoints.
curl -fsS http://127.0.0.1:8000/api/health
@printf "\n"
curl -fsSI http://127.0.0.1:8501 | head -n 1
curl -fsSI http://127.0.0.1:8000/trend-inbox | head -n 1

openapi: ## Write the current OpenAPI schema to /tmp/ecommerce-agent-openapi.json.
@test -x "$(PYTHON)" || { echo "Run 'make install' first."; exit 1; }
Expand Down
38 changes: 38 additions & 0 deletions assets/design_handoff_b1_workshop/B1 Workshop.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Workshop — B1 (Concrete · Amber Dark) · Handoff</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
html, body { margin: 0; padding: 0; background: #1c1108; }
#root { min-height: 100%; }
</style>
</head>
<body>
<div id="root"></div>

<template id="__bundler_thumbnail">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect width="100" height="100" fill="#1c1108" />
<rect x="30" y="30" width="40" height="40" fill="none" stroke="#fb5a28" stroke-width="5" />
<text x="50" y="58" font-family="monospace" font-size="20" font-weight="700" fill="#f4ece1" text-anchor="middle">B1</text>
</svg>
</template>

<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>

<script type="text/babel" src="theme.b1.jsx"></script>
<script type="text/babel" src="studio.jsx"></script>
<script type="text/babel" src="wschrome.jsx"></script>
<script type="text/babel" src="screen-inbox.jsx"></script>
<script type="text/babel" src="screen-reports.jsx"></script>
<script type="text/babel" src="screen-etsy.jsx"></script>
<script type="text/babel" src="b1-mount.jsx"></script>
</body>
</html>
105 changes: 105 additions & 0 deletions assets/design_handoff_b1_workshop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Workshop — B1 (Concrete · Amber Dark) · Claude Code Handoff

This folder is a **complete handoff package** for implementing the Workshop B1 design in a
real codebase. It is written so a developer (or Claude Code) who was **not** part of the
original design conversation can build the product from these documents alone.

---

## What Workshop is
An internal, single-operator tool for an AI-assisted print-on-demand business. It runs a
human-in-the-loop pipeline: surface market **trends** → generate **research reports** →
**design** print artwork → push **products** to Etsy/Printful. Tagline: *Human-driven commerce.*

## What "B1" is
B1 (code-named **Concrete · Amber Dark**) is the chosen visual direction: a **brutalist**,
monospace-accented UI — hard 0-radius corners, 1.5px structural borders, solid offset
"hard shadows," a single **vermilion** signal color (`#fb5a28`) over **warm amber-orange
near-blacks**. It ships **dark by default** but is fully **light/dark compatible** (a toggle
lives in every topbar). The other directions explored earlier have been intentionally
stripped from this package.

---

## How to use this package

1. Open **`B1 Workshop.html`** in a browser to see all four screens live (stacked, dark mode;
use the LIGHT/DARK toggle in any topbar to flip the whole study). This is your visual
source of truth.
2. Read the docs below **in order**. They are the build spec.
3. The `.jsx`/`.html` files are **design references**, not production code — see *Fidelity* below.

### Documents
| Doc | Contents |
|---|---|
| [`docs/01-design-tokens.md`](docs/01-design-tokens.md) | Both color palettes (dark + light), type scale, geometry, spacing, shadows, image placeholders. Start here. |
| [`docs/02-components.md`](docs/02-components.md) | The app shell (sidebar, topbar), every shared primitive, and reusable patterns with exact specs. |
| [`docs/03-screens.md`](docs/03-screens.md) | Per-screen layout breakdowns: Design Studio, Trend Inbox, Research Reports, Etsy Posting. |
| [`docs/04-interactions-and-state.md`](docs/04-interactions-and-state.md) | Hover/active/selection behavior, transitions, theming mechanism, and per-screen state. |
| [`docs/05-data-model.md`](docs/05-data-model.md) | The shape of all mock content (`WS_DATA`) — your provisional data contract. |
| [`docs/06-implementation-guide.md`](docs/06-implementation-guide.md) | Recommended build approach, component tree, theming strategy, what's mocked, acceptance checklist. |

### Reference screenshots
`screenshots/` contains each screen rendered in **both** dark and light mode — use them to
sanity-check your implementation:
- `design-studio-{dark,light}.png`
- `trend-inbox-{dark,light}.png`
- `research-reports-{dark,light}.png`
- `etsy-posting-{dark,light}.png`

(These are captured at the design width; the topbar's right edge may be cropped — see the live
`B1 Workshop.html` for the full topbar cluster.)

---

## About the design files (read this)
The `.jsx` and `.html` files are **design references created in HTML/React** — prototypes that
faithfully show the intended look and behavior. They are **not production code to copy
directly.** Your task is to **recreate these designs in your target codebase** using its
existing framework, component library, state management, and conventions (React, Vue,
SwiftUI, native, etc.). If no environment exists yet, choose the most appropriate framework
and implement them there.

The prototype takes shortcuts a real app must not: all content is hard-coded mock data, there
is no routing, and detail panes sometimes show shared sample content regardless of the list
selection. Treat the **tokens, layouts, components, and interactions** as the spec; treat the
running HTML as the pixel reference.

## Fidelity
**High-fidelity.** Colors, typography, spacing, borders, and interactions are final. Recreate
the UI pixel-accurately using your codebase's libraries and patterns. Exact values are in
`docs/01-design-tokens.md`.

---

## File map
```
design_handoff_b1_workshop/
├── README.md ← you are here (index + overview)
├── docs/
│ ├── 01-design-tokens.md
│ ├── 02-components.md
│ ├── 03-screens.md
│ ├── 04-interactions-and-state.md
│ ├── 05-data-model.md
│ └── 06-implementation-guide.md
├── screenshots/ ← reference renders (dark + light)
│
├── B1 Workshop.html ← entry point; mounts all four screens
├── b1-mount.jsx ← handoff mount: stacks the screens, owns the theme toggle
├── theme.b1.jsx ← WS_B1 theme object + all mock content (WS_DATA)
├── wschrome.jsx ← shared app shell (WSChrome) + shared primitives + icons
├── studio.jsx ← Design Studio screen + the one-time interaction CSS
├── screen-inbox.jsx ← Trend Inbox screen
├── screen-reports.jsx ← Research Reports screen
└── screen-etsy.jsx ← Etsy Posting Workflow screen
```

## Screens at a glance
1. **Design Studio** — compose & version print artwork (composer + library + focus detail).
2. **Trend Inbox** — triage agent-surfaced market signals (master/detail).
3. **Research Reports** — read agent-written market reports (list + reading pane + TOC).
4. **Etsy Posting Workflow** — pipeline kanban + listing editor.

> All screens are **desktop layouts** sized as **1440 × 1180** artboards. No responsive
> breakpoints were designed — define those in implementation if the product needs them.
49 changes: 49 additions & 0 deletions assets/design_handoff_b1_workshop/b1-mount.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// b1-mount.jsx — handoff entry. Renders the four B1 (CONCRETE · AMBER DARK)
// screens stacked, fixed dark mode. No design canvas, no tweaks, no other
// directions — just the B1 designs a developer needs to recreate.

const B1_SCREENS = [
{ id: 'studio', label: 'Design Studio', Comp: window.StudioScreen },
{ id: 'inbox', label: 'Trend Inbox', Comp: window.TrendInboxScreen },
{ id: 'reports', label: 'Research Reports', Comp: window.ResearchReportsScreen },
{ id: 'etsy', label: 'Etsy Posting Workflow', Comp: window.EtsyPostingScreen },
];

function B1Handoff() {
const theme = window.WS_B1;
const [mode, setMode] = React.useState(() => localStorage.getItem('ws-b1-mode') || 'dark');
const c = mode === 'dark' ? theme.dark : theme.light;
const onSetMode = (m) => { setMode(m); localStorage.setItem('ws-b1-mode', m); };

React.useEffect(() => { document.body.style.background = c.bg; }, [c.bg]);

return (
<div style={{ minHeight: '100vh', background: c.bg, padding: '40px 0 80px', transition: 'background .2s' }}>
<header style={{ width: 1440, margin: '0 auto 28px', padding: '0 4px',
fontFamily: theme.fonts.mono, color: c.sub }}>
<div style={{ fontSize: 13, letterSpacing: '0.14em', textTransform: 'uppercase', color: c.accent }}>
Workshop · B1 — Concrete · Amber Dark
</div>
<div style={{ fontSize: 12, marginTop: 6, color: c.faint, letterSpacing: '0.04em' }}>
Design reference · {B1_SCREENS.length} screens · see README.md for the build spec
</div>
</header>

{B1_SCREENS.map(({ id, label, Comp }) => (
<section key={id} data-screen-label={label} style={{ width: 1440, margin: '0 auto 44px' }}>
<div style={{ fontFamily: theme.fonts.mono, fontSize: 12, letterSpacing: '0.1em',
textTransform: 'uppercase', color: c.faint, padding: '0 4px 10px',
display: 'flex', alignItems: 'center', gap: 10 }}>
<span style={{ width: 6, height: 6, background: c.accent, display: 'inline-block' }}></span>
{label}
</div>
<div style={{ height: 1180, border: `${theme.borderW}px solid ${c.hairline}`, overflow: 'hidden' }}>
<Comp theme={theme} mode={mode} scan={false} onSetMode={onSetMode} />
</div>
</section>
))}
</div>
);
}

ReactDOM.createRoot(document.getElementById('root')).render(<B1Handoff />);
Loading
Loading