尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 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.