Order Ly
카페 POS와 QR 셀프 주문, 고객은 테이블 QR로 주문·결제하고 캐셔 PC는 오프라인으로 작동
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Live at https://runam.app
Runam is a web app for errands inside the estate: residents ask for food, groceries, gas refills, parcel pick-ups or laundry, a vetted runner does it, and the shop is paid directly by the platform so runners never handle residents' money.
It's a mobile-first web app (installable on the home screen). Everyone signs in at /login with their phone number, and the app opens the right part for them:
| Who | Where | What they do |
|---|---|---|
| Residents | /home | Start an errand, pay with Paystack or wallet, track it live, approve extra money, give the delivery code, get change back in their wallet, rate the runner |
| Runners | /runner | Go online, get errands (with sound + vibration), accept, confirm the purchase with a receipt photo, the shop is paid automatically, deliver, enter the resident's code |
| Shop staff | /shop | Chat with customers, see riders on their way |
| You (admin) | /admin | Live dashboard, errands, runners, shops & their items, payout approvals, runner payouts, residents (incl. "gone quiet" watch), support chats, fees and settings |
Who gets in where. Everyone signs in with their email and a 6-digit code we email them. Only the emails in ADMIN_EMAILS can open /admin. An email becomes a runner when you add it in Admin → Runners, and shop staff when you add it to a shop. Everyone else is a resident. If someone opens a page that isn't theirs (a runner trying /admin, say), they're sent back to their own home. Admins can also use the resident app, and there's an "Open admin console" button on their Account page.
"Runam" is a working name. Change it in one place: set
NEXT_PUBLIC_APP_NAME(andNEXT_PUBLIC_ESTATE_NAME) in your environment.
Chat with the shop. Residents tap a shop and chat with it in the app: ask what's in stock, agree the price, and pay the shop directly (the shop can send its bank details in one tap). Once they've paid, they tap Send rider, enter the name the order is under, and pay the delivery fee in the app. The shop is then asked in the chat (and on its "Riders coming" tab) whether the payment reached them: only after Payment received is a rider sent. Not yet tells the resident to check their transfer or cancel. (Shops with nobody on chat skip this step; an admin can also confirm on the shop's behalf from the errand page.) The shop sees in the same chat when the rider arrives. At the door the rider enters the resident's delivery code and takes a photo of the handover as proof of delivery. Cancelling before the rider reaches the shop refunds the fee to the wallet.
Phone numbers and WhatsApp links typed into chats are hidden, so orders stay on the platform.
Let a runner buy it. The resident pays everything up front and the app pays the shop, as described below. This needs Paystack Transfers, so it's off by default: switch it on in Admin → Settings once your Paystack account can send transfers. While it's off, the Food, Groceries and Gas tiles show those shops, and Pick up / Laundry errands (no buying involved) still work.
Residents can call a shop from its chat, and residents and runners can call each other during an errand, using the call button. Calls go over the internet (WebRTC), so phone numbers are never shared, and they aren't recorded; the chat or errand timeline gets a line like "Voice call · 2:31" or "Missed call".
Calls connect directly between phones. On some mobile networks that isn't possible without a relay, so for reliable calls add a TURN service (for example Cloudflare Realtime TURN or Metered) and set TURN_URLS, TURN_USERNAME and TURN_CREDENTIAL. Microphone access needs HTTPS, which the live site has.
Residents, runners and shop staff can tap Chat with support (Account, Profile or the shop inbox, and "Get help" on any errand). Messages arrive in Admin → Support with a badge and a push notification to every admin; replies go straight back to them. Next to the chat there are Call and WhatsApp buttons for the support phone set in Admin → Settings (also shown on the landing page, the login screen, and in the Terms and Privacy Policy).
In /admin/vendors, add each shop's staff under Shop staff on chat (email + name). They sign in with that email like everyone else and land in the shop inbox at /shop: chats with customers, and riders on their way. Residents never see it. Removing someone signs them out.
This is what keeps everyone in the app: residents are covered only for in-app payments, runners never hold cash, runners are assigned automatically (so nobody "owns" a household), phone numbers stay hidden behind in-app chat, and the admin "gone quiet" list flags regulars who suddenly stop ordering.
Everything in this section is for a test copy on your own computer. The live site has no demo data and no demo mode.
Requirements: Node 20.9+ and a Postgres database (local, or a free one from Neon).
npm install
cp .env.example .env # then set DATABASE_URL, and DEMO_MODE=true
npm run setup # creates tables + demo data
npm run dev # http://localhost:3000
With DEMO_MODE=true and no Paystack key, payments go through a pretend checkout and shop transfers "settle" after a few seconds, and the login code is shown on screen (without it, codes are only printed in the terminal).
⚠️
DEMO_MODE=truelets anyone sign in as anyone. Never set it on the live site. Without it and without a Paystack key, the app refuses payments with "Online payments aren't switched on yet".
Demo accounts (all made up, local only; the seed script refuses to run against anything but a local database):
| Role | |
|---|---|
| Admin | [email protected] (whatever you put first in ADMIN_EMAILS) |
| Resident | [email protected] |
| Runner | [email protected], [email protected], [email protected] |
| Shop staff | [email protected] (Village Mart) |
Start an errand as Amaka in one browser and accept it as Adaeze in another (or a private window) to see the whole flow.
To wipe everything and start again: npm run db:seed -- --reset (deletes all data).
Create a Postgres database (Neon free tier is plenty to start). Use the pooled connection string as DATABASE_URL.
.env.example (see the table below).vercel-build script runs database migrations automatically before each build./login with your admin email and add your real shops and runners in /admin. Don't set DEMO_MODE and don't run the demo seed on the live database.Create a Paystack business account and complete business activation. A Starter (unregistered) business can take payments but can't send transfers; a Registered business (CAC) can do both.
Put your secret key in PAYSTACK_SECRET_KEY (sk_test_… first, sk_live_… at launch). On a Starter business also set PAYSTACK_TRANSFERS=off: bank account names are then typed in, and runner payouts and wallet withdrawals appear in Admin → Payouts for you to pay from your bank app and tap Mark as paid.
In Paystack → Settings → API Keys & Webhooks, set:
https://YOUR-DOMAIN/api/paystack/webhookhttps://YOUR-DOMAIN/pay/callback(Both are shown with a copy button in /admin/settings.)
In Paystack → Settings → Preferences, turn off OTP for transfers, otherwise automatic shop payments will stop and ask for an OTP.
Keep your Paystack balance topped up so transfers to shops and runners go through.
Paystack charges a fee on every payment; build that into your service fees in /admin/settings.
Create a Resend account, add your domain (it gives you a few DNS records to add), and set RESEND_API_KEY and EMAIL_FROM (e.g. Runam <[email protected]>). Nobody can sign in on the live site until this is done: without it, codes are only written to the server logs (Vercel → your project → Logs, search for email:console). Resend's free plan covers 3,000 emails a month (100 a day).
SMS (Termii) is optional and only used for a few errand alerts. A Nigerian SMS sender ID needs CAC documents.
npx web-push generate-vapid-keys
Put the keys in NEXT_PUBLIC_VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY. Runners and residents can then switch on notifications from their profile. On iPhone this needs the app added to the home screen first.
The Terms of Service (/terms) and Privacy Policy (/privacy) are written for a Nigerian business under the Nigeria Data Protection Act 2023. Set NEXT_PUBLIC_LEGAL_NAME to your registered business name and the support phone in /admin/settings, and have a lawyer look over both before launch. Depending on how many people's data you handle, you may also need to register with the Nigeria Data Protection Commission.
| Variable | Required | What it's for |
|---|---|---|
DATABASE_URL | ✅ | Postgres connection string |
APP_URL | ✅ | Your public URL, e.g. https://runam.app (no trailing slash) |
SESSION_SECRET | ✅ | Long random string — openssl rand -base64 48 |
ADMIN_EMAILS | ✅ | Comma-separated admin emails |
RESEND_API_KEY, EMAIL_FROM | ✅ | Sends sign-in codes by email |
PAYSTACK_SECRET_KEY | for payments | Empty = no payments (pretend checkout only with DEMO_MODE=true) |
PAYSTACK_TRANSFERS | off for a Starter Paystack business (no transfers): payouts are paid by hand | |
PAYSTACK_EMAIL_DOMAIN | Used to build an email for residents who haven't added one | |
SMS_PROVIDER, TERMII_* | Optional SMS alerts | |
DEMO_MODE | Local demo only: on-screen login codes and a pretend checkout. Never set on the live site. | |
NEXT_PUBLIC_VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT | for push | Web push notifications |
NEXT_PUBLIC_APP_NAME, NEXT_PUBLIC_ESTATE_NAME | Rename the app / estate | |
NEXT_PUBLIC_LEGAL_NAME | Your registered business name, used in the Terms and Privacy Policy | |
TURN_URLS, TURN_USERNAME, TURN_CREDENTIAL | for calls on mobile data | TURN relay for in-app calls |
/admin/runners with their phone, NIN, guarantor and bank account. They sign in with that phone number./admin/vendors (Shops) with a photo, the staff who reply to chats, their bank account and popular items. Partner shops are paid automatically./admin/payouts (one-off shops and wallet withdrawals), and pay runners their earnings weekly with one tap.Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS 4 · Motion · Drizzle ORM + Postgres · Paystack · Termii · Web Push.
src/app/(auth) sign-in and onboarding
src/app/(resident) resident app
src/app/runner runner app
src/app/admin admin console
src/app/api JSON endpoints, Paystack webhook, uploads
src/lib/orders order state machine, dispatch, queries
src/lib/payouts.ts transfers to shops/runners
src/lib/db schema (drizzle) — migrations live in /drizzle
Useful commands: npm run typecheck, npm run db:generate (after editing the schema), npm run db:migrate.