๐ ๐๐๐ถ๐น๐ ๐ ๐๐น๐ฎ๐๐ต๐ฐ๐ฎ๐ฟ๐ฑ ๐๐ฝ๐ฝ ๐๐ผ๐ฟ $๐ฑ/๐ ๐ผ๐ป๐๐ต
I wanted a way to study Japanese words on the go.
I had a huge Excel file of vocabulary. I needed an app to turn those rows into flashcards. I built a custom tool and deployed it to Azure for a low cost.
Now I study on the train or at the park.
How it works:
The app uses the SM-2 algorithm. This is the same logic used by Anki.
You rate your recall after each card:
- Easy: You remembered without effort.
- Good: You remembered correctly.
- Hard: You remembered with difficulty.
- Again: You forgot.
The algorithm pushes easy cards further into the future. It brings difficult cards back sooner. This ensures you only study what you need.
I added a 45-second timer per card. If the timer runs out, the app marks the card as "Again." This stops me from losing focus or switching tabs.
The Tech Stack:
- Frontend: Blazor WebAssembly (.NET 10)
- Backend: ASP.NET Core minimal API (.NET 10)
- Database: Azure SQL (Basic DTU tier)
- Hosting: Azure Static Web Apps and Azure App Service
The Cost Breakdown:
I wanted to keep costs low. I use these Azure services:
- Azure Static Web Apps: Free tier via GitHub Actions.
- Azure App Service: Free tier (F1) for the API.
- Azure SQL: ~$5/month for the Basic DTU tier.
I avoided the Serverless tier because the minimum billing was too high. The Basic tier is cheaper for light daily use.
Security and Setup:
I use Managed Identities for the database. This means I do not store SQL passwords in my code. This removes the risk of leaking credentials.
I also added Microsoft Entra ID for authentication. This protects the API from public access.
Key lessons learned:
- Use Bicep files to automate your infrastructure. I can spin up the entire stack with two commands.
- Avoid global authorization handlers in Blazor WASM. They can cause infinite login loops. Use page-level attributes instead.
- Excel imports save time. My app uses ClosedXML to parse files with three simple columns: Front, Back, and Notes.
The code is open source. You can build your own version.