ViewTouch Point of Sale
GNU/Linux Restaurant Point of Sale software - Free and open source POS solution
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
RepeatlyOS is a city marketplace where shoppers find real local businesses —
and the operating system those businesses run on: orders, bookings,
payments, and customers, all in one place. Launched in Batroun and Shekka,
Lebanon.
This repo holds two things at different stages of maturity, and it's worth
knowing which is which before you dig in:檢視完整 README ↗RepeatlyOS is a city marketplace where shoppers find real local businesses — and the operating system those businesses run on: orders, bookings, payments, and customers, all in one place. Launched in Batroun and Shekka, Lebanon.
This repo holds two things at different stages of maturity, and it's worth knowing which is which before you dig in:
/, /:citySlug, /app, /onboarding,
/platform-admin). This is what's described below./dashboard/*, kept around from before the Supabase build-out. It runs
entirely on fake in-memory data (src/context/DemoContext.tsx) and has no
connection to the real backend. Useful for showing off UI polish quickly
with zero setup, not representative of what a real business actually sees.For shoppers: browse a city's page (/batroun, /shekka), search across
every business in it — including a rule-based natural-language search
(/discover, try "nike basketball shoes in shekka") that falls back to
neighboring cities in the same region if nothing matches, or a real GPS-radius
"near me" search — add items from multiple businesses to one cart, and check
out as a guest (no account needed). Verified photo reviews, a verified-business
badge, live power-cut-aware "closed right now" status, and a city-wide loyalty
wallet (earn at any participating business, redeem at any other) round out the
shopping side.
For business owners: sign up, get approved, and run the shop from
/app/:businessId/* — products, inventory (a real append-only movement
ledger, not just a number you edit), orders, bookings with staff assignment
and overlap-safe scheduling, customers, tasks, payments, and analytics
(revenue heatmap, 30-day forecast, churn-risk flags, a health score, referral
leaderboard) — all computed from real data via Postgres functions, not
estimated client-side.
For the platform: a super-admin dashboard to approve businesses, open new cities, assign SaaS plans, manage the USD/LBP exchange rate shown throughout the marketplace, and revoke passkeys.
npm install
cp .env.example .env # fill in your Supabase project URL + anon key
npm run dev # → http://localhost:5173
Real backend, real schema — this is not a zero-config demo. You need an actual Supabase project. See Backend setup below.
npm run build # tsc -b && vite build
npm run lint
npm run test # vitest — unit tests for the parsing/math-heavy logic
.env
(.env.example has the exact variable names).supabase link --project-ref <your-ref> then
supabase db push — applies every file in supabase/migrations/ in
order. There are currently 41 migrations building up the full schema
incrementally; read a few if you want the "why", not just the "what" —
this codebase documents its own reasoning unusually heavily.supabase/seed.sql once (via the SQL editor, or
supabase db reset locally) for the business-type templates and the
first launch city.supabase/functions/ (verify-login,
admin-manage-passkeys, decrypt-invite-email,
decrypt-customer-address) — supabase functions deploy <name> each, or
via the Dashboard.insert into public.platform_admins (user_id) values ('<your auth.users.id>');
supabase test db # pgTAP — requires Docker Desktop
Covers core SQL logic (booking-overlap constraint, inventory auto-decrement,
loyalty balance) and an automated tenant-isolation check. See
supabase/tests/README.md.
No passwords, no codes, no emailed links — every login page works the same
way: type your email, click Verify, and if you're authorized, register
a passkey right there (or just use your existing one on repeat visits).
See docs/REPEATLYOS_SECURITY_MODEL.md → "Bootstrap flow reworked" for
exactly how a real session is established with nothing ever shown to or
typed by the user.
Business owner:
/signup (just an unauthenticated
signup_requests row — no account exists yet)./platform-admin — this only flips
the request's status; it doesn't create an account or send anything./app, enters that same email, clicks Verify, and
registers a passkey — landing on /onboarding.status = 'pending_approval' and they're made its owner immediately.pending_approval only hides the business from the public marketplace;
it does not block the owner's own use of their dashboard.City admin: a platform admin adds their email against a city from
/platform-admin (no account needs to exist yet) — they then verify and
register a passkey at /city-admin-login. Never self-registered.
Platform admin: the one role still requiring direct SQL access
(insert into platform_admins ..., see below) — intentional friction so
this can never be granted through the app itself. Once granted, sign-in
itself works the same way, at /super-admin.
Lost your passkey or switched devices? Same flow, any role: email + Verify re-establishes a session and lets you register a new one — fully self-service, no admin involvement needed.
React 19 · TypeScript (strict) · Vite · Tailwind CSS · React Router 7 · Supabase (Postgres + Auth + Edge Functions + Storage) · Recharts · Vitest
No custom API server — Postgres Row Level Security is the actual
authorization boundary; every table has RLS enabled with policies backed by
security definer helper functions (is_business_member,
has_business_permission, is_city_admin, is_platform_admin).
repeatlyos/
├── supabase/
│ ├── migrations/ # 41 files, applied in order — the real schema
│ ├── functions/ # 4 Edge Functions (service-role-gated operations)
│ └── tests/database/ # pgTAP tests
├── src/
│ ├── App.tsx # all routes — marketplace, /app, /dashboard, admin
│ ├── lib/ # smartSearch, geo, currency, i18n, checkout, offlineQueue
│ ├── pages/
│ │ ├── marketplace/ # public shopper-facing pages
│ │ ├── business/ # real merchant dashboard (Supabase-backed)
│ │ ├── admin/ # platform + city admin
│ │ ├── onboarding/ # business registration wizard
│ │ ├── auth/ # signup, per-role sign-in pages, passkeys
│ │ └── dashboard/ # legacy mock demo — see note at the top
│ └── types/domain.ts # hand-written mirror of the SQL schema
└── docs/ # architecture, security model, progress log —
# read these for the "why" behind non-obvious decisions
delivery_pool_members and
delivery_groups model shared delivery coordination internally, but
dispatching an actual rider needs a specific local courier chosen (a
business decision, not a code one).supabase/tests/), not exhaustive
coverage of all 33 tables.cities is a normal table, not a hardcoded list), not a code change.See docs/REPEATLYOS_PROGRESS.md for the full, dated history of what was
built, tested, and found along the way.