A web application for managing musical ensembles built with Astro, Astro DB, and Bulma CSS.
- Site Admin: Can create ensembles and manage all users
- Ensemble Admin: Has full control over a specific ensemble (manage members, create rehearsals, track attendance)
- Regular User: Can join ensembles via invite codes, check in to rehearsals, view attendance
- Authentication: User registration, login, and session management
- Invite System: Ensembles are private and require invite codes to join
- Ensemble Management: Create and manage musical groups with images
- Voice Parts: Define and manage voice parts (e.g., soprano, alto, tenor, baritone, bass) for each ensemble
- Member Organization: Group members by their assigned voice parts
- Profile Pictures: Users can upload avatars to personalize their profiles
- Rehearsal Scheduling: Schedule rehearsals with date, time, and location
- Attendance Tracking: Multiple check-in methods for rehearsals:
- Manual check-in button
- QR code scanning for touch-free check-in
- Admin can manually mark attendance
- Member Management: Add/remove members, assign ensemble admin roles
- Role-based Access Control: Different permissions for site admins, ensemble admins, and members
- Profile Management: Users can edit their name, upload profile pictures, and select their voice part for each ensemble
- Responsive UI: Mobile-friendly interface using Bulma CSS
- Node.js (v18 or higher)
- pnpm (v10 or higher)
- Clone the repository:
git clone <repository-url>
cd tutti-belli- Install dependencies:
pnpm install- Set up environment variables:
cp .env.example .envEdit .env and add your Astro DB connection details:
ASTRO_DB_REMOTE_URL=your_database_url
ASTRO_DB_APP_TOKEN=your_app_token
- Start the development server:
pnpm devThe application will be available at http://localhost:4321/
ASTRO_DB_REMOTE_URL: The remote database URL for Astro DBASTRO_DB_APP_TOKEN: Authentication token for connecting to the remote Astro DB
On first run, the database is seeded with:
- Admin Account:
- Email: admin@example.com
- Password: admin123
- Test User:
- Email: test@example.com
- Password: test123
- Sample Ensemble: "Chamber Orchestra" with both users as members
- Voice Parts: Soprano, Alto, Tenor, Baritone, and Bass (pre-configured for the sample ensemble)
- Sample Invite Code: TEST1234 (for joining Chamber Orchestra)
- Upcoming Rehearsal: A test rehearsal for the next week
/
├── db/
│ ├── config.ts # Database schema definition
│ └── seed.ts # Database seeding script
├── src/
│ ├── layouts/
│ │ └── Layout.astro # Main layout with Bulma CSS
│ ├── lib/
│ │ ├── auth.ts # Authentication utilities
│ │ ├── session.ts # Session management
│ │ └── upload.ts # File upload utilities
│ ├── pages/
│ │ ├── index.astro # Home page
│ │ ├── login.astro # Login page
│ │ ├── register.astro # Registration page
│ │ ├── logout.astro # Logout handler
│ │ ├── profile.astro # User profile
│ │ ├── admin.astro # Site admin panel
│ │ ├── invite/
│ │ │ └── join.astro # Join ensemble with invite code
│ │ ├── checkin/
│ │ │ └── [code].astro # QR code check-in landing page
│ │ └── ensembles/
│ │ ├── index.astro # List of user's ensembles
│ │ └── [id]/
│ │ ├── astro # Ensemble detail page
│ │ ├── edit.astro # Edit ensemble (name, description, image)
│ │ ├── parts.astro # Manage voice parts (admin)
│ │ └── rehearsals/
│ │ ├── index.astro # Rehearsal list & scheduling
│ │ └── [rehearsalId].astro # Rehearsal detail & attendance
│ ├── middleware.ts # Authentication middleware
│ └── env.d.ts # TypeScript definitions
└── astro.config.mjs # Astro configuration
id: Primary keyemail: Unique email addresspasswordHash: Hashed passwordname: User's full nameavatarUrl: Optional profile picture (stored as base64 data URI)role: 'admin' or 'user'createdAt: Account creation timestamp
id: Primary keyname: Ensemble namedescription: Optional descriptionimageUrl: Optional ensemble image (stored as base64 data URI)createdBy: Reference to User who created itcreatedAt: Creation timestamp
id: Primary keyensembleId: Reference to EnsembleuserId: Reference to UserpartId: Optional reference to Part (voice part assignment)joinedAt: Timestamp when user joined
id: Primary keyensembleId: Reference to Ensemblename: Part name (e.g., "Soprano", "Alto", "Tenor")sortOrder: Numeric order for display (lower numbers first)createdAt: Creation timestampspecific role)joinedAt: Timestamp when user joined
id: Primary keyensembleId: Reference to Ensemblecode: Unique 8-character invite codecreatedBy: Reference to User who created the inviteexpiresAt: Optional expiration datecreatedAt: Creation timestamp
id: Primary keyensembleId: Reference to Ensembletitle: Rehearsal titledescription: Optional descriptionscheduledAt: Date and time of rehearsallocation: Optional locationcheckInCode: Unique code for QR check-increatedAt: Creation timestamp
id: Primary keyrehearsalId: Reference to RehearsaluserId: Reference to UsercheckedInAt: Timestamp of check-incheckedInMethod: 'qr', 'manual', or 'admin'
- Log in wiVoice Parts**:
- Click "Manage Parts" to define voice parts for your ensemble
- Add new parts (e.g., Soprano, Alto, Tenor, Baritone, Bass)
- Edit part names and sort order
- Delete parts (only if no members are assigned)
- Manage Invite Codes:
- Generate new invite codes to share with prospective members
- Delete old invite codes
- Manage Members:
- View all members grouped by their voice parts
- Promote members to ensemble admin
- Remove members from the ensemble 5
- Navigate to your ensemble from "My Ensembles"
- Manage Invite Codes:
- Generate new invite codes to share with prospective members
- Delete old invite codes
- Manage Members:
- View all members and their roles
- Promote members to ensemble admin
- Remove members from the ensemble
- Schedule Rehearsals:
- Create rehearsals with date, time, and location
- View upcoming and past rehearsals
- Track Attendance:
- Display QR code for members to scan at the door
- View who has checked in to each rehearsal
- Manually mark members present if needed
- View attendance statistics
- Register for an account
- Receive an invite code from your ensemble admin
- Click "Join with Invite Code" and enter the code
- Set Your Profile:
- Go to "Profile" to edit your name
- Upload a profile picture (max 2MB, square images recommended)
- Select your voice part for each ensemble you've joined
- View your ensemble's upcoming rehearsals
- Check in to rehearsals by:
- Clicking the "Check In Now" button
- Scanning the QR code displayed at the venue
- Or visiting the check-in URL
The system supports three ways for members to mark their attendance:
- QR Code Scanning: Admins can display a QR code that members scan with their phones to instantly check in
- Manual Check-In: Members can visit the rehearsal page and click "Check In Now"
- Admin Override: Ensemble admins can manually mark any member as present
All attendance records include timestamps and the method used for check-in.
pnpm dev # Start development server
pnpm build # Build for production
pnpm preview # Preview production build
pnpm check # Run TypeScript type checking
pnpm lint # Run linter and type check
pnpm fmt # Auto-fix linting issues- Framework: Astro v5
- Database: Astro DB
- CSS Framework: Bulma v1.0
- Icons: Font Awesome v6
- QR Codes: qrcode package
- Authentication: bcryptjs for password hashing
- SSR Adapter: @astrojs/node
- Linting: Oxlint for TypeScript files
- Passwords are hashed using bcrypt (10 rounds)
- Sessions are stored server-side with HTTP-only cookies
- Ensembles are private and require invite codes
- Check-in codes are unique per rehearsal
- CSRF protection should be added for production use
- Always use HTTPS in production
- Change the default admin password immediately
See docs/self-hosting.md for a full guide covering the required external services (Turso, Resend, Backblaze B2), environment variables, Docker setup, Fly.io deployment, and first-login setup.
AGPL V3 License. See LICENSE file for details.
Contributions are welcome! Please read the Contributing Guide to learn how to get set up, what to work on, and how to submit a pull request. By participating in this project, you agree to abide by the Code of Conduct.