Ecommerce Template
Next.js·React 등으로 만든 최신 전자상거래 템플릿
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Merqo is a configurable, multi-business-type Point-of-Sale platform, deployed independently
per client. One POS engine adapts to supermarkets, restaurants, pharmacies, fashion stores,
and more via configuration rather than per-industry rewrites.
See docs/milestones/README.md for the full implementation
roadmap and docs/milestones/DECISIONS_AND_CONFLICTS.md
for the authoritative resolution of architectural decisions.README 전문 보기 ↗Merqo is a configurable, multi-business-type Point-of-Sale platform, deployed independently per client. One POS engine adapts to supermarkets, restaurants, pharmacies, fashion stores, and more via configuration rather than per-industry rewrites.
See docs/milestones/README.md for the full implementation
roadmap and docs/milestones/DECISIONS_AND_CONFLICTS.md
for the authoritative resolution of architectural decisions.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router) + React 19 + TypeScript 6 |
| Styling | Tailwind CSS v4 (CSS-first) + shadcn/ui |
| Backend/data | Supabase (Postgres + Auth + Storage) |
| Resend | |
| Subscription billing | Paystack — software subscriptions only, never POS payments |
| Package manager | pnpm |
| Testing | Vitest + React Testing Library (unit), Playwright (E2E) |
| CI/CD | GitHub Actions |
| Hosting | Vercel |
There is no Express or standalone Node backend. Server-side logic lives entirely in
Next.js Server Actions and Route Handlers, talking to Supabase directly. Earlier design
documents (docs/PRD.md, docs/TAS.md) describe an Express-based "ERN" stack — that was
superseded during the design process; see docs/milestones/DECISIONS_AND_CONFLICTS.md §1
before reintroducing it.
.nvmrc)corepack enablepnpm db:start)corepack enable
pnpm install
cp .env.example .env.local # fill in Supabase values, see below
pnpm dev # http://localhost:3000
Verify it's running:
curl http://localhost:3000/api/health
# {"status":"ok","service":"merqo","timestamp":"...","commit":null,"checks":{"supabase":"not_configured"}}
checks.supabase reads "not_configured" until .env.local has real Supabase values — that's
expected, not an error.
Every variable is documented in .env.example with inline comments. Three
rules apply everywhere in this project:
.env.example holds placeholders only.NEXT_PUBLIC_ is shipped to the browser. Never put a secret behind that
prefix.SUPABASE_SERVICE_ROLE_KEY is server-only and bypasses Row Level Security. It must never
be imported from a Client Component, and lives only in Vercel's and GitHub's encrypted
secret stores — never in a file that gets committed.| Variable | Required from | Scope | Source |
|---|---|---|---|
NEXT_PUBLIC_APP_URL | Milestone 01 | Public | Set manually |
NEXT_PUBLIC_SUPABASE_URL | Milestone 01 | Public | Supabase Dashboard → Project Settings → API |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Milestone 01 | Public | Supabase Dashboard → Project Settings → API |
SUPABASE_SERVICE_ROLE_KEY | Milestone 03 | Server-only | Supabase Dashboard → Project Settings → API |
SUPABASE_PROJECT_REF | Milestone 01 | Server-only | Supabase Dashboard, or supabase status locally |
SUPABASE_DB_PASSWORD | Milestone 02 | Server-only | Set when the project was created |
RESEND_API_KEY | Milestone 12 | Server-only | Resend dashboard |
PAYSTACK_SECRET_KEY | Milestone 13 | Server-only | Paystack dashboard (subscription billing only) |
pnpm db:start # requires Docker Desktop running
pnpm db:status # prints local URL + keys — paste into .env.local
pnpm db:stop
There is no schema yet — that's Milestone 02. pnpm db:start gives you a working local
Postgres/Auth/Storage stack to develop against as soon as migrations exist.
main is production-ready. Direct pushes are disabled by branch protection (see below).feature/*, fix/*, or chore/* branches, merged via pull request.docs/milestones/DECISIONS_AND_CONFLICTS.md
and the Milestone 01 PR for context: GitHub's branch-protection APIs return a 403 on private
repos without a paid plan, so the repo was made public to unlock real enforcement and native
secret scanning at $0 cost).required_approving_review_count is set to 0 — GitHub does not allow self-approval,
which would otherwise permanently block a solo contributor. This is a deliberate, documented
exception, not an oversight.pnpm test # Vitest, once
pnpm test:watch # Vitest, watch mode
pnpm test:e2e # Playwright — builds and starts the app itself
pnpm test:e2e:ui # Playwright, interactive UI mode
First-time Playwright setup: pnpm exec playwright install chromium.
Every pull request against main runs three jobs, all required to pass before merge:
pnpm format:check && lint && typecheck && test && build.Later milestones extend .github/workflows/ci.yml with their own test suites rather than
creating a parallel pipeline.
import { logger } from '@/lib/logger'
logger.info('sale.created', { saleId, branchId })
console.* method by severity.message is a dotted event name, not a sentence — grep-able and stable across refactors./key|token|secret|password|authorization|cookie|apikey/i are
automatically redacted before logging.docs/milestones/16-launch/operations.md
for the symptom → destination table that maps these event names to where you look during an
incident.Hosted on Vercel: production deploys from main, preview deploys per pull request. Environment
variables are set in Vercel's dashboard for both Production and Preview — never in git.
The Super Admin role (platform.override + platform.manage_pricing, exempt from the
subscription lock — see docs/milestones/DECISIONS_AND_CONFLICTS.md §5) cannot be assigned
through the app or the role builder; it is granted once, deliberately out-of-band, via a SQL
function with no EXECUTE grant to any application role:
public.users row must already exist).psql connected as the postgres role), run:
select public.promote_to_super_admin('[email protected]');
on conflict do nothing) and audited (platform.super_admin_promoted
in audit_logs). No app restart or redeploy needed — the next request that account makes
picks up the new grant.https://<your-domain>/api/webhooks/paystack as the webhook URL in the Paystack
Dashboard (Settings → API Keys & Webhooks). Paystack signs every delivery with your secret
key — there is no separate webhook secret to configure on Paystack's side, despite
PAYSTACK_WEBHOOK_SECRET existing as a reserved (optional) env var; see .env.example.CRON_SECRET (openssl rand -hex 32) and set it as a Vercel project environment
variable. Vercel's Cron (configured in vercel.json) automatically sends
Authorization: Bearer $CRON_SECRET to /api/cron/subscriptions once that variable exists —
no further wiring needed. Leaving it unset makes the endpoint refuse to run (503), never run
unauthenticated.docs/milestones/16-launch/cost-model.md.docs/milestones/16-launch/launch-checklist.md
§7, for a decision at launch. It does not block development.[email protected]'s bundled
[email protected] crashes at runtime against ESLint 10's removed legacy Context
API (context.getFilename()). Revisit once Next.js ships an eslint-config-next update
compatible with ESLint 10.