Member Feedback Portal
Angular 19 and ASP.NET Core 8 feedback portal with admin approval, cookie auth, and live stats on Azure SQL.
بسم الله الرحمن الرحيم
The Member Feedback Portal was another one of the small full-stack projects I built to sharpen my dev skills for a role I was interviewing for. The premise: members submit feedback with a title, message, and rating. An admin reviews each submission and approves or rejects it. The frontend shows live stats on submissions that have made it through moderation.
The stack
Frontend: Angular 19 with standalone components, Bootstrap for layout, deployed on Firebase Hosting.
Backend: ASP.NET Core 8 with C#, exposing a small REST API for the CRUD operations and admin auth.
Database: Azure SQL, wired to the ASP.NET service through Azure App Service configuration.
Auth: cookie-based session auth for the admin panel. No user accounts on the public submission side, since the whole point was that anyone could submit without an account.
The public submission form is deliberately simple. Three fields, no captcha, no account. The admin dashboard is where the actual logic lives: pending queue, approve/reject controls, and a live stats panel that shows average rating, submission count, and approval ratio, all pulled fresh on load.
What broke
The three-provider setup meant the usual round of CORS pain. Firebase and Azure don't share a domain, so the ASP.NET API had to explicitly whitelist the frontend origin, and I had to configure the ASP.NET CORS middleware to allow credentials so the auth cookie would round-trip properly.
A 415 error had me chasing the wrong lead for an hour. I was convinced it was a serializer issue on the backend. It turned out to be a Content-Type header the frontend wasn't setting on the POST, so the ASP.NET model binder was refusing to parse the body. Small fix on the frontend once I traced it, but a good reminder to check the request headers before diving into the server.
Firebase's default MIME type config for JavaScript modules also needed tweaking so the built Angular bundle would actually load in the browser. That one's a Firebase-specific gotcha: the CLI generates a firebase.json that gets close but doesn't quite have the right hosting rewrites for Angular's standalone bundles.
The last thing I hit was caching. Newly-approved feedback wasn't showing up in the public stats until a hard reload. I added a small polling refetch on the stats endpoint so the UI updates without user intervention. Not the most elegant solution — SignalR or server-sent events would be cleaner — but polling was the fastest way to ship the fix.
Next steps
If I picked this up again I'd move the polling to SignalR so the stats update the moment an admin approves something, and I'd add rate limiting on the public submission endpoint. Right now nothing stops someone from firing a script at it and flooding the queue.
Try it at member-feedback--memberfeedback-2e570.us-central1.hosted.app.