A comprehensive web-based system for creating, editing, managing, and versioning flashcards for yoga teacher study decks. Users can come to the site and see a "flash card of the day". They do not get to choose which flashcard they can see, the system picks a new one every day. Dont duplicate which flashcard is choosen as the flashcard of the day until all the cards have been used, then repeat.
Logged in users can see all flashcards.
-
Apps: - Make two apps:
- A "front-end" public accessible app. Users can sign up, edit their profile, password, and adjust daily email settings. Non-registered users can see most content, and cannot see a profile or daily email settings.
- A "back-end" admin and curator accessible app. (Admins and curators can log in and edit content and users)
-
User Roles: - Three levels of users:
- Admin (Full access, can CRUD everything including users and user permissions)
- Curator (CRUD all flash cards, and other content. Cannot edit users.)
- User (front-end access only, no admin app access.)
-
Sign up: - users can enter email and password (twice) to create new user. Email is used as the login identifier. After successful signup, users are automatically logged in and redirected to the home page.
-
Sign up with facebook or google: (planned, not implemented) The login and signup pages show disabled Google/Facebook buttons; no OAuth provider is wired up.
-
Admin and curator access - All admin and curator routes require authentication.
-
Flashcard management - Curators have all CRUD operations with versioning.
-
Version Control - All card edits create new versions while preserving history. Each edit creates a new version marked as "LIVE". Previous versions remain accessible and can be reverted to at any time. All versions of a card share a version_group UUID.
-
Image support - Front and back photos can be uploaded, edited and deleted for each card
-
Tagging system - Organize cards with flexible tags
-
Search and filtering - Find cards across all text fields
-
Version history - View complete edit history for each card with ability to revert to any previous version
-
CSV import - Bulk import cards from CSV files. A script is provided to import new or update existing cards in bulk.
-
Default photo (planned, not implemented) - A single .jpg or vector placeholder for cards with no image. Cards without an image currently render a CSS placeholder block.
-
Initial Data -
backend/flashcards/management/commands/data/flashcards.jsonseeds 19 cards:- The 8 limbs of yoga, title and sanscrit phrase, english definition, tagged as "8 Limbs"
- The 5 yamas, title and sanscrit phrase, english definition, and tagged as "Yamas".
- The 5 niyamas, title and sanscrit phrase, english definition, and tagged as "Niyamas".
- A "Yoga" overview card, tagged as "8 Limbs".
The legacy
initial_data.csvat the repo root is no longer read by the seeder; it is kept only as sample input forimport_cards.
- Backend: Django + Django REST Framework + MySQL
- Frontend: Vue 3 + Quasar Framework + Pinia
- Development: Docker Compose
- Production: Kubernetes + Helm
- Docker and Docker Compose
- Git
- Clone the repository:
git clone <repository-url>
cd yoga-flashcards- Start the development environment:
./start-dev.shAlternatively, start manually:
docker-compose up --build- Access the application:
- Frontend: http://localhost:9000
- Backend API: http://localhost:8000
- Django Admin: http://localhost:8000/admin
The setup script will automatically:
- Build Docker containers
- Set up the database
- Run migrations
- Create admin user
- Load initial flashcard data
- Email:
admin@example.com - Password:
admin123
The API follows REST principles with the following main endpoints:
GET /api/cards/- List cards (with pagination, search, filtering), all users, authenticated onlyGET /api/dailycard/- See the card of the day, all users, regardless of authenticated statusPOST /api/cards/- Create new card (Admin and curators only)GET /api/cards/{id}/- Get card details (any authenticated user)PUT /api/cards/{id}/- Update card (creates new version, marks it as live) (admin and curator only)DELETE /api/cards/{id}/- Delete card, permanently (admin and curator only)GET /api/cards/{id}/versions/- Get version history for a card (admin and curator only)POST /api/cards/{id}/revert_version/- Revert to previous version (creates new live version from selected version) (admin and curator only)GET /api/tags/- List tags (all users, no auth required)GET /api/health/- Health check for Kubernetes probes (no auth required)POST /api/tags/- Create tag (admin and curator only)PUT /api/tags/{id}/- Update tag (admin and curator only)DELETE /api/tags/{id}/- Delete tag (admin and curator only)
All data provided by the API is in JSON format. The API supports server-side pagination, search, and filtering for cards.
The flashcard versioning system works as follows:
- Version Groups: All versions of the same card share a unique
version_groupUUID - Live Version: Only one version per group is marked as
is_live=True- this is the current active version - Creating Versions: When a card is edited, a new copy is created with an incremented
version_numberand marked as live. The previous live version remains in the database butis_liveis set to False - Version History: All previous versions are preserved and can be viewed in the admin interface
- Reverting: Reverting to a previous version creates a new version (with the highest version number) that copies the content from the selected version and marks it as live
- Querying: By default, only live versions are returned in list queries. Version history can be accessed via the
/api/cards/{id}/versions/endpoint
POST /api/users/register/- Signup (email, password, password_confirm)POST /api/users/login/- Login (email and password)POST /api/users/logout/- LogoutGET /api/users/auth-status/- Check authentication statusGET|PUT /api/users/profile/- Read or update your own profile (names, email, daily email preference)POST /api/users/change-password/- Change your own password (current_password, new_password)DELETE /api/users/delete-account/- Delete your own account (soft delete; signs you out)GET /api/users/csrf/- Issue a CSRF token and set thecsrftokencookie (no auth required)
Admin only:
GET|POST /api/users/manage/- List or create usersPUT|PATCH|DELETE /api/users/manage/{id}/- Update or delete a userPOST /api/users/manage/{id}/toggle_active/- Activate or deactivate a userPOST /api/users/manage/{id}/restore/- Restore a soft-deleted accountGET /api/users/manage/?include_deleted=true- Include soft-deleted accounts in the listGET /api/users/manage/stats/- User counts for the admin dashboard
Note: The system uses email addresses as the primary login identifier. Users log in with their email address and password.
Login Process:
- User enters email and password on login page
- After successful authentication, user is redirected to home page (
/) - If user was redirected to login from a protected page, they return to that page after login
Signup Process:
- User enters email and password (twice for confirmation) on signup page
- After successful account creation, user is automatically logged in
- User is redirected to home page (
/) and can immediately access the application
Session Management:
- Uses Django session-based authentication (no JWT tokens)
- Sessions persist across browser sessions
- Automatic logout on session expiry
Import cards in bulk using the Django management command:
docker-compose exec backend python manage.py import_cards /path/to/cards.csvCSV format:
title,phrase,definition,tags
"Downward Dog","Adho Mukha Svanasana","A foundational pose","Asana,Sanskrit"title and definition are required; phrase and tags are optional. Separate multiple
tags with commas inside the single tags field.
Options:
--dry-run- Preview import without making changes--user username- Specify the creating user (default: admin) If the tag does not yet exist, it will be created. If the tag already exists, it will be added to the card.
- Responsive design with Quasar components
- Real-time search and filtering
- Image upload with preview
- Version history with revert functionality
- Tag management interface
- Session-based authentication
- Responsive design with Quasar components
- Login/Logout with Quasar components. After successful login, users are redirected to the home page.
- Signup asks users for password twice. After successful signup, users are automatically logged in and redirected to the home page.
- Flashcard of the day Displays today's flashcard (all visitors)
- Real-time search and filtering when logged in
- User favorites (planned, not implemented) - The
/favoritespage and the star buttons are placeholders; there is no favorites API yet, thoughUserProfile.favorite_cardsexists on the model. Card sharing (Web Share API / copy to clipboard) does work. - Edit user when logged in - name, email, password and the daily card email preference, plus account deletion.
- Session-based authentication
The Django backend uses:
- Thin views, fat models - Business logic in services
- DRF ModelViewSets - RESTful API endpoints
- Django migrations - Database schema management
- Factory Boy - Test data generation
- Pytest - Unit testing
The Vue 3 frontend uses:
- Composition API - Modern Vue 3 patterns
- Pinia - State management
- Quasar - UI components and build system
- Axios - HTTP client with interceptors
- Vue Router - Navigation with auth guards
Run backend tests:
docker-compose exec backend python -m pytest- Build and push Docker images:
# Backend
docker build -t your-registry/yoga-flashcards-backend:latest ./backend
docker push your-registry/yoga-flashcards-backend:latest
# Frontend
docker build -t your-registry/yoga-flashcards-frontend:latest ./frontend
docker push your-registry/yoga-flashcards-frontend:latest- Deploy with Helm:
helm install yoga-flashcards ./k8s/helm \
--set image.repository=your-registry/yoga-flashcards \
--set env.DJANGO_SECRET_KEY=your-production-secret \
--set database.password=your-db-passwordStatus: incomplete. k8s/helm/ currently contains only Chart.yaml and values.yaml.
There is no templates/ directory, so helm install creates no resources. values.yaml
also declares a mysql subchart that Chart.yaml does not list under dependencies, so it
is never fetched. The chart needs Deployment, Service and Ingress templates before this
section is usable.
Backend:
DEBUG- Enable debug mode (default: 0)DJANGO_SECRET_KEY- Django secret keyDATABASE_URL- Database connection stringCORS_ALLOWED_ORIGINS- Allowed CORS origins (comma separated)CSRF_TRUSTED_ORIGINS- Origins allowed to send unsafe requests. Falls back toCORS_ALLOWED_ORIGINSwhen unset.DJANGO_ALLOWED_HOSTS- Comma-separated hostnames. Defaults to*; set this in production.CSRF_COOKIE_SECURE/SESSION_COOKIE_SECURE- Set both to1in production (HTTPS).CSRF_COOKIE_SAMESITE/SESSION_COOKIE_SAMESITE- DefaultLax. Only a genuinely cross-site deployment needsNone, which also requires the Secure flags above.
Frontend:
API_BASE_URL- Backend API base URL, injected viabuild.envinquasar.config.js. Read at build time, not run time: a production image must be built with it set.
The application uses MySQL with proper UTF-8 support for international characters in Sanskrit terms.
-
Session-based authentication - No JWT tokens to manage
-
Role-based permissions -
IsCuratorOrAdminandIsAdminOnlygate the API by therolefield; user management is admin-only on every action -
CORS configuration - Properly configured for frontend
-
CSRF protection - Enforced on every authenticated API write. DRF views are
csrf_exempt, so the check comes fromSessionAuthentication.enforce_csrf()rather thanCsrfViewMiddleware; Django therefore never sets thecsrftokencookie for/api/by itself, andGET /api/users/csrf/exists to issue one. The frontend primes it automatically before its first unsafe request. Requests from an origin outsideCSRF_TRUSTED_ORIGINSare rejected even with a valid token. -
Accounts are soft deleted - Deleting a user disables the account and hides it, but removes nothing.
Flashcard.created_byusesPROTECT, so a user delete can never cascade into their card library.
Known gaps:
- Card deletes are permanent.
DELETE /api/cards/{id}/removes the row; there is no soft delete for cards, despite theis_activeflag existing on the model. - Login itself is not CSRF-protected. DRF only enforces CSRF once a session authenticates, and login is anonymous. This is standard DRF behaviour.
- Follow the coding conventions in
.github/copilot-instructions.md - Write tests for new features
- Use the provided Docker environment for development
- Ensure migrations are included for model changes
CODE:
- Helm chart templates (see Production Deployment above)
- Favorites API and wire up the
/favoritespage - Google / Facebook OAuth
- Default card placeholder image
- Soft delete for cards
CONTENT: By a human at later iterations
- Collect images
- Carefully create and edit new card content
- Hire designer to layout flashcards in adobe in-design
None at this time. This program is 100% closed source and proprietary. All rights reserved by the author.