Part 3 of my RFID system has got some cool features

Adithya nAdithya n
5 min read

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 any is_active = true
It gives wrong info

I needed something smarter.

Let’s imagine this table:

user_idlogging_timeis_active
12025-08-01 10:00AMtrue
12025-08-01 05:00PMfalse
22025-08-01 11:00AMtrue

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's is_active = true
Only then consider them “inside”

→ Sample: access_logs Table (Before Smart Filtering)

iduser_idrfid_uidis_activelogging_time
11123ABCtrue2025-08-01 09:00:00 AM
22456DEFtrue2025-08-01 09:05:00 AM
31123ABCfalse2025-08-01 05:00:00 PM
43789GHItrue2025-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_idrfid_uidis_activelogging_time
1123ABCtrue2025-08-01 09:00:00 AM
2456DEFtrue2025-08-01 09:05:00 AM
3789GHItrue2025-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_idlast_log_timeis_active
12025-08-01 05:00:00 PMfalse
22025-08-01 09:05:00 AMtrue
32025-08-01 06:30:00 PMtrue

Now we filter only those with is_active = true, and we get the actual logged-in users:

→ Final Output (Correctly Logged-In Users)

user_idrfid_uidname
2456DEFAlice
3789GHIBob

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?

👉 www.iadiee.xyz/#contact

Always happy to chat, brainstorm, or help others build cool stuff.

0
Subscribe to my newsletter

Read articles from Adithya n directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Adithya n
Adithya n