Multi-tenant B2B SaaS for dance school management. Each school is a tenant; owners and teachers manage classes, students, enrollments, payments, and partner matching from a single admin portal.
- Live app (WIP): https://app.aquisebaila.ch (free hosting with warm-up time on render, no test data available)
- API: https://api.aquisebaila.ch
The current product (Phase 1) is an admin portal for dance schools:
- School & member management — owners create a school, invite teachers, configure pricing plans
- Course lifecycle —
DRAFT → OPEN → RUNNING → FINISHED, derived from publish/start/end dates - Enrollment workflow — covers
PENDING_PAYMENT,PENDING_APPROVAL,CONFIRMED,WAITLISTED,REJECTED - Capacity & role balancing — solo courses use simple capacity; partner courses (Salsa, Bachata, …) track lead/follow distribution with FIFO waitlisting when imbalance exceeds a threshold
- Level-gated approval —
INTERMEDIATE+courses require owner approval when a student's recorded dance level is missing or too low - Manual payment tracking — owners mark payments received; Stripe integration is architected behind a single seam for later activation
See docs/GLOSSARY.md for the ubiquitous language and docs/TESTING_WORKFLOWS.md for end-to-end business scenarios.
| Layer | Stack |
|---|---|
| Frontend | Angular 21 (standalone components, signals), Angular Material, SCSS design tokens |
| Backend | Spring Boot 3.5 (Java 21), Spring Security, Spring Data JPA, Liquibase, H2 (dev) |
| API docs | SpringDoc OpenAPI / Swagger UI |
| Auth (dev) | Form login + session cookie; in-memory users seeded on startup |
| Auth (prod) | Firebase JWT (Google sign-in), stateless OAuth2 resource server |
| Testing | JUnit + MockMvc integration tests, Vitest + Playwright on the frontend, Testcontainers (*IT.java) for external services |
| CI | GitHub Actions — backend mvn verify, frontend npm test + ng build on every PR |
Monorepo with two independent builds — no Maven/npm coupling:
danceschool/
├── frontend/ Angular 21 SPA
├── backend/ Spring Boot REST API
├── docs/ Glossary, testing workflows, tech debt
└── .github/ CI, CodeQL, Dependabot
Multi-tenancy is the central design constraint. Every domain entity belongs to a School, and the backend enforces isolation mechanically:
- Repository methods take
schoolIdalongside any entity ID (e.g.findByIdAndSchoolId) - ArchUnit tests fail the build if a
@TenantScopedcontroller reaches an unscoped finder, skips@PreAuthorize, or talks to a repository directly - Every
@RestControlleris either@TenantScopedor on an explicit open-controller allowlist - Per-request
TenantContextFilterpopulates MDC with[schoolId=… userId=…]for all logging
Package-by-feature on the backend: each feature owns its Entity, Repository, Service, Controller, and DTOs. Shared infrastructure (shared/error, shared/logging, shared/security) is the only cross-cutting layer features may depend on.
Design tokens on the frontend: hardcoded spacing, colors, and typography are forbidden — all styles route through --ds-* and --mat-sys-* CSS variables defined in frontend/src/styles/.
- Phase 1 (now) — Admin portal for owners and teachers. Manage classes, students, enrollments, partner matching, manual payments.
- Phase 1.5 (pilot) — Public student-booking website. Students browse pilot schools and enroll with name/email/phone; no accounts.
- Phase 2 — Native student app (Android/iOS). Social login (Google, Apple), discovery, community events feed.
- Phase 3 — Online payments via Stripe (Mobile SDK + Apple/Google Pay), multi-tenant payouts via Stripe Connect.
Phase 1 deliberately makes simplifying assumptions (single school per user, OWNER == TEACHER, implicit school in /me URLs, no student login) that later phases will lift. Authorization is designed so these collapses can be widened without reshaping endpoints. Full details in .claude/rules/product-roadmap.md.
The project is built extensively with Claude Code. The workflow is codified in .claude/commands/ so every feature follows the same path:
- Design in Figma Make — quick interactive prototype of a screen or flow
- Promote to Figma components — consolidate primitives (Button, Chip, Form Field, …) and page compositions in the design file
- Write a PRD (
/write-a-prd) — a single GitHub issue capturing problem, solution, user stories, and design references (Figma links, not embedded screenshots) - Break into vertical-slice issues (
/prd-to-issues) — each issue is a tracer bullet through schema → API → UI → tests, marked HITL or AFK and linked as a sub-issue of the parent PRD - Implement (
/start-issue <N>) — automated lifecycle: worktree + branch, plan mode for non-trivial work, code + tests, visual verification, code review - Verify
- Visual: Playwright at 1440×900 against a real Angular dev server + real Spring Boot backend, screenshotting every affected page
- Design parity:
get_design_context+get_screenshotfrom Figma compared against the implementation - Code review: an automated
code-revieweragent reads the diff against project conventions, the originating issue, and the multi-tenant authz rules; returns Blockers / Suggestions / Nits
- Ship — commit, rebase, push, PR with summary + test plan, watch CI, squash-merge after green
- Deploy — automatic on Render via webhooks on
main
The full step-by-step lives in .claude/commands/start-issue.md.
- Dependabot — weekly version updates for npm (
frontend/), Maven (backend/), and GitHub Actions - CodeQL — code scanning configured in
.github/workflows/codeql.yml - Secret scanning — enabled at the repository level on GitHub
- CI gate — backend
mvn verify(Surefire + Failsafe, including Testcontainers) and frontendnpm test+ng buildmust pass before merge - ArchUnit authz tests — multi-tenant isolation and authorization rules are enforced at build time, not just at runtime
Backend (Java 21):
cd backend
./mvnw spring-boot:runRuns on http://localhost:8080. The H2 in-memory database resets on every restart; DevDataSeeder seeds two schools with separate owners.
Frontend (Node 22):
cd frontend
npm install
npx ng serveRuns on http://localhost:4200. The Angular dev server proxies /api to the backend via proxy.conf.json.
Dev credentials:
| User | School |
|---|---|
owner@test.com / password |
School 1 |
owner2@test.com / password |
School 2 |
Further reading:
CLAUDE.md— repo conventions and the issue workflowfrontend/CLAUDE.md— Angular conventions and design tokensbackend/src/CLAUDE.md— Spring Boot architecture and authz guardrailsdocs/GLOSSARY.md— domain languagedocs/TESTING_WORKFLOWS.md— manual end-to-end scenarios
MIT with Commons Clause — see LICENSE.
You can read, fork, modify, and contribute to the code freely. You may not sell the software or offer a paid product or service whose value derives substantially from it (including paid hosting or consulting around it). For commercial use, contact the author.