MyMusicStaff's lesson notes are linked to attendance — and the design choice loses you teaching context
A close reading of one Sarah R. Capterra review and the architectural reason MyMusicStaff's notes feel clunky. Why Segnoly stores notes separately from status, with examples.
In October 2025, a piano teacher posted a Capterra review of MyMusicStaff under the name Sarah R. that I keep coming back to. It's nine words long and it describes a design mistake that took me a year of building Segnoly to fully understand:
"Lesson Notes tool is linked to attendance record and is very weak, clunky, unintuitive."
I want to take that sentence apart, because the words "linked to attendance record" are doing more work than they look. They aren't a complaint about a UI button being in the wrong place. They're a complaint about a data model. And the data model is what makes the experience clunky for everyone who has ever tried to write a real teaching note inside MyMusicStaff.
This post is a close reading of the architectural choice underneath Sarah R.'s nine words, why it shows up as friction every single lesson, and the choice Segnoly made instead — which lives in db/schema.ts, on the lessons table, in roughly fifteen lines of code.
What "linked to attendance record" actually means
The data model that Sarah R. is describing — and the model that almost every legacy studio-management product ships — treats a lesson note as a property of a specific attendance event. You mark the student as attended and a notes field appears, attached to that attendance row. You mark the student as no-show and… well, what happens then is the question.
In a "linked" model, one of three things happens, and none of them are good.
Option A: the note field disappears entirely on a no-show. This is the simplest implementation and the one I see most often in legacy tools. The reasoning is that "no-show" means there's no lesson to take notes on. The reality is that no-show is when notes are most important. "Second consecutive no-show. Called Dad — said the car broke down and they're shopping for a replacement this week. Don't push on Friday's slot, push on next Tuesday's series." Without a place for that note, the studio's institutional memory of the family evaporates the second the attendance toggle moves.
Option B: the note field exists but is scoped to the attendance status. Change the status from attended to no-show and the note that was there before vanishes (or worse, ends up orphaned in the database). This is the model where teachers learn, painfully, never to change a status after writing a note. Which is the same as saying: the software has trained the teacher to lie about the attendance record because the alternative is losing their notes.
Option C: the field stays, but its semantics are unclear. What does a note attached to a no-show event mean? Is it about why the student didn't come, or about what was supposed to happen? The interface gives no signal, so the teacher invents one — and three months later, the note reads "Bach, page 14" and nobody can remember whether the student actually played it.
I don't know which of these three Sarah R. is describing in her studio. I do know that all three flow from the same root cause: somewhere early in MyMusicStaff's history, a developer wrote a schema where note was a child of attendance, instead of note and attendance both being children of lesson. That decision is invisible from the outside, but it surfaces every single lesson.
The "very weak, clunky, unintuitive" experience Sarah R. describes isn't a UI bug. It's that bug surfacing in the only place it can — at the touchpoint where a teacher has thirty seconds between students and needs to write down what just happened.
What a teaching note actually has to survive
When I was reading my way through 600 Piano World, Violinist.com, and Mumsnet threads before I wrote the first line of Segnoly, the most consistent pattern in how teachers describe their own notes was this: a note is a story about a student that spans status changes.
Real notes from real teachers, paraphrased from forum posts and design-partner interviews:
- "He was here but barely — pulled an all-nighter on a school project, played through the Mendelssohn anyway, marked attended, but flag this so I don't repeat the same hard piece next week."
- "She didn't come; her mother emailed at 3pm to cancel for strep throat. This is the third Wednesday in a row. I want the cancel record AND the pattern note so we can talk to Dad at the end of the term."
- "Marked attended in the moment, but on review I should have marked late-cancel — the parent pulled into the lot, called from the car, and we never started. Need to change the status, but DON'T lose what I already wrote about the conversation."
In every one of these, the note has to exist independently of whatever the teacher decides about status. The first scenario is attended with a note that anchors next week's plan. The second is no-show with a note that anchors the term-end conversation. The third is the failure mode of the linked model: the teacher needs to fix the status, and in a tool where notes are scoped to status, fixing the status nukes the most important paragraph she's written all week.
A correct model has notes and status as siblings, not parent-and-child. The note is about the lesson. The status is also about the lesson. They both update independently, they both survive each other's changes, and the teacher's job is to be honest about the status without paying a tax on her teaching record.
How Segnoly's lessons table is laid out
Here's the relevant slice of db/schema.ts in Segnoly. I'm keeping it short because the point is not the syntax, it's the topology:
export const lessons = sqliteTable("lessons", {
id: text("id").primaryKey(),
studentId: text("student_id").notNull(),
startUtc: text("start_utc").notNull(),
endUtc: text("end_utc").notNull(),
status: text("status").notNull().default("scheduled"),
// scheduled | attended | late_cancel | no_show | makeup | cancelled
notes: text("notes"),
// ... priceCents, groupId, seriesId, etc.
});
Two specific design choices are visible here.
The notes column is on the lesson row, not on a separate attendance table. There is no separate "attendance event" entity in Segnoly. Attendance is a status enum on the lesson itself. A lesson exists from the moment it's scheduled — the row is created when the teacher (or the recurrence engine in lib/recurrence.ts) generates it — and it carries the note from the moment the teacher writes one, regardless of what status it's in.
The status enum has six values, not two. A common architectural shortcut is attended: boolean. That field is a boolean because the developer was thinking about attendance as binary. The result is that late-cancel, no-show, cancelled, and makeup all collapse into "not attended," and the only signal the teacher has to distinguish them is whatever they manage to type into a notes field that's also scoped to the same boolean. Segnoly's six-state enum forces the model to recognize that late-cancel and no-show are different events with different downstream consequences (different charge defaults, different reminder triggers, different reports).
The combination matters. A teacher can mark a lesson no_show and write "Mom emailed at 3pm — strep, will pay for the missed lesson per policy, schedule the makeup for next week" in the same row. Six weeks later, when she's reviewing the term, she pulls the student's lesson list and the no-show row carries both the status and the prose — exactly the way her institutional memory of that family runs. If she later realizes the cancel came in 28 hours ahead of time and updates the status from no_show to late_cancel, the note doesn't move and doesn't disappear.
What the single-lesson modal actually does
The settings tab to edit a single lesson lives in app/(app)/schedule/page.tsx (the modal is rendered by the calendar grid component). The form has six fields visible to the teacher:
- Date and time
- Lesson type (and so price, indirectly)
- Status (the six-value enum)
- Notes (free-text, optional)
- A toggle for whether the lesson is chargeable
- A makeup-credit toggle, if relevant
Crucially, those six fields are independent inputs that all post to the same row update. The teacher can change one without touching the others. There is no UI sequencing where "you must mark attended before you can write a note," because there is no schema sequencing. The modal mirrors the data model. The data model mirrors what teachers actually need to do at 7:55pm on a Tuesday between students.
The other thing the modal does that I want to call out: the notes field is the biggest control on the form. It's not buried under an "advanced" toggle. The teacher's most valuable output — the paragraph that names the student's specific situation this week — is the part of the UI that gets the most pixels. Everything else is one line.
Why the linked model survives in legacy products
A reasonable question is: if the linked model is so bad, why did MyMusicStaff (and the rest of the category) end up there? My read, after looking at how older studio-management products are built and talking to teachers who used the early-2010s versions of these tools, is that it comes from a specific assumption about teacher workflow that doesn't match how teaching actually goes.
The assumption is: teachers write notes during or right after a successful lesson, and only then. If you start with that assumption, scoping notes to attendance is natural. The "no-show + note" case is rare, the "late-cancel + note" case is rare, and the "I was wrong about the status" case is something you handle by retyping.
The assumption is wrong. Notes get written about every lesson event, not just attended ones, and the most important notes — the ones that change how the studio handles a family three months out — are disproportionately about the not-attended events. Teachers don't write a paragraph about a normal Tuesday; they write a paragraph when something is off. Off, by definition, often correlates with something other than attended.
Sarah R.'s nine-word review is the field-evidence verdict on that assumption. "Linked to attendance record" names the architecture. "Very weak, clunky, unintuitive" names what it feels like every Tuesday at 7:55pm.
What this means if you're shopping
If you're evaluating a studio-management tool, here's a fifteen-second test that surfaces this issue without you having to read the schema. Open the lesson editor, mark a lesson as no-show, then look for the notes field. If it disappears, the tool is in Option A. If it appears but is labeled "absence reason" or similar, the tool is in Option C. If you write a note, change the status to attended, and the note vanishes, the tool is in Option B.
Segnoly fails that test in the right way: the notes field is identical in every status, the prose persists across status changes, and the teacher's writing belongs to the lesson rather than to her decision about whether the student showed up. You can build a billing system on top of either model. You cannot build a teaching record on top of the linked one without paying the tax that Sarah R. is paying.
The code that decouples these two concerns is fifteen lines on db/schema.ts:lessons. It is the cheapest fifteen lines I have ever written, and it is the reason I am writing this post and not a defensive one.
Building Segnoly — billing and automation for independent music teachers. The schema choices in this post are how the software actually works, and the waitlist is open for the first cohort.