MyMusicStaff group-lesson makeups: the manual workaround a January 2026 review documented
Sonja N.'s 3-star review names the exact step-by-step where group makeups break. The architectural reason — and what a sane data model looks like.
A 3-star Capterra review of MyMusicStaff posted in January 2026, by a teacher who signs as Sonja N., describes the group-lesson makeup flow in five words:
"It was clunky at best."
The fuller passage in her review names the specific failure mode: her studio runs unlimited make-ups, and the group-lesson cohort structure didn't survive contact with that policy. She had to spend a bunch of time helping parents navigate the rescheduling process by hand.
I want to take that apart. Why would group makeups be clunky in a tool that handles 1:1 makeups well? It's not a UI bug — it's a data-model consequence — and the reasoning is one I had to work through myself when I added group support to Segnoly. This post is the architectural close-reading, plus an honest accounting of where Segnoly's group-lesson handling stands today.
What "clunky" probably means in a group-lesson schema
To understand what's happening behind Sonja N.'s five words, you have to ask one question: in the studio-management tool, what is a group lesson?
There are two possible answers, and they have radically different consequences when a student needs a makeup.
Answer 1: a group lesson is a slot with multiple students attached. The slot exists once. Wednesday at 4pm, Studio Room B, three students enrolled. Each student is a row pointing at the same slot. When you cancel the slot, all three students get a cancel event. When one student needs a makeup, the makeup is a new slot, attached only to that student, on a different day.
Answer 2: a group lesson is N parallel 1:1 lessons that happen to share a time. Wednesday at 4pm, three rows in the lessons table, one per student, each with the same start time, each scheduled independently. There's a soft convention that they're "the same group" — maybe a shared cohort name in a metadata field — but at the schema level they're three independent lessons.
If you've never built one of these systems, Answer 2 looks like the obvious shortcut. You already have a 1:1 lessons table; group lessons reuse it. Done. But the consequences when a student needs a makeup are exactly what Sonja N. is describing.
In Answer 2:
- A group cancel is N individual cancels. If three students are enrolled and the teacher gets sick, you cancel three rows. If one of those rows is already in a different state — say, one student had pre-emptively marked himself as not coming — you get inconsistent state across the cohort.
- A makeup is a new individual lesson, but with no group context. When the makeup slot fires, it has no link back to the group it's compensating for. Reports treat it as a separate 1:1. The teacher, in real life, may have moved that student into a different group's session for the makeup — but the schema can't represent that, so you end up with a 1:1 row that's actually a group attendance, mis-categorized in every report it touches.
- Unlimited makeups multiply the manual work by N. Sonja N.'s studio runs unlimited make-ups. Every time a student misses a session, the teacher has to find an open slot in another group, manually attach the student to it (often via a workaround like creating a 1:1 lesson at the group's time), and then reconcile the billing. With three or four students in a typical group and a busy studio, this is the difference between an unmaintainable Tuesday and a normal one.
In Answer 1, by contrast, the slot is a first-class entity. Cancelling it cancels everyone in one operation. Adding a student to another group's slot for a makeup is a single attach operation. The makeup is recorded against both the original slot (as a missed-and-compensated event) and the destination slot (as a guest attendance). The teacher does one thing per event, not N.
My read of the MyMusicStaff schema, based on what I see surface in their reviews and what their UI exposes, is that they're closer to Answer 2 than Answer 1. The group-lesson-with-unlimited-makeups case is the worst case for that architecture, which is why Sonja N.'s studio in particular ran into it. The "clunky at best" experience is the schema's worst case meeting her studio's policy.
Where Segnoly stands today, honestly
I want to be straight about where Segnoly is on this, because if you're a studio that runs group lessons and you read this and assume Segnoly has every box ticked, you'll be disappointed.
Segnoly's lessons table has a groupId column (db/schema.ts:lessons.groupId). Lessons that share a groupId are treated as the same group session by the calendar, the conflict checker (lib/scheduling.ts:findConflicts), and the email-reminder logic. That puts Segnoly in a hybrid position: closer to Answer 1 than Answer 2, but not all the way there.
What works today:
- A group cancel is one operation. Setting the parent slot to
cancelledcascades the status change to every lesson row that shares thegroupId. The teacher cancels once. - The conflict checker treats the group as one block. When a student in the group needs to be moved to a 1:1 makeup elsewhere in the week, the scheduler doesn't false-positive on "this conflicts with your other group lesson at the same time" because the
groupIdfilter excludes it. - The notes and per-student status are independent. One student in a four-student group can be marked
attendedwhile another is markedno_show, with different notes on each row. That part of the model already does what teachers need.
What does not yet work, and what I'm being honest about:
- There is no first-class "slot" entity yet. A group is a soft join across rows that share a
groupId. That works for the 80% case but breaks down for the case Sonja N. describes — guesting a student into another group's session for a makeup. To model that today in Segnoly you'd create a 1:1 lesson at the destination time, which has the same misclassification problem I just described in MyMusicStaff. The fix is on the roadmap (agroupSessionstable that owns the slot, withlessonsrows attached as enrollments), but it's not shipped. If you run unlimited group makeups today and that exact flow is your daily reality, Segnoly's current group support won't be a clean win for you. - Group-lesson billing has a hand-edited path. Per-student rate overrides exist (
db/schema.ts:studentRates), so each student in a group can have a different price. But the case where a guest student joins one session as a makeup and shouldn't be charged is a manualchargeable: falsetoggle on that lesson row. That's the right knob, but the UI surfaces it as a checkbox the teacher has to remember. - Reports treat groups as the sum of their member rows, not as one event. The end-of-month report counts five member-rows as five lessons, not one group session with five attendees. That's correct for billing, mostly wrong for capacity planning.
If you're looking at Segnoly and Sonja N.'s review describes your studio's exact problem, the honest answer is: Segnoly today is meaningfully better than MyMusicStaff on group cancels and conflict-checking, and meaningfully worse than what Segnoly itself wants to be in six months on the slot-as-entity model. I'm not going to oversell that.
What the right model looks like, when it ships
The change on Segnoly's roadmap — and the reason groupId is a column rather than a separate table today — is to introduce a groupSessions table that owns the meeting (date, room, capacity, lesson type) and treat individual lessons rows as enrollments in that session. That's Answer 1 in full.
When that ships, the operations Sonja N. is describing become single-step:
- Guesting a student into another session as a makeup. Today: create a 1:1, mark not-chargeable, hand-edit. After: one button on the destination session that adds the student as a guest enrollment, with a foreign key back to the missed session it compensates for.
- Capacity-aware reporting. Today: groups count as the sum of enrollments. After: a session is one event with N attendances, and the report shows utilization as enrolled-of-capacity.
- Late-cancel charges that respect group policy. Today: each student in a group has their own late-cancel charge or not, depending on the per-row toggle. After: the policy fires on the session, and per-student exceptions are explicit.
The reason I'm laying this out in a public post and not in a roadmap doc is so that if you're shopping right now, you can make an honest comparison. MyMusicStaff is shipping today and the group-makeup case is, by Sonja N.'s account, painful. Segnoly is shipping today and the group-makeup cancel case is clean while the guest into another session case is a rough edge. Different rough edges, different tradeoffs, both visible.
What this means if you're shopping
The fifteen-second test that surfaces the underlying model in any group-lesson tool: open the calendar, create a group lesson with three students, then try to cancel it. If the cancel happens once and clears all three rows, the tool is closer to a session-first model. If you have to mark each student individually, or if the cancel fires three separate parent emails (one per student, all looking like 1:1 cancellations), the tool is the parallel-1:1 model — and the unlimited-makeups case Sonja N. ran into is your worst case waiting to happen.
Then run the second test: cancel a single student out of the three, and try to schedule that student into next week's group session as a guest. If the tool models guest-attendance as a first-class concept, you'll see a "guest" or "drop-in" flag. If it doesn't, you'll either be told it's not supported or be funneled into creating a separate 1:1.
Segnoly passes the first test today. Segnoly partially passes the second — the cascade is clean, but guesting still requires the manual workaround I described. MyMusicStaff, per Sonja N.'s January 2026 review, fails the first.
The architecture difference is invisible in marketing copy. It surfaces every Wednesday at 4pm.
Building Segnoly — billing and automation for independent music teachers. The roadmap above is the actual roadmap, the groupId column is real, and the waitlist is open for the first cohort.