Part 3 of my RFID system has got some cool features


Hello,
If you’re new here, maybe look at Part 1 and Part 2 first, context matters.
TL;DR — I built an RFID-based access system with NodeMCU + FastAPI. First it logged card taps. Then I added admin-only registration with JWT. And now?
Now… I made it feel like an actual admin panel.
Because if you’re building a secure system, shouldn’t the admin (aka me) have some controls too?
What I Wanted This Time
Make the system cleaner.
Make it smarter.
Make it admin-friendly.
Imagine you're halfway through adding a user and realize, you typed the wrong name. Or someone asks, “Hey, who’s inside right now?” and you have no way to tell.
Yes, I fixed that.
What I Added
1. /cancel_registration
— Abort Mission!
Sometimes I start registering someone and then…
“Oops. Wrong mobile number.”
“Wait, this user already exists.”
“Never mind. It was a test.”
Now I just hit:
POST /cancel_registration
Authorization: Bearer <token>
Cleared. Registration wiped. Clean state.
2. /users
— Who's In the System?
Want to quickly check all registered users?
GET /users
Authorization: Bearer <token>
Super useful for audits or when I want to flex the database in front of friends.
Also helps avoid duplicate entries.
3. /logs
— Who Scanned When?
Every scan (entry/exit) is logged. Now I can view them like this:
GET /logs
Authorization: Bearer <token>
And yes, it’s sorted with the latest ones first. Because nobody got time to scroll through old data first.
4. /get_current_users_logged_in
— Who’s Inside Right Now?
Okay, this one’s actually pretty cool. The challenging part.
Earlier, I just checked the logs for entries where is_active = true
.
But here’s the problem with that:
Let’s say the user logs in → In DB the person’s log would be changed to
is_active = true
Then later logs out → In DB the person’s log would be changed tois_active = false
But both entries still exist in the DB.
So if we just check for anyis_active = true
It gives wrong info
I needed something smarter.
Let’s imagine this table:
user_id | logging_time | is_active |
1 | 2025-08-01 10:00AM | true |
1 | 2025-08-01 05:00PM | false |
2 | 2025-08-01 11:00AM | true |
If I naively check for is_active = true
, user 1 would wrongly show as still logged in.
So here's how I fixed it:
Fetch the latest log entry per user
Check if that entry'sis_active = true
Only then consider them “inside”
→ Sample: access_logs
Table (Before Smart Filtering)
id | user_id | rfid_uid | is_active | logging_time |
1 | 1 | 123ABC | true | 2025-08-01 09:00:00 AM |
2 | 2 | 456DEF | true | 2025-08-01 09:05:00 AM |
3 | 1 | 123ABC | false | 2025-08-01 05:00:00 PM |
4 | 3 | 789GHI | true | 2025-08-01 06:30:00 PM |
→ Naive Approach (is_active = true
)
If we just query all logs with is_active = true
, this is what we get:
user_id | rfid_uid | is_active | logging_time |
1 | 123ABC | true | 2025-08-01 09:00:00 AM |
2 | 456DEF | true | 2025-08-01 09:05:00 AM |
3 | 789GHI | true | 2025-08-01 06:30:00 PM |
Wrong user_id = 1
actually logged out later.
We shouldn’t count them as inside.
→ Correct Approach: Only Check Latest Log Per User
Now let’s group by user_id
and pick only their latest log entry:
user_id | last_log_time | is_active |
1 | 2025-08-01 05:00:00 PM | false |
2 | 2025-08-01 09:05:00 AM | true |
3 | 2025-08-01 06:30:00 PM | true |
Now we filter only those with is_active = true
, and we get the actual logged-in users:
→ Final Output (Correctly Logged-In Users)
user_id | rfid_uid | name |
2 | 456DEF | Alice |
3 | 789GHI | Bob |
Here’s the SQL logic I used under the hood:
SELECT u.*
FROM users u
WHERE u.id IN (
SELECT a.user_id
FROM access_logs a
JOIN (
SELECT user_id, MAX(logging_time) AS latest_time
FROM access_logs
GROUP BY user_id
) latest
ON a.user_id = latest.user_id AND a.logging_time = latest.latest_time
WHERE a.is_active = TRUE
);
This gives me a list of users who most recently logged in and haven’t logged out yet.
Feels correct and real.
GitHub Link for the project: Click here
What the Admin Can Do Now
Login securely
Start a user registration
Cancel it midway
See all users
See all logs
Track live logged-in users
And guess what?
All of it is token-protected, No more random API hits, Admin-only club.
What I Learned
Subqueries in SQLAlchemy (finally feels like real backend dev)
Protecting routes cleanly with FastAPI’s
Depends()
Making endpoints usable, not just functional
Keeping admin happy (because that admin is me)
What’s Next (Part 4? )
May be
- A React-based dashboard for live view
Got Feedback?
Have a cool idea to improve this?
Wanna build your own version?
Or just wanna say hi?
Always happy to chat, brainstorm, or help others build cool stuff.
Subscribe to my newsletter
Read articles from Adithya n directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
