Ecommerce Template
Next.js·React 등으로 만든 최신 전자상거래 템플릿
Merqo는 싱가포 소규모 판매자를 위한 간편 도구군을 qkit, 실시간 대기열·주문 등 앱·하드웨어 없이 제공
Merqo builds a family of no-fuss tools for Singapore's small sellers — starting with qkit, live queues and orders with no app and no hardware.
커머스TypeScript · PLpgSQLGitHub @merqo-io온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗House brand + operator console for a modular family of small-business tools
("kits") for Singapore micro/small sellers. qkit (queue/orders), loopkit
(stamp-card loyalty), paykit (payments), and stockkit (inventory) are
live; shopkit and reachkit are upcoming (see src/lib/kits.ts).
This app is the public brand landing plus a role-gated operator console:
/dashboard — cross-product metrics overview (post-login home)/admin/vendors — grant/revoke kit access per vendor/admin/team — manage Merqo-team members/admin/products — per-kit health from the metrics API/admin/feedback — vendor NPS + comments per kit/admin/activity — the admin-audit trail (every real mutating admin action)/about — public "Why Merqo" page: the qkit origin story and a
founder/business-name line matching /legal/terms's phrasingEach kit runs its own app on its own schema in a shared Supabase project.
Merqo pulls per-kit metrics over an HTTP API (bearer secret) — it never
queries another kit's schema directly. Brand theme is "Harbour Control"
(harbour-navy primary, buoy-amber accent) as of 2026-08-19, replacing
"Control Room" (pine-green + marigold-gold) — see globals.css's own
header comment. src/lib/brand-icon.tsx's ImageResponse-generated
favicon/apple-touch-icon carries the same rebrand. Dark mode moved from a
pure OS-media-query to a .dark-class-based approach (@custom-variant dark), driven by next-themes' ThemeProvider wrapping the root layout,
so @merqo/ui's AccountMenu (v0.18.0, collapsed into a "Theme · {current}"
submenu as of v0.19.0) now exposes a manual Light/Dark/
System control on top of the existing OS-auto behavior. In production, every kit's auth
cookie is scoped to .merqo.io (NEXT_PUBLIC_AUTH_COOKIE_DOMAIN,
src/lib/supabase/), so signing in on one kit signs you in on the rest —
unset in dev/preview, where each kit still runs on its own *.vercel.app
host. Kit links (src/lib/kits.ts) default to each kit's
https://<kit>.merqo.io host; NEXT_PUBLIC_<KIT>_URL overrides one. The dashboard's onboarding tour (src/components/dashboard-tour.tsx)
stamps its "seen" state as soon as it auto-runs rather than when it
finishes, so a refresh mid-tour can't make it re-trigger on the next load —
and since that client-fired stamp is fire-and-forget and can be aborted by
a hard navigation (the tour's own steps spotlight @merqo/ui's
AccountMenu trigger, whose dropdown renders links as plain <a> tags),
/dashboard's own server render (src/app/dashboard/(app)/layout.tsx)
also stamps it synchronously, durably, as part of the request. The tour's
"your kits" step now spotlights the active-kit grid (data-tour="kit-cards")
with an inline example kit-card preview in its description, the same
example-card treatment every other Merqo kit's own onboarding tour carries
on its first step — that preview's plan-tier pill renders the real Badge
component instead of a hand-copied color, so it can't drift from what the
badge actually looks like — see
../docs/superpowers/specs/2026-08-25-tour-example-badge-drift-fix-design.md
(workspace root, cross-kit spec). The landing footer matches qkit's exactly
(single-row wordmark/tagline/credit-line/sign-in link, no CTA band above it).
Merqo uses @merqo/ui, the shared component package for the kit family (see
qkit/loopkit/paykit/stockkit for the same dependency). /about's own story
is now @merqo/ui's shared
AboutMerqo component (v0.25.0), the same content every kit's own
/about page renders. LegalDocument (every /legal/* page) gained a
"← Back" button in the same release. As of v0.24.0, TermsAcceptanceCheckbox no longer
collects a typed legal name — just the agree checkbox — since a plain
ToS/Privacy clickwrap doesn't need a signatory name for evidentiary
strength beyond the existing acceptance record (see /legal/accept's
own README). useAsyncAction, InfoTooltip, Section,
TwoColumnSections, ImageUploader, and DashboardTour are used directly
or through a thin per-app adapter (src/hooks/use-async-action.ts,
src/lib/image-upload-adapter.ts, src/components/dashboard-tour.tsx).
dashboard-nav.tsx composes @merqo/ui's DashboardNav for both the
vendor dashboard and admin-console headers (burger, inline links, account
menu, kit switcher on the dashboard), and both layouts end with the landing
Footer without its sign-in link. The profile and vendor-detail pages use
BackButton. The profile page composes shared Section, TwoColumnSections, ImageUploader and SocialLinksFields in route-local sections. Each section owns its save state and retains its distinct server-action or Supabase Auth contract.
@merqo/ui's AccountMenu hardcodes its Profile link to
/dashboard/profile; src/app/dashboard/profile/page.tsx redirects that
to Merqo's real, persona-shared /profile route. The landing nav
(src/components/landing/nav.tsx) is built on @merqo/ui's LandingNav
shell (wordmark/end slots), added in v0.9.0. v0.10.0 added an optional
LinkComponent prop to AccountMenu/DashboardNav so Next.js consumers can
opt their internal nav links out of a plain <a>'s full page reload;
dashboard-nav.tsx passes LinkComponent={Link} (next/link).
@merqo/ui bumped to v0.32.0 (2026-09-22), for currency. It adds
ImageUploader's deferUpload mode (upload on save instead of on pick);
this app doesn't need it, because its only uploader is the profile icon,
which saves the moment an image is picked.
@merqo/ui bumped to v0.31.4 (2026-09-22), for its new
storagePathFromPublicUrl. Replacing or removing a profile icon now deletes the
old image from storage (removeReplacedAvatar in
src/lib/image-upload-adapter.ts); before this, every avatar change orphaned one
file, because ImageUploader names each upload randomly.
@merqo/ui bumped to v0.31.3 (2026-09-22), which also stops resizeToWebp
mislabelling a PNG as WebP on browsers that cannot encode WebP; the public
vendor-avatars bucket now enforces 5 MB and JPEG/PNG/WebP itself (migration
0030). Before that, v0.31.2 (2026-09-19), from v0.29.3. v0.31.0 replaced
the package-wide "use client" banner with per-module directives, so a
plain-data export is a real value inside a Server Component rather than an
opaque client-reference stub — the root cause of the 2026-09-18 RSC crashes
across the kits. It also promoted four modules merqo had its own copy of:
safeRedirectPath, resizeToWebp, BackToTop and GoogleMark. The
landing Footer is now a thin adapter over the shared one, passing
copyright and signInLabel overrides so the hub keeps saying
the current-year Merqo copyright and "Sign in →" rather than a kit's "a Merqo kit" /
"Vendor sign in →"; rendered output is unchanged. v0.31.1 fixes a latent
resizeToWebp bug where a dotless filename yielded the whole name as its
extension. Which repo uses which shared export is tracked in
../merqo-ui/docs/usage-matrix.md.
Next.js 16 · App Router · Turbopack · TypeScript strict · Tailwind v4 ·
shadcn/ui (new-york) · Zod · Supabase (@supabase/ssr) · Vitest ·
Playwright · pnpm 11 · Node ≥24 · deploy target: Vercel
pnpm dev # dev server — http://localhost:3000
pnpm build # production build
pnpm test # run test suite (vitest)
pnpm test:e2e # playwright public smoke
pnpm check # prettier --check + eslint + tsc --noEmit
pnpm format # prettier --write
pnpm check:legal-versions # compare actual legal versions at each product's locked UI commit
pnpm-workspace.yaml's overrides block pins transitive deps (postcss,
nanoid, undici, fast-uri, js-yaml, brace-expansion, sharp) past known CVE
thresholds — pnpm audit --prod --audit-level=high (CI's security.yml
audit job) hard-gates on these. When a new advisory lands on a transitive
dep, bump its floor here rather than waiting on the upstream package to
update; a floor set too low silently stops helping once a newer vulnerable
release ships within the allowed range.
src/app/ — app router (landing, dashboard, admin console, server actions)
src/app/page.tsx — public brand landing with session-aware CTAs
src/app/dashboard/ — vendor dashboard: (app)/ (overview + kit discovery,
open to every signed-in user)
src/app/admin/ — Merqo-team console: overview (page.tsx) + vendors/, team/,
products/, feedback/, activity/ (all auth-gated)
src/app/profile/ — shared account page (signed-in gate only — reachable from
both the vendor dashboard and the admin console)
src/app/login/ — email/password sign-in
src/app/api/telegram/webhook/ — merqo's own Telegram bot's webhook (customer connect)
src/app/api/merqo/ — bearer-secret endpoints qkit/loopkit call INTO merqo
src/proxy.ts — Supabase session refresh + route guard (Next 16)
src/components/landing/ — landing sections (nav, hero, kit-stacker, …)
src/components/dashboard/ — dashboard widgets (stat cards, kit discovery/preview cards)
src/components/brand/ — shared Merqo wordmark
src/hooks/use-async-action.ts — shared pending/error state for server-action buttons
src/lib/kits.ts — kit family config (landing roadmap source of truth)
src/lib/metrics-client.ts — fetch of a kit's HTTP metrics endpoint
src/lib/vendor-activity-client.ts — fetch of a single vendor's per-kit triage status/metrics
(admin/vendors/[email]'s Activity cards)
src/lib/schemas.ts — Zod schemas for the profile page's forms
src/lib/merqo-vendor-profile.ts — typed wrapper over the shared vendor_profile RPCs
src/lib/supabase/ — browser / server (schema=merqo) / service-role clients
supabase/migrations/ — SQL schema (merqo.* tables) + RLS + grants
supabase/seed/staging-registry.sql: one-time staging registry wiring (docs/STAGING.md)
scripts/staging-migrate.sh: applies migrations to the staging project with psql
scripts/check-legal-version-skew.mjs — asserts merqo + all 5 kit repos pin
matching terms/privacy/pilot versions from exact locked UI commits
One shared Supabase project, schema per kit. Merqo owns merqo.*:
merqo_team (team membership), products (kit registry + per-product
metrics_secret), vendor_links (vendor↔kit access, email-keyed),
billing_settings (cross-kit pricing levers — currently just the
bundle-discount toggle, public-read, service-role-only write),
customers (cross-kit customer identity — phone-keyed OR Telegram-chat-keyed
per vendor since the 2026-08-16 widening, the shared counterpart to
vendor_profile, reachable only through upsert_customer and three
Telegram-identity SECURITY DEFINER functions, called by qkit/loopkit),
telegram_link_tokens (short-lived deep-link tokens for merqo's own
customer-facing Telegram bot, service-role only), admin_audit (every real
mutating admin action — kit-access grant/revoke, team add/remove, the
bundle-discount toggle, support-message resolution — recorded via
recordAudit(); immutable at the grant level, no update/delete grant
to any role; surfaced on /admin/activity). Merqo also hosts that
bot's webhook plus two bearer-secret endpoints qkit/loopkit call into —
the first kit → merqo HTTP direction in this codebase (see
docs/superpowers/specs/2026-08-16-customer-telegram-connect-design.md).
RLS defaults to deny. Vendors can read their own vendor_links; registry
secrets and administrative writes use server-only service clients, so
metrics_secret never reaches a browser.
CHANGELOG.md (includes the new admin-audit trail, plus a fix
restoring card/background contrast in both modes after the Harbour
Control rebrand had accidentally collapsed them to the same color and a
follow-up dark-mode brightness bump, a fix routing every signed-in
landing CTA through /post-login instead of straight to /admin,
founder Telegram alerts on any kit's help/feedback submission, a
fix to that alert's own setup runbook (it was missing the step where
you message the bot first), and security bumps of next to 16.3.4,
browserslist to 4.28.9, and vitest to 4.1.11, and a vitest.config.ts
testTimeout bump from 10s to 30s fixing a real test-isolation leak where a
timed-out test skipped its cleanup and bled a stale render into the next test)docs/DEPLOY.mddocs/STAGING.md. .gitattributes
keeps *.sh on LF line endings so the staging script runs in a Linux
container from a Windows checkout.docs/superpowers/.claude/README.mdSee AGENTS.md for full engineering rules, harness details, and skills.
Vendor grants, product options, team memberships and open support messages read all API pages in stable order. Incomplete reads fail rather than showing partial administrative data. Email resolution queries only referenced auth user IDs in batches of eight; adding a team member by email retains full directory pagination. Recent audit entries remain intentionally limited by the requested history size. These offset-based lists are operational views, not transactionally consistent accounting snapshots.
The legal rollout check reads each product's lockfile and uses the sibling
merqo-ui Git checkout to inspect its exact committed legal constants. Fetch
any missing locked commit before running the check. Different UI releases are
allowed when the legal document versions match. Git uses its standard installed
path (Windows: C:/Program Files/Git/cmd/git.exe; Unix: /usr/bin/git).
The shared UI dependency is pinned to immutable commit 7b386558af36a1cbf008a9b4c4073c07ffc105ba, tagged v0.34.2, carrying the reviewed upload lifecycle, storage URL validation and safe money parsing fixes. Since v0.32.1, Section title tooltips and default-mode InfoTooltips open on a tap as well as on hover and keyboard focus. Since v0.32.2 every info icon also takes taps through a 44px touch area on touch devices. Since v0.32.3 a long tooltip wraps inside the viewport. Since v0.34.2 a server action that ends in redirect() counts as navigation, not an error. pnpm 11.10 permits preparation only for that exact locked source URL; update the dependency and its build allowlist together.
The AI harness follows templateCentral 6.0.4: hook commands are anchored on the project directory, and the guard against committing to main reads the branch of the directory a command runs in. The dated entry in AGENTS.md lists what was adopted.
src/proxy.ts sets the CSP (nonce on per-request routes) and X-Robots-Tag on non-production deployments. The operator console requires TOTP MFA; see src/app/mfa/README.md and docs/security/.
eslint.config.mjs consumes the shared @merqo/ui/eslint preset (comment and directive hygiene, size and complexity limits, no colour literals or em dashes in src). eslint.config.test.ts asserts the key rules stay at error. Colour literals are allowed only in src/lib/brand-icon.tsx and src/app/global-error.tsx.