2026-05-18 16:44:02 +09:00
# packages/web/ — Marketing Site (Next.js + Cloudflare Workers)
2026-05-08 13:35:00 +09:00
2026-05-20 17:18:44 +09:00
**Generated: ** 2026-05-20
2026-05-08 13:35:00 +09:00
## OVERVIEW
Public-facing marketing site for oh-my-opencode / oh-my-openagent. Next.js 15 (App Router) deployed to Cloudflare Workers via [@opennextjs/cloudflare ](https://opennext.js.org/cloudflare ). Independent of the npm plugin — its own `package.json` , `bun.lock` , and `tsconfig.json` .
## STACK
| Layer | Choice |
| -------------- | ----------------------------------------------------------------------------------- |
| Framework | Next.js 15.5 (App Router, RSC) |
| Runtime target | Cloudflare Workers (`compatibility_flags: ["nodejs_compat"]` ) |
| Adapter | `@opennextjs/cloudflare` (build → `.open-next/worker.js` ) |
| Styling | Tailwind v4 (`@tailwindcss/postcss` ) + shadcn/ui (`components.json` ) |
| i18n | `next-intl` with `app/[locale]/...` routing; 4 locales (en/ja/ko/zh) in `messages/` |
| Animation | `motion` (Framer Motion v12) |
| E2E | Playwright (`e2e/*.spec.ts` ) |
| Lint/Format | ESLint flat config + Prettier (Tailwind plugin) |
## STRUCTURE
```
2026-05-18 16:44:02 +09:00
packages/web/
2026-05-08 13:35:00 +09:00
├── app/[locale]/ # localized routes (App Router)
├── components/ # shared UI primitives + shadcn-generated
├── lib/ # utility helpers (cn, etc.)
├── messages/{en,ja,ko,zh}.json # i18n strings
├── i18n/ # next-intl request/routing config
├── middleware.ts # next-intl middleware
├── public/ # static assets (largest dir, ~4 MB)
├── e2e/ # Playwright tests
├── scripts/prepare-build.mjs # purges .next/cache/fetch-cache before build
├── next.config.ts
├── open-next.config.ts
├── wrangler.toml # worker name + compatibility settings
├── playwright.config.ts
├── eslint.config.mjs
├── postcss.config.mjs
├── tsconfig.json
├── components.json # shadcn config
└── package.json
```
## SCRIPTS
``` bash
2026-05-18 16:44:02 +09:00
# from packages/web/ directory
2026-05-08 13:35:00 +09:00
bun install
bun run dev # next dev (local Node.js)
2026-05-14 13:46:11 +09:00
bun run lint # biome lint + eslint
2026-05-08 13:35:00 +09:00
bun run lint:fix
bun run format # prettier --write
bun run format:check
2026-05-14 13:46:11 +09:00
bun run type-check # tsgo --noEmit
2026-05-08 13:35:00 +09:00
bun run build # next build (Node target — for sanity)
bun run preview # opennextjs-cloudflare build + preview locally
bun run deploy # opennextjs-cloudflare build + deploy to Cloudflare
bun run test:e2e # playwright test
bun run cf-typegen # regenerate cloudflare-env.d.ts from wrangler.toml bindings
```
## CI/CD
2026-05-18 16:44:02 +09:00
| Workflow | Trigger | What |
| ---------------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `.github/workflows/web-ci.yml` | push/PR to master/dev that touches `packages/web/**` | format check, lint, type-check, next build, opennextjs-cloudflare build |
| `.github/workflows/web-deploy.yml` | push to master that touches `packages/web/**` OR manual dispatch | full deploy via `cloudflare/wrangler-action@v3` |
2026-05-08 13:35:00 +09:00
**Required secrets ** (must be configured in repo settings before deploy works):
- `CLOUDFLARE_API_TOKEN` — token with `Workers Scripts: Edit` permission
- `CLOUDFLARE_ACCOUNT_ID` — Cloudflare account ID
A `web-production` GitHub environment is referenced by the deploy workflow so deploys can be gated behind required reviewers / wait timers if desired.
## RELATIONSHIP TO npm PACKAGE
2026-05-18 16:44:02 +09:00
The npm package `oh-my-opencode` ships only `dist/` , `bin/` , and `postinstall.mjs` (see root `package.json` `files` field). `packages/web/` is **not ** included in any npm publish — it is exclusively a separate Cloudflare deployment target.
2026-05-08 13:35:00 +09:00
2026-05-18 16:44:02 +09:00
Root `bun test` ignores `packages/web/**` through `bunfig.toml` so `packages/web/e2e/*.spec.ts` does not pollute plugin tests.
2026-05-08 13:35:00 +09:00
## CONVENTIONS
2026-05-18 16:44:02 +09:00
- **No path aliases globally** in the omo project, but `packages/web/` is a Next.js app where `@/*` aliases are the framework default. Keep `@/*` confined to packages/web/.
2026-05-08 13:35:00 +09:00
- Use the existing shadcn primitives in `components/ui/` rather than installing new UI libs.
- All user-facing copy goes through `messages/{locale}.json` ; never hardcode strings in components.
- Format with prettier before commit — `web-ci.yml` enforces `format:check` .
## ANTI-PATTERNS
2026-05-18 16:44:02 +09:00
- Never run `npm install` in `packages/web/` . Use `bun install` only. (Root `.gitignore` already blocks `package-lock.json` .)
- Never commit `.next/` , `.open-next/` , `.wrangler/` , `node_modules/` (covered by `packages/web/.gitignore` ).
2026-05-08 13:35:00 +09:00
- Never deploy locally with `bun run deploy` against production — use the GitHub Actions workflow so Cloudflare credentials live in one place.