Convex database rules
Is there any example of large scale use of these rules? Like, how do people manage it if they have hundreds of rules? Thanks for your input.
23 Replies
Thanks for posting in <#1088161997662724167>.
Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets.
- Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.)
- Use search.convex.dev to search Docs, Stack, and Discord all at once.
- Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI.
- Avoid tagging staff unless specifically instructed.
Thank you!
What kind of rules?
Like let's say I have like a lot of rules
And I don't want them to all be in one file
Currently I have:
Also I customized the ctx
Now TypeScript is yelling at me about the type of ctx.
I have no idea what type it is now!
Also to be honest I Haven't been able to get these rules to work.
I put some console.log stuff and I found that they don't do anything.
Crap, a lot of type errors.
They didn't mention this in the docs. Crap!
I have a call with the client tomorrow good thing he is oblivious to all these TS errors
Trying to use customization type
It's very complicated and I cannot find any documentation
But I know it's the path to customizing the ctx type in the query and mutation
yeah types can be hard when a lot of changes are being made
broadly relevant article in case it helps https://stack.convex.dev/authorization
Authorization Best Practices and Implementation Guide
Learn about authorization techniques and how to implemented them with practical examples.
(assuming you already have the articles/docs related to the custom function and rls stuff you're using there)
ok that's the only thing that told me what type to use
Unfortunately says nothing about what types to pass to customCtx function
Result in: 'customizedCtx' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
can you control click through and read the types, or hover and read jsdoc
export const authenticatedAction = customAction(action, customizedCtx);
'authenticatedAction' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
types:
Added:
Same error on customizedCtx and authenticatedAction.
This working:
Everything works but types all wrong
Type error on ctx here:
Here is how I have everything setup:
All of the logic works but TypeScript hates me.
I also often find the docs to be dated and the types they say to use no longer working.
It's very hard to "mouse over the type" when the type is a gigantic object with all these properties...
All of my types are messed up, nested object types are messed up now also.
Here is something that makes no sense
Oh I guess it's because it could be null
The issue was that I didn't want to repeat the code for everything but for example the db property doesn't exist in action
And the query uses a reader and the mutation uses a writer
ONce I inlined everything it fixed the issues
anyways row level security is sick I deleted like over 1,000 lines of dumbass repeated code
(It wasn't me, I let Claude run wild 🤣 )
Anyways I love this customization helper stuff
When you use it as intended it works great lol
I outclevered myself.
I just need to figure out why in TypeScript it says my modules don't exist sometimes in import
When they clearly do and I'm looking righ tat them (and they work at runtime)
Hello
So what is the best practice of Convex Row Level Security?
I assume it's a bad idea to like run database operations / queries inside of RLS rules?
And all of the metadata needed should be on like my user object?
Or is it okay to run queries and figure out access? I don't know how Convex queries work is what i realized
Like if I run the same query 16 times in one transaction will it cache the result or will it literally execute the query 16 times
Like should I create a class that caches the result of the permission check or store it in a secondary storage like Valkey?
Basically there are very complicated rules for access that involve organization, teams, etc
And many different related tables
It's cached after the first time for the remainder of the transaction
okay so is it a bad idea to do the queries in the RLS?
like if I do a .collect() on a query is that cached
cause i'm thinking like, for every row it's going to run that same .collect() over and over again
same query with same args is cached. If args change, it's not.
ok
so it's ok to do the queries in RLS then
like you can have super complex granular RLS?
basically each table is a file like addresses.ts and it has the rules. one thing i couldn't find....
What rule types are available?
you're going to have database interactions in your rls config, I don't know how else you'd accomplish anything
how granular is up to you
my golden rule of convex is try it and see
I'm using modifiy and read right now
so often you think something will hurt perf and it's actually fine
I don't know what else is available
I'm more worried about the usage billing more than anything tbh
I would defer to docs/stack articles on that
I don't want to bankrupt my client it's kinda my job
(what's available)
Yeah I couldn't find it
The one I found even had wrong / old keys...
it was like "canRead" for the key
And it changed lol
Also when I Try to use satisfies keyword I'm having issues getting it to accept the rules
I would say maybe the rules aren't doing anything but I know they are
So now I just need ot create like my declarative rule functions for the different rules I want to enforce on each thing.
And figure out what actual rules i can use...
The documentation for this kind of sucks not gonna lie
Like the examples are so simple it makes it seem like you can only have simple rules
Also need to figure out slots / intercepted route for NextJS
I want to use it for the page header cause some page have different header
I have so much to figure it out and I have 0 seconds
Have you used the Convex LLM stuff? Do you think it's better to just use like OpenAI or something?
I was trying to decide if I should just use the Convex AI stuff or if I should use a third party like Bedrock.
Anyways I'm going off the rails
I need to implement rules for 16 tables...
So back to rules, the on topic thing.
So I added to the context "ctx.user"
Sometimes authentication is optional
So should I create two queries like maybeAuthenticatedQuery and authenticatedQuery
Or should I just do like if (!ctx.user) throw new ConvexError()...
Eh just asking made me realize thats not so great cause then if I want to change that I have to change it on everything
So would I just throw in the customCtx()?
Or is there another place I would throw?
Like I'm not sure how to do this i guess
Okay I guess I can throw in customCtx i just tried it.
Guess my next question is.... should I throw in customCtx?
How can I reuse customCtx?
I tried to set it in a const and it didn't work
oh i guess I would just reuse the actual function not the part with customCtx
yeah reusing it is painful with typescript...
I can't figure out how to use this function since it contains database writer, database reader, or no database.
*reuse
Hey all, quick question, does Convex have anything official regarding row level security? I didn't see anything in the docs, but I saw you all were talking about it.
Just pretend I pasted it in the correct order 😅
Yes I am inquiring about row level security and how do I reuse this TS function for an "authenticated context"
aka everytime i try to use generics they confuse me
I guess i need to make some kind of generic factory
The "const db" part is the tricky part that I'm unsure how to do
It has to be no db for action, dbreader for query, and dbwriter for mutation.
If I can check the type of "ctx.db" somehow....
I think I'm doing this wrong.
It just says T is any
Simpler approach also isn't working
This is what i have
But I hate that I'm basically copy and pasting this to action, mutation, and query.
The problem is when I try to create reusability my type for the context is typeof authenticatedQuery
And it basically creates a reciprocal loop on the type