Disclosure
Full disclosure: I currently intern at Perfai Security, the authorization and access control testing platform mentioned later in this article. This isn't a sponsored postβI genuinely built FlashDraft as a personal project, and because I work at Perfai, I naturally used it as part of my release process. If you think either the app or Perfai could be improved, I'd genuinely appreciate your honest feedback.
The Problem
AI coding tools make it possible to generate dashboards, databases, authentication flows, and API routes faster than ever.
But a working application is not automatically a secure application.
This becomes especially important when an app has multiple users, private data, ownership rules, and different permission levels. A user may be signed in correctly but still gain access to another user's information or perform actions they should not be allowed to perform.
I wanted to explore both sides of AI-assisted development: how quickly I could build a real multi-user application and how I could verify its authorization before calling it complete.
Using Claude Code, I built FlashDraft, a one-week fantasy soccer platform with league commissioners, members, site administrators, private draft boards, trades, rosters, and league-specific controls.
This article is less about the fantasy game itself and more about what I learned while building quickly with AI, defining permissions, and testing the deployed application for authorization problems.
The Project
FlashDraft is a short-format fantasy soccer application where users create leagues, draft players, manage rosters, and compete for one week.
The application has three main roles:
- Site administrators manage the overall platform.
- League commissioners manage the leagues they create.
- League members manage their own teams, lineups, trades, and private draft information.
These roles created the main technical challenge.
Authentication could confirm who a user was, but the application still needed to determine which leagues, teams, settings, and actions that user was authorized to access.
For example, a member should be able to edit their own lineup but not another member's lineup. A commissioner should be able to manage their own league but not a league created by someone else. A private draft board should remain private even from other members in the same league.
Those permission boundaries became one of the most important parts of the project.
Dashboard:
We can see the player list as well, along with their prices:
Tech Stack
FlashDraft was built using:
- Claude Code
- TypeScript
- Prisma ORM
- PostgreSQL
- Tailwind CSS
- Clerk Authentication
- Neon Database
- Vercel
Claude Code generated much of the application's foundation, including:
- Database models
- Dashboards
- API routes
- League workflows
- Authentication flows
Clerk handled authentication, while Prisma and Neon managed users, leagues, rosters, trades, draft selections, and league settings.
Testing the Authorization Model
Building an application that works is only half the challenge.
FlashDraft stores user accounts, league memberships, team ownership, private draft strategies, trades, lineups, and league settings. If authorization is implemented incorrectly, one user could potentially view or modify information belonging to someone else.
I began by testing the application manually with multiple accounts, roles, and leagues.
I checked whether:
- A member could access another member's team
- A member could edit another user's lineup
- A commissioner could manage a league they did not create
- A non-member could access a private league
- One user could view another user's private draft board
- A user could manipulate IDs inside requests
- Sensitive API responses exposed unnecessary data
- Admin and commissioner permissions remained separate
This type of testing is important because normal user flows only confirm that allowed actions work. Authorization testing also asks whether forbidden actions are properly blocked.
After completing the manual checks, I submitted the deployed application to Perfai Security.
Perfai tested the running application's authorization and access-control behavior. The goal was not simply to review whether the code looked correct. It was to validate whether users could access only the resources and actions they were permitted to use.
This mattered because authorization bugs often appear across the boundaries between users, roles, resources, and API endpoints.
No automated tool can guarantee that an application is completely secure. However, testing the deployed product can help identify access-control weaknesses that may be missed during rapid AI-assisted development.
Because I currently intern at Perfai Security, I naturally used it as part of my release process. Readers can view the demo or create an account using the links near the end of this article.
All I needed to do was submit my live link, and Perfai Security did the rest.
How I Built It with Claude Code
FlashDraft began as a detailed product prompt inside Claude Code.
I first defined the main roles, resources, and workflows. These included users, leagues, teams, rosters, drafts, trades, league settings, and private draft boards.
Claude Code then helped generate much of the application foundation, including:
- Database models
- Prisma relationships
- Authentication flows
- API routes
- Dashboards
- League workflows
- UI components
This dramatically reduced the time required to create boilerplate and connect the major parts of the application.
However, generating the structure was only the beginning.
I still needed to decide who owned each resource, which roles could perform each action, and where authorization needed to be enforced on the server.
AI was effective at producing code quickly, but it could not replace the product decisions behind the permission model.
A useful way to think about the process was:
The biggest lesson was that AI-generated code should be treated as a strong first draft, not automatically trusted as production-ready.
Authentication Is Not Authorization
One of the most important lessons from this project was the difference between authentication and authorization.
Authentication answers: Who is the user?
Authorization answers: What is that user allowed to do?
Clerk handled authentication by identifying signed-in users.
The application still needed server-side checks to confirm:
- Whether the user belonged to the requested league
- Whether the user owned the requested team
- Whether the user was the commissioner of that league
- Whether the user could edit a roster or lineup
- Whether the user could view a private draft board
- Whether the user could approve a trade
- Whether the requested resource belonged to another user
A route is not secure simply because it checks that someone is logged in.
Every sensitive request must also verify that the authenticated user has permission to access the specific resource or action.
What I Learned
By the end of the project, FlashDraft included public and private leagues, live drafts, salary-cap roster building, trades, commissioner controls, private draft boards, persistent data, and a public deployment.
The more important result, however, was the development process.
Claude Code made it possible to move from an idea to a functional application extremely quickly. But speed did not remove the need to:
- Define roles before generating routes
- Decide who owns each resource
- Enforce permissions on the server
- Test with multiple accounts
- Attempt actions users should not be allowed to perform
- Review API responses for private-data exposure
- Test the deployed application rather than only local code
AI made building faster.
It did not make authorization automatic.
Lessons for Vibe Coders
The biggest lesson from FlashDraft is that a functioning interface can create a false sense of completion.
An application may look polished, authenticate users correctly, and support all its intended workflows while still containing serious authorization problems.
For anyone building with Claude Code or another AI coding tool, I would recommend:
- Define every user role before generating the application.
- List the resources each role can view, create, edit, or delete.
- Never rely on hidden buttons as a security control.
- Validate ownership and permissions on the server.
- Test the application with multiple users and multiple organizations or groups.
- Try changing IDs, URLs, and request values.
- Check whether API responses expose private information.
- Treat generated code as a first draft.
- Test the deployed application before release.
- Make security checks part of the normal build process.
AI-assisted development makes it easier to turn ideas into software.
The next challenge is making sure the software behaves correctly when users attempt actions they were never supposed to perform.
Try the Project and Security Tools
Play FlashDraft
Try the live application: https://worldcupfantasy-seven.vercel.app/
I would especially appreciate feedback on the gameplay, user experience, one-week league format, and any bugs you encounter.
Test Your Vibe-Coded App with Perfai Security
Join the Discussion
I would love to hear from other vibe coders and developers.
Leave your feedback in the comments. I will read every response and reply thoughtfully to each one.
Top comments (0)