Skip to content

User Entity Schema#406

Open
artemdemo wants to merge 1 commit intomainfrom
users-and-auth
Open

User Entity Schema#406
artemdemo wants to merge 1 commit intomainfrom
users-and-auth

Conversation

@artemdemo
Copy link
Contributor

@artemdemo artemdemo commented Mar 11, 2026

Note

Description

This PR adds local User entity support to the dev server, replacing the previous behavior of proxying /User requests to production. The authenticated user is now automatically seeded into an in-memory user collection on startup, and a dedicated router handles User CRUD operations locally with production-compatible semantics. The validator is also refactored from a return-value pattern to throw-based errors for cleaner call sites.

Related Issue

None

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Other (please describe):

Changes Made

  • User entity local support: Database.load() now seeds a user collection pre-populated with the current authenticated user's info (email, name, role, etc.), eliminating the need to proxy /User calls to production
  • New entities-user-router.ts: Dedicated Express router for /User endpoints — GET by id or "me", PUT for "me" only, POST/DELETE/bulk as no-ops matching production behavior
  • Validator refactored to throw: Validator.validate() now throws EntityValidationError instead of returning a ValidationResponse object; all call sites and tests updated accordingly
  • Entity name normalization: Collection and schema lookups now normalize entity names to lowercase via normalizeName()
  • Bearer token middleware: Added global authorization check in main.ts requiring a Bearer token on all requests
  • Shared utils.ts: Extracted stripInternalFields and getNowISOTimestamp helpers into a shared dev-server/utils.ts module
  • File restructure: routes/entities.ts renamed to routes/entities/entities-router.ts; remoteProxy dependency removed from createEntityRoutes

Testing

  • I have tested these changes locally
  • I have added/updated tests as needed
  • All tests pass (npm test)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (if applicable)
  • My changes generate no new warnings
  • I have updated docs/ (AGENTS.md) if I made architectural changes

Additional Notes

The User entity is treated as a built-in collection with reserved fields (full_name, email). If an app defines a custom User entity schema containing these fields, loading will throw an error at startup to prevent conflicts. The POST /User endpoint silently returns a fake record (matching production behavior where direct user creation is not permitted).


🤖 Generated by Claude | 2026-03-18 12:45 UTC

@github-actions
Copy link
Contributor

github-actions bot commented Mar 11, 2026

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/cli@0.0.45-pr.406.b61b272

Prefer not to change any import paths? Install using npm alias so your code still imports base44:

npm i "base44@npm:@base44-preview/cli@0.0.45-pr.406.b61b272"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.0.45-pr.406.b61b272"
  }
}

Preview published to npm registry — try new features instantly!

@artemdemo artemdemo changed the title Users and Authorization Users Schema Mar 16, 2026
@artemdemo artemdemo force-pushed the users-and-auth branch 2 times, most recently from 11c2912 to f7b1fa4 Compare March 17, 2026 16:06
/** @public - called by Commander internally via command dispatch */
override action(
// biome-ignore lint/suspicious/noExplicitAny: must match Commander.js action() signature
// biome-ignore lint/suspicious/noConfusingVoidType: must match Commander.js action() signature
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to my PR, but started to fail for me.
Ignoring

const result = validator.validate({ name: "Alice" }, schema);

expect(result.hasError).toBe(false);
expect(() => validator.validate({ name: "Alice" }, schema)).not.toThrow();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validator is now throwing an error, instead of returning object that describes the error.
Updating tests to handle it.
Here and below.

);
if (requiredFieldsResponse.hasError) {
return requiredFieldsResponse;
throw new EntityValidationError(requiredFieldsResponse.error);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that it's more convenient to throw the error, rather than return an object that describes the error.
So I decided to refactor it a bit.

@base44 base44 deleted a comment from claude bot Mar 18, 2026
@base44 base44 deleted a comment from claude bot Mar 18, 2026
@artemdemo artemdemo changed the title Users Schema Users Entity Schema Mar 18, 2026
@artemdemo artemdemo changed the title Users Entity Schema User Entity Schema Mar 18, 2026
Comment on lines +125 to +127
private normalizeName(entityName: string): string {
return entityName.toLowerCase();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Behind the scenes production is treating entity name as case-insensitive: "User" and "user" are the same.

@base44 base44 deleted a comment from claude bot Mar 18, 2026
@artemdemo artemdemo marked this pull request as ready for review March 18, 2026 12:50
@kfirstri kfirstri moved this from Backlog to In review in CLI Development Mar 18, 2026
@kfirstri kfirstri self-requested a review March 19, 2026 15:31
Copy link
Collaborator

@kfirstri kfirstri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, i'm not sure i understand some stuff in the entities-user-router..
Also, can we resolve the user with the auth token and not with readAuth somehow? I see we added a check to assert the api calls has a Bearer.. so maybe we can parse the token?

return;
}
next();
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So every request to the dev-server must have an authorization header. Is this also how the apper/ backend works? It won't allow anonymous calls at all?

let result: Record<string, unknown> | undefined;

if (req.params.id === "me") {
const userInfo = await readAuth();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wont the request at this point will have a authorization token that we can read some user data from? then we don't need the readAuth call

const now = getNowISOTimestamp();

// Production is not allowing to add user entity directly.
// In case developer tries to do it - backend silently fails.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this whole POST / endpoint .. we're validating the developing (since we're using readAuth), and if we found the developer account we just return an object, but not really save it? so basically it's just a mock.. but production also does not allow it?

router.post("/bulk", async (_req, res) => {
// not supported in direct call: NO-OP
res.json({});
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a noop endpoint because we just don't want to support it? can't we just delete it and it will return 404?

Comment on lines +72 to +76
const userInfo = await readAuth();
const collection = db.getCollection(USER_COLLECTION);
const userRecord = await collection?.findOneAsync({
email: userInfo.email,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is really how we will get the developer account (raising it again - do we have it as an auth header maybe?), then this is the 3rd time we're doing this in this file, so maybe refactor to another function

return;
}
logger.error(
`Error in PUT /${USER_COLLECTION}/${req.params.id}:`,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error looks weird, no need to use USER_COLLECTION inside the url that we're printing

res.status(404).json({ error: `User record not found` });
}
} else {
res.json({});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IF the user can only update himself and not others, shouldn't we return some errors? this is how apper behaves? :S

router.delete("/:id", async (_req, res) => {
// not supported in direct call: NO-OP
res.json({});
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question like in /bulk route, maybe we can just remove it? what does "direct call" mean?

return {
name: "User",
type: "object",
properties: { ...builtInFields, role: { type: "string" } },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-project-automation github-project-automation bot moved this from In review to Ready in CLI Development Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

2 participants