MONAILabel
MONAI Label은 지능형 오픈소스 이미지 라벨링 및 학습 도구이다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Nurora counsellor scheduling and time tracking
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Counselling practice console — scheduling, session time tracking and payments,
with reminders that reach both the counsellor and the client three days before
every appointment.
Next.js 15 (App Router) · Supabase (Postgres + Auth + Realtime) · Vercel.
Sign-up and sign-in use email and password. The first account created
becomes a counsellor with admin rights — a lane on the schedule plus
full control of the practice.README 전문 보기 ↗Counselling practice console — scheduling, session time tracking and payments, with reminders that reach both the counsellor and the client three days before every appointment.
Next.js 15 (App Router) · Supabase (Postgres + Auth + Realtime) · Vercel.
Sign-up and sign-in use email and password. The first account created becomes a counsellor with admin rights — a lane on the schedule plus full control of the practice.
Booking desk — clients do not book themselves. They call, and whoever picks up works a three-step flow: find the caller (by phone digits, so repeat callers never get duplicated), capture their details and what they need help with, then match them to a counsellor by specialism and language and take a slot from real availability. If the day is full it offers the next days that are not, so nobody is turned away on the phone. Every booking records who took it and how it arrived (phone, walk-in, referral, online).
Schedule board — the day's sessions grouped into a lane per counsellor. A 7-day strip expands to a full month. Each row shows the time, the client, an inline age chip, and a Start button. Open slots in a counsellor's availability appear as bookable gaps.
Two independent timers
Payments — every booking raises an invoice. Settle it by hand (UPI, cash, bank transfer, card, cheque) with a method and reference, refund it, waive it, or re-price it from the time actually tracked. No payment gateway is wired in.
WhatsApp confirmations — booking, moving or cancelling a session sends the
client a WhatsApp message straight away (Twilio), with email alongside when an
address is on file. WhatsApp leads; SMS is a fallback, not a second copy, so
nobody gets the same message twice. Numbers are normalised to E.164 first — a
stored 09876543210 is dialled as +919876543210 — and an unusable number is
skipped rather than sent as garbage. Counsellors get their own copy according
to the notification preferences on their profile.
Production also needs approved WhatsApp templates: Meta blocks free-form
business-initiated messages outside a 24-hour window, so set the Twilio Content
SIDs in .env. Left blank, the app sends free-form text — which is exactly what
the Twilio sandbox accepts in development.
Nothing here can take a booking down: every send is awaited but its failure is recorded, never thrown. The session is booked either way, and the desk is told separately whether the message got out. Reception can resend the confirmation from the appointment page when a client gives a corrected number.
Reminders, three days out — a daily Vercel Cron job finds every session exactly three days away and notifies both parties by email (Resend), WhatsApp/SMS (Twilio) and in-app. Sends are idempotent: a ledger row per (appointment, recipient, channel) means re-running the job never double-sends, while a channel that failed is retried the next day.
Week-offs, leave and holidays — three deliberately different things:
The week-off allowance is computed, never stored. A month is not four Sun–Sat weeks: it is split into rows that each end on a Saturday, and a stub row of three days or fewer at either end merges into its neighbour. August 2026 yields 4 rows, September 2026 yields 5. Only one week-off is allowed per row, so the allowance cannot be spent faster than it accrues. The bands down the left of the calendar are those real rows, so the number on screen is the number the server enforces.
Team chat — two kinds, both realtime and both staff-only:
The floating composer on the schedule board carries a recipient picker, so a counsellor between sessions can fire a private line to reception without leaving the board. It also keeps Quick Book and voice dictation (the browser's built-in SpeechRecognition — no external service, hidden where unsupported).
A direct message rings the recipient's bell and badges the Team nav item. Privacy holds against admins too: a thread is readable only by its two participants, enforced in row-level security rather than in the UI. Clients can never appear at either end.
Roles
| Role | Sees |
|---|---|
| admin (a flag) | Everything: every lane, all clients, payments, roles |
counsellor | The shared board; starts/ends only their own sessions; their own session notes |
support | The booking desk: clients, bookings, counsellors, availability, payments — but no session notes and no session timers |
client | Read-only view of their own sessions |
Admin is a flag rather than a role, so one person can run sessions as a counsellor and administer the practice.
Clinical notes are separated by design. Reception has to read
appointment rows to run the diary, and row-level security cannot hide a
single column — so session notes live in their own session_notes table
whose policy admits only the treating counsellor and admins. Support sees
the booking notes from the call; never the case notes.
Counsellors are added by the practice, not by self-service. Support or an admin creates them with a specialism set, the languages they work in, a fee and a session length, and hands over a temporary password. Their working hours are then fed in under Availability, which is what makes them appear in the desk's slot search.
Clients are records first: staff create them with a name, age, contact details, preferred language and what they are calling about. A client only gets a login if they sign in with the same email or phone, at which point their account links automatically — and even then it is read-only.
Create a project, then in SQL Editor run:
supabase/migrations/0001_init.sql — schema, row-level security, triggerssupabase/seed.sql — optional demo data (5 counsellors, clients, a day of
sessions, and one session exactly 3 days out so the cron has something to send)Authentication → Sign In / Providers:
Google sign-in is off by default. The button is hidden unless you set
NEXT_PUBLIC_ENABLE_GOOGLE_AUTH=true, because an unconfigured provider
gives users a button that always fails. To turn it on: create a Google
Cloud OAuth client whose redirect URI is
https://<project>.supabase.co/auth/v1/callback, paste the client ID and
secret into Authentication → Providers → Google, then set that
environment variable.
In Authentication → URL Configuration, add your site URL and
https://your-app.vercel.app/auth/callback as a redirect URL.
cp .env.example .env.local
Fill in the Supabase URL and keys. Everything else is optional — reminders
degrade cleanly, recording a skipped delivery rather than failing, when
Resend or Twilio are not configured.
npm install
npm run dev
The first account to sign up becomes a counsellor with admin rights. It gets its own lane on the schedule and can manage everyone else. Later sign-ups choose Counsellor or Client on the form and are never admins; an existing admin grants that from Settings → People, where the Admin checkbox is independent of role — so a counsellor can be an admin too.
Signing in with the demo seed:
| Password | ||
|---|---|---|
[email protected] | nurora1234 | counsellor with admin rights |
[email protected] | nurora1234 | counsellor |
[email protected] | nurora1234 | counsellor |
[email protected] | nurora1234 | counsellor |
[email protected] | nurora1234 | counsellor |
[email protected] | nurora1234 | booking desk (support role) |
Sign in as [email protected] to see the desk exactly as reception does:
no timesheet, no session notes, disabled Start buttons, but full control of
bookings, clients, counsellors and availability.
Push to GitHub, import into Vercel, add the same environment variables, deploy.
vercel.json registers the cron:
{ "crons": [{ "path": "/api/cron/reminders", "schedule": "0 3 * * *" }] }
That is 03:00 UTC — 08:30 IST. Set CRON_SECRET in Vercel and the endpoint
rejects anything without a matching bearer token.
npm run typecheck # tsc --noEmit
npm run build # production build
npm run test:logic # timezone, slot and reminder arithmetic (no services needed)
npm run test:e2e # full browser walkthrough against a local Supabase stack
npm run test:signup # first-account bootstrap: counsellor + admin, on an empty DB
npm run test:desk # the booking desk, driven as reception: lookup → capture → match → book
npm run test:messaging # WhatsApp-on-booking + the team channel and private threads
npm run test:rules # the MUST MATCH business rules (no database, no services)
npm run test:leave # week-off allowance, one-per-week, leave, holidays, permissions
test:e2e needs Docker and the local stack (npx supabase start). It checks
sign-up validation, rejects a wrong password, signs in properly, then checks
in, starts a session, watches the timer tick, ends it, and confirms the tracked
minutes reached the invoice. It resets the database first, since the
walkthrough completes a session. Screenshots of every step land in
screenshots/.
test:signup empties the database and signs up through the UI, asserting the
first account really is a counsellor with is_admin set, lands on the
schedule, gets a default working week, and that a second sign-up is not
made an admin.
test:desk signs in as reception and books a session end to end, then checks
what reached the database: the booking channel, the call notes, that the
matched counsellor genuinely holds the requested specialism, that an invoice
was raised, and that reception can read the booking notes but not the
session notes.
test:messaging books a session and asserts the WhatsApp confirmation was
attempted and written to the delivery ledger with a normalised destination
(locally Twilio is unset, so the expected status is skipped — what is being
checked is that the send path ran and was recorded rather than silently doing
nothing). It then sends a team message and a private one, confirms the
recipient receives it, and confirms a third counsellor cannot see it.
test:rules checks the week-off allowance against the two months the handoff
names as its acceptance case (August 2026 → 4, September 2026 → 5), then all 84
months from 2024–2030 for gapless tiling, no surviving stub rows and an
allowance that is always 4 or 5. It also covers the tiered advance formula and
the extension-block billing.
test:leave drives the allowance through the real UI: takes a week-off, is
refused a second one in the same week, fills the month, is refused a fifth,
then confirms leave can still be logged once the allowance is spent and that a
non-admin counsellor cannot set clinic holidays.
The logic checks cover DST transitions in both directions, month and year boundaries, partial-day blocks, and the case where a late-evening IST session belongs to a different UTC date than its local one.
Trigger the reminder job by hand:
curl -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/reminders
It returns { scanned, due, sent, failed, skipped }.
Double-booking is prevented in the database, not in application code — a
Postgres exclusion constraint over (counsellor_id, tstzrange(starts_at, ends_at))
for live statuses. Two simultaneous bookings for the same slot cannot both win.
Likewise, partial unique indexes enforce at most one running timer per
appointment and per counsellor, and one open shift per staff member.
Availability is stored as local wall time (weekday + time) in the
counsellor's timezone, and converted to real instants at read time via Intl.
Storing UTC instants instead would silently shift working hours across DST.
Row-level security is the authorisation boundary. Clients cannot read the
team channel or another client's sessions even if the UI were bypassed;
is_staff() and is_admin() are SECURITY DEFINER so policies can consult
profiles without recursing through its own policy.