MTtargiel.pro│case study
← back to work
Client case study

BNB Academy of Dance

Enrollment, Payments & Operations Platform

BNB Academy of Dance is a dance school in Kraków. I designed and built its production platform: the class catalogue and timetable, family enrollment, staff review and acceptance, monthly pass billing, online payments, and the admin panel the studio runs on day to day.

client
BNB Academy of Dance, Kraków
delivered by
Michał Targiel — architecture, domain model, implementation
in production
bnbacademyofdance.pl
stack
Next.js · TypeScript · Payload CMS · PostgreSQL · Przelewy24
Client DeliveryProduct EngineeringPaymentsBusiness WorkflowsVisit live website ↗

01 Problem

Enrolling in a dance academy is not a checkout. A family chooses classes for one or more people, but whether each of them gets a place depends on the group: its age range, whether it is recruiting, and — for tournament formations — the result of a casting. What each person then pays depends on how many sessions a week they end up attending across all their groups, with a discount for siblings.

The platform has to carry an application from the first visit to a paid monthly pass without losing track of who applied, who was accepted where, what each person owes, and what has actually been paid.

02 Context

The academy runs a season-based timetable of groups across styles, age bands and levels — from open classes to tournament formations entered through casting. One person may train in several groups; one household may enroll several people at once.

Fees are monthly passes priced by weekly frequency (1×, 2×, 3× a week, or OPEN), plus single entries. A family discount applies to eligible lower-priced monthly passes within the same household. Money arrives online through Przelewy24, by bank transfer, by BLIK, and in cash at the studio — and all of it has to land against the same charges.

03 Requirements

  • Browse classes and the timetable by age, style, level and instructor.
  • One application for a whole family, with classes and a pass chosen per person.
  • Applying is free and creates no financial obligation.
  • Eligibility — age for the season, recruitment status, invite-only groups — enforced by the server.
  • Staff decide per person and per class; overriding a rule is explicit and recorded.
  • One monthly fee per person, derived from their total weekly sessions.
  • Online and offline payments recorded against the same charges.
  • Groups, timetable, attendance, billing and the cash till run from one admin panel.

04 Enrollment lifecycle

Enrollment moves through explicit states, and money enters only at the end: a submitted application is a request for a place, the studio decides, and acceptance is what creates a fee and a payment link.

   Visitor
      │
   Class discovery        catalogue · timetable
      │
   Application            free · one per family
      │
   Server-side rules      age · recruitment · pass
      │
   BNB review             per person, per class
      │
   Acceptance             membership · pass · charge
      │
   Payment                pay link · online / offline
      │
   Billing state          monthly · per participant
Discovery — a filterable class catalogue and timetable, rendered from the same class, group and schedule records the studio manages in the panel.
Application — one free form per household; each chosen class becomes a separate selection awaiting a decision.
Server-side rules — season, age, recruitment policy and pass-to-frequency fit are checked again on the server; an invalid application is refused with a reason.
BNB review — staff accept or decline each selection. Age, casting and closed-recruitment blockers need an explicit override with a reason; only an admin can override a casting.
Acceptance — creates the membership, recalculates the person's pass, and issues the monthly charge.
Payment — one household e-mail with the confirmed fee and a secure pay link; Przelewy24 online, or transfer, BLIK and cash recorded by staff.
Billing — a daily job issues monthly charges; each charge’s status is derived from the payments recorded against it.

05 Key decisions

Applying is not paying

Submitting the form creates applications, not an order. The charge and the pay link are issued only when staff accept, so a family is never asked to pay for a place the studio has not confirmed, and a declined application needs no refund.

The server owns eligibility and price

The form runs the same shared rule functions for instant feedback, but the submission endpoint re-checks everything. Recruitment and invite-only status are read from group records, not from the request, and the price is computed from the server-side price list — the client sends a pass choice, never an amount.

Decisions per person and per class

Each chosen class is its own selection with its own status, and the application’s status is derived from them rather than set by hand. One family form can end with one child accepted into two groups and another waiting for a casting result.

A pass belongs to a person, not a group

The monthly fee is derived from the number of unique weekly sessions across all of a person’s groups. Someone in three once-a-week groups pays for a 3× pass, not three 1× passes; a technique session shared by several formations counts once.

A payment is applied once

A Przelewy24 notification is accepted only with a valid signature and the exact expected amount, then confirmed with the provider’s verify call using the server’s own amount. The order is claimed as paid by a conditional update inside a transaction, so a repeated notification changes nothing and a second payment is recorded as a duplicate, not applied twice.

A month is billed once

Monthly charges are created in one transaction per run, with unique indexes that make an overlapping run or a retry unable to bill the same month twice. Automatic repricing may only lower an unpaid charge; raising one is an explicit correction that staff confirm.

06 Trade-offs

Human acceptance over instant confirmation

Every application waits for a staff decision before any money is involved. That costs studio time and makes families wait, but placement depends on things a form cannot judge: level, group fit and casting results.

Warnings where people know better

Age and closed recruitment block an application. Schedule collisions only warn, and a group is marked full by staff rather than by a seat counter. These stay staff decisions — informed by the system, not taken by it.

No silent price increases

The system lowers an unpaid charge on its own but never raises one. Increases need a correction that staff acknowledge — more manual steps, in exchange for no family ever seeing a higher amount that nobody decided on.

Links instead of accounts

Parents do not create accounts. Payments go through single-purpose pay links sent by e-mail. There are fewer credentials to secure and nothing to sign up for, but families do not get a self-service portal.

07 Operations

The studio side is a custom admin panel built on Payload CMS, organised around the jobs the office actually does:

├─ Application review — accept or decline per selection, with a dry-run preview of the decision and its effect on the fee
├─ Groups, timetable, rooms and season rollover
├─ Attendance, including a PIN-protected view for instructors
├─ Billing grid, cash till and payment reminders
├─ Online payments queue and a charge-correction wizard
└─ Workshops, castings and studio rental bookings

08 Outcome

The platform runs the academy’s enrollment and billing in production at bnbacademyofdance.pl. In concrete terms:

├─ One path from class discovery to a paid monthly pass, recorded per participant
├─ No financial commitment until the studio has accepted the participant
├─ One fee rule — weekly frequency plus family discount — used both in the application summary and in monthly billing
└─ Online and offline payments reconciled against the same charges

Engineering verification — Unit, integration and end-to-end test suites; integration tests run against PostgreSQL, end-to-end tests against a mock payment provider.

Related: the DocAI architecture case study rests on the same principle in a different domain — a completed step is a proposal, and approval is a separate, recorded act.

← Selected workbnbacademyofdance.pl ↗Contact