-
Notifications
You must be signed in to change notification settings - Fork 3
feat: multi-tenancy #428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: multi-tenancy #428
Conversation
All bff functions with requester and the ripples it created.
The origin contains the protocol of the incoming request as well. We need the origin so we can pass this to the authentication service as a redirect url. Authentication is updated to configure paths, and dynamically get the origin passed in.
Introduces a new origin creation flow with validation, error handling, and database insertion. Refactors the origin 'get' logic to 'find', updates related tenant/origin lookups, and adds comprehensive tests and fixtures for origin and tenant modules. Also includes minor improvements and bug fixes in authentication, middleware, and utility code.
Summary by CodeRabbit
""" WalkthroughThis update introduces comprehensive multitenancy support across the application, focusing on URL-based tenant identification, tenant-scoped data access, and dynamic tenant-specific styling. It adds new middleware for origin and tenant management, modifies domain logic to propagate tenant context, updates configuration and environment variables, and enhances the frontend to load tenant-specific assets. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant WebUI
participant OriginMiddleware
participant TenantMiddleware
participant BFF/Domain
participant MongoDB
Browser->>WebUI: Request with Origin header
WebUI->>OriginMiddleware: Handle request
OriginMiddleware->>WebUI: Validates/extracts origin, sets cookie/header
WebUI->>TenantMiddleware: Handle request
TenantMiddleware->>BFF/Domain: Fetch tenant by origin (cache or DB)
BFF/Domain->>MongoDB: Query tenant by origin
MongoDB-->>BFF/Domain: Tenant data
BFF/Domain-->>TenantMiddleware: Tenant info
TenantMiddleware->>WebUI: Attach tenant to request context
WebUI->>WebUI: Load tenant-specific CSS, fetch tenant-scoped data
WebUI-->>Browser: Render tenant-specific UI and data
Estimated code review effort🎯 4 (Complex) | ⏱️ ~90–120 minutes Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
🧹 Nitpick comments (14)
src/webui/main.tsx (1)
14-18
: Consider error boundary for tenant loading.The component hierarchy looks good, but consider whether
TenantContainer
should have its own error boundary to handle tenant loading failures gracefully without breaking the entire application.Consider wrapping
TenantContainer
with an error boundary:<StrictMode> + <ErrorBoundary fallback={<div>Failed to load tenant configuration</div>}> <TenantContainer> <AppContextProvider> <App /> </AppContextProvider> </TenantContainer> + </ErrorBoundary> </StrictMode>docker/mongodb/init.js (1)
1-14
: Consider environment-specific configuration for tenant origins.The script hard-codes localhost origins for ports 3000 and 5173. While appropriate for development, consider:
- Making origins configurable via environment variables for different deployment scenarios
- Adding validation for origin URL formats
- Ensuring this initialization script is only used in development environments
Consider this approach for more flexible configuration:
+const origins = process.env.TENANT_ORIGINS ? + process.env.TENANT_ORIGINS.split(',') : + ['http://localhost:3000', 'http://localhost:5173']; + db = db.getSiblingDB('comify'); db.tenant.updateOne( { _id: 'localhost' }, { $set: { - origins: [ - 'http://localhost:3000', - 'http://localhost:5173' - ] + origins: origins } }, { upsert: true } );src/integrations/runtime/tenantMiddleware.ts (1)
4-4
: Consider using a constant for the tenant path.The hardcoded string
'domain/tenant/getByOriginConverted'
could be error-prone if the path changes. Consider defining this as a constant or importing it from a configuration module to improve maintainability.+import { TENANT_BY_ORIGIN_PATH } from '^/domain/tenant/constants'; + -const tenantPath = 'domain/tenant/getByOriginConverted'; +const tenantPath = TENANT_BY_ORIGIN_PATH;src/domain/tenant/getByOrigin/getByOrigin.ts (1)
23-23
: Consider safer type conversion.The type assertion
as DataModel
bypasses TypeScript's type safety. Consider adding runtime validation to ensure the database record structure matches the expectedDataModel
interface.- return record as DataModel; + // Validate record structure matches DataModel interface + if (!record || typeof record.origins !== 'object' || !Array.isArray(record.origins)) { + throw new Error('Invalid tenant record structure'); + } + + return record as DataModel;src/webui/features/hooks/useHighlight.ts (1)
11-11
: Clarify naming inconsistency between file and export.The file is named
useHighlight.ts
but exportsuseReaction
. Consider aligning the naming for better code maintainability.src/webui/components/common/hooks/useTenant.ts (1)
11-15
: Consider adding tenant.origin to the dependency array.The
useCallback
has an empty dependency array, but it referencestenant.origin
. Iftenant.origin
can change during the component's lifecycle, this could lead to stale closures.const getTenant = useCallback(async () => { return await getByOriginConverted(tenant.origin); - }, []); + }, [tenant.origin]);src/domain/tenant/getByOriginConverted/getByOriginConverted.ts (1)
8-8
: Consider async validation if needed.The current validation is synchronous, which works well for URL validation. However, if future requirements include async validation (e.g., checking origin against external services), consider making
validateData
async and awaiting it.src/domain/creator/generateNickname/retrieveByStartNickname.ts (1)
8-13
: Consider adding tenantId validation.While the database query correctly filters by
tenantId
, consider adding validation to ensure thetenantId
parameter is not empty or malformed before constructing the query.export default async function retrieveByStartNickname(nickname: string, tenantId: string): Promise<DataModel | undefined> { + if (!tenantId?.trim()) { + throw new Error('tenantId is required'); + } + const query = { nickname: { 'STARTS_WITH': nickname }, tenantId: { 'EQUALS': tenantId } };src/webui/components/common/TenantContainer.tsx (1)
26-28
: Consider improving loading state and error handling.The component returns
null
during tenant loading, which might cause layout shifts. Additionally, there's no error handling if the tenant-specific CSS fails to load.-if (tenant === undefined) return null; - -return children; +if (tenant === undefined) { + // Consider showing loading indicator or rendering with default styles + return <div className="loading-tenant">{children}</div>; +} + +return children;For CSS error handling, consider adding an
onError
handler:const link = document.createElement('link'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('href', `/assets/${tenant.id}.css`); link.setAttribute('data-tenant-css', 'true'); +link.onerror = () => { + console.warn(`Failed to load tenant CSS for: ${tenant.id}`); +}; document.head.appendChild(link);src/integrations/runtime/middlewares/OriginMiddleware.ts (3)
23-49
: Consider removing unnecessary type assertion.The logic flow is excellent and properly handles origin extraction, validation, and cookie management. However, the type assertion on line 39 is unnecessary since validation ensures the value is defined.
- request.setHeader('origin', origin as string); + request.setHeader('origin', origin!);
65-73
: Improve cookie parsing robustness.The current cookie parsing has potential issues:
- Splitting on '=' could break if the cookie value contains '=' characters
- Cookie values should be URL-decoded
- Manual parsing is error-prone
Consider using a more robust approach:
- for (const cookie of header.split(';')) - { - const [key, value] = cookie.split('='); - - if (key.trim() === TENANT_COOKIE_NAME) - { - return value?.trim(); - } - } + for (const cookie of header.split(';')) + { + const [key, ...valueParts] = cookie.split('='); + + if (key.trim() === TENANT_COOKIE_NAME) + { + const value = valueParts.join('='); + return value ? decodeURIComponent(value.trim()) : undefined; + } + }
86-89
: Consider cookie encoding and development environment compatibility.The security attributes are excellent, but consider:
- URL-encode the cookie value to handle special characters
- The
Secure
flag requires HTTPS and may break in development environments- response.setHeader('Set-Cookie', `${TENANT_COOKIE_NAME}=${origin}; Path=/; HttpOnly=true; SameSite=Strict; Secure`); + response.setHeader('Set-Cookie', `${TENANT_COOKIE_NAME}=${encodeURIComponent(origin)}; Path=/; HttpOnly=true; SameSite=Strict; Secure`);Consider making the
Secure
flag configurable for development environments.src/integrations/authentication/implementations/openid/OpenID.ts (1)
75-78
: Consider more robust query parameter handling.The URL construction is correct, but consider using URLSearchParams for safer query parameter handling:
- const currentUrl = new URL(`${this.#providerConfiguration.redirectPath}?session_state=${data.session_state}&iss=${data.iss}&code=${data.code}`, origin); + const url = new URL(this.#providerConfiguration.redirectPath, origin); + url.searchParams.set('session_state', data.session_state as string); + url.searchParams.set('iss', data.iss as string); + url.searchParams.set('code', data.code as string); + const currentUrl = url;This approach handles URL encoding automatically and is more maintainable.
src/integrations/runtime/middlewares/TenantMiddleware.ts (1)
23-43
: Consider cache expiration and error handling strategy.The caching logic is solid, but consider these improvements:
- Cache expiration: The cache has no TTL, which could lead to stale tenant data
- Memory management: No cache size limits could cause memory issues
- Error caching: Client errors (4xx) are cached, which may not be desired
Consider implementing:
- Cache TTL with timestamps
- LRU cache with size limits
- More selective caching (e.g., only cache 200 responses)
- if (response.status < 500) + if (response.status === 200) { this.#cache.set(origin, response); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (107)
docker-compose.yml
(1 hunks)docker/mongodb/init.js
(1 hunks)docs/integrations/AUTHENTICATION.md
(1 hunks)eslint.config.js
(1 hunks)example.env
(2 hunks)package.json
(2 hunks)segments/bff.json
(1 hunks)segments/reads.json
(1 hunks)services/bff.json
(1 hunks)services/gateway.json
(0 hunks)services/proxy.json
(1 hunks)services/standalone.json
(2 hunks)src/assets/localhost.css
(1 hunks)src/domain/authentication/login/login.ts
(1 hunks)src/domain/creator/aggregate/types.ts
(1 hunks)src/domain/creator/create/create.ts
(1 hunks)src/domain/creator/create/createData.ts
(1 hunks)src/domain/creator/create/types.ts
(1 hunks)src/domain/creator/create/validateData.ts
(2 hunks)src/domain/creator/generateNickname/generateNickname.ts
(1 hunks)src/domain/creator/generateNickname/retrieveByNickname.ts
(1 hunks)src/domain/creator/generateNickname/retrieveByStartNickname.ts
(1 hunks)src/domain/creator/getByEmail/getByEmail.ts
(1 hunks)src/domain/creator/getById/CreatorNotFound.ts
(1 hunks)src/domain/creator/getById/getById.ts
(1 hunks)src/domain/creator/getByIdAggregated/getByIdAggregated.ts
(1 hunks)src/domain/creator/getByNickname/getByNickname.ts
(1 hunks)src/domain/creator/getByNicknameAggregated/getByNicknameAggregated.ts
(1 hunks)src/domain/creator/getMe/getMe.ts
(1 hunks)src/domain/creator/getMeAggregated/getMeAggregated.ts
(1 hunks)src/domain/creator/getOthers/getOthers.ts
(1 hunks)src/domain/creator/register/register.ts
(1 hunks)src/domain/creator/types.ts
(1 hunks)src/domain/notification/aggregate/aggregate.ts
(1 hunks)src/domain/notification/getByIdAggregated/getByIdAggregated.ts
(1 hunks)src/domain/notification/getRecentAggregated/getRecentAggregated.ts
(1 hunks)src/domain/post/aggregate/aggregate.ts
(1 hunks)src/domain/post/create/InvalidPost.ts
(1 hunks)src/domain/post/create/create.ts
(1 hunks)src/domain/post/create/createData.ts
(1 hunks)src/domain/post/create/types.ts
(1 hunks)src/domain/post/create/validateData.ts
(2 hunks)src/domain/post/createWithComic/createWithComic.ts
(1 hunks)src/domain/post/createWithComment/createWithComment.ts
(1 hunks)src/domain/post/explore/explore.ts
(1 hunks)src/domain/post/explore/retrieveData.ts
(1 hunks)src/domain/post/exploreAggregated/exploreAggregated.ts
(1 hunks)src/domain/post/getByCreatorAggregated/getByCreatorAggregated.ts
(1 hunks)src/domain/post/getByFollowingAggregated/getByFollowingAggregated.ts
(1 hunks)src/domain/post/getByIdAggregated/getByIdAggregated.ts
(1 hunks)src/domain/post/getByParentAggregated/getByParentAggregated.ts
(1 hunks)src/domain/post/getRecommended/getRecommended.ts
(1 hunks)src/domain/post/getRecommendedAggregated/getRecommendedAggregated.ts
(1 hunks)src/domain/post/types.ts
(1 hunks)src/domain/relation/aggregate/aggregate.ts
(1 hunks)src/domain/relation/explore/explore.ts
(1 hunks)src/domain/relation/exploreAggregated/exploreAggregated.ts
(1 hunks)src/domain/relation/getAggregated/getAggregated.ts
(1 hunks)src/domain/relation/getFollowersAggregated/getFollowersAggregated.ts
(1 hunks)src/domain/relation/getFollowingAggregated/getFollowingAggregated.ts
(1 hunks)src/domain/tenant/definitions.ts
(1 hunks)src/domain/tenant/getByOrigin/TenantNotFound.ts
(1 hunks)src/domain/tenant/getByOrigin/getByOrigin.ts
(1 hunks)src/domain/tenant/getByOrigin/index.ts
(1 hunks)src/domain/tenant/getByOriginConverted/InvalidOrigin.ts
(1 hunks)src/domain/tenant/getByOriginConverted/getByOriginConverted.ts
(1 hunks)src/domain/tenant/getByOriginConverted/index.ts
(1 hunks)src/domain/tenant/getByOriginConverted/types.ts
(1 hunks)src/domain/tenant/getByOriginConverted/validateData.ts
(1 hunks)src/domain/tenant/index.ts
(1 hunks)src/domain/tenant/tenant.ts
(1 hunks)src/domain/tenant/types.ts
(1 hunks)src/integrations/authentication/definitions/interfaces.ts
(1 hunks)src/integrations/authentication/implementations/openid/OpenID.ts
(3 hunks)src/integrations/authentication/implementations/openid/create.ts
(1 hunks)src/integrations/runtime/authenticationMiddleware.ts
(1 hunks)src/integrations/runtime/middlewares/AuthenticationMiddleware.ts
(4 hunks)src/integrations/runtime/middlewares/OriginMiddleware.ts
(1 hunks)src/integrations/runtime/middlewares/TenantMiddleware.ts
(1 hunks)src/integrations/runtime/originMiddleware.ts
(1 hunks)src/integrations/runtime/setUpBff.ts
(1 hunks)src/integrations/runtime/setUpGateway.ts
(0 hunks)src/integrations/runtime/tearDownBff.ts
(1 hunks)src/integrations/runtime/tearDownGateway.ts
(0 hunks)src/integrations/runtime/tenantMiddleware.ts
(1 hunks)src/webui/components/application/LegalInfo.tsx
(1 hunks)src/webui/components/common/TenantContainer.tsx
(1 hunks)src/webui/components/common/hooks/useTenant.ts
(1 hunks)src/webui/components/index.ts
(1 hunks)src/webui/contexts/AppContext.tsx
(1 hunks)src/webui/features/hooks/useAddComicPost.ts
(2 hunks)src/webui/features/hooks/useCreatePostComicReaction.ts
(1 hunks)src/webui/features/hooks/useCreatePostCommentReaction.ts
(1 hunks)src/webui/features/hooks/useCreator.ts
(2 hunks)src/webui/features/hooks/useCreatorFollowers.ts
(2 hunks)src/webui/features/hooks/useCreatorFollowing.ts
(2 hunks)src/webui/features/hooks/useCreatorPosts.ts
(2 hunks)src/webui/features/hooks/useExploreCreators.ts
(2 hunks)src/webui/features/hooks/useExplorePosts.ts
(2 hunks)src/webui/features/hooks/useHighlight.ts
(2 hunks)src/webui/features/hooks/useIdentify.ts
(2 hunks)src/webui/features/hooks/useNotifications.ts
(2 hunks)src/webui/features/hooks/usePost.ts
(2 hunks)src/webui/features/hooks/usePostReactions.ts
(2 hunks)src/webui/features/hooks/usePostsFollowing.ts
(2 hunks)src/webui/features/hooks/usePostsRecommended.ts
(2 hunks)src/webui/main.tsx
(1 hunks)
⛔ Files not processed due to max files limit (29)
- test/domain/authentication/fixtures/index.ts
- test/domain/authentication/fixtures/records.fixture.ts
- test/domain/authentication/fixtures/tenants.fixture.ts
- test/domain/authentication/login.spec.ts
- test/domain/notification/fixtures/index.ts
- test/domain/notification/fixtures/records.fixture.ts
- test/domain/notification/fixtures/tenants.fixture.ts
- test/domain/notification/getRecentAggregated.spec.ts
- test/domain/post/createWithComic.spec.ts
- test/domain/post/fixtures/databases.fixture.ts
- test/domain/post/fixtures/index.ts
- test/domain/post/fixtures/records.fixture.ts
- test/domain/post/fixtures/tenants.fixture.ts
- test/domain/post/getByFollowingAggregated.spec.ts
- test/domain/post/getRecommendedAggregated.spec.ts
- test/domain/relation/exploreAggregated.spec.ts
- test/domain/relation/fixtures/index.ts
- test/domain/relation/fixtures/records.fixture.ts
- test/domain/relation/fixtures/tenants.fixture.ts
- test/domain/relation/getFollowersAggregated.spec.ts
- test/domain/relation/getFollowingAggregated.spec.ts
- test/domain/tenant/fixtures/databases.fixtures.ts
- test/domain/tenant/fixtures/index.ts
- test/domain/tenant/fixtures/records.fixtures.ts
- test/domain/tenant/fixtures/values.fixtures.ts
- test/domain/tenant/getByOrigin.spec.ts
- test/domain/tenant/getByOriginConverted.spec.ts
- test/integrations/database/implementation.spec.ts
- vite.config.ts
🧠 Learnings (2)
src/domain/tenant/getByOriginConverted/index.ts (1)
Learnt from: basmasking
PR: #412
File: segments/writes.json:23-23
Timestamp: 2025-05-23T20:57:56.396Z
Learning: Segmentation files in the Comify project support index resolution. When a path like ./domain/post.metrics/update
is referenced in segment configuration files, it implicitly refers to ./domain/post.metrics/update/index.ts
(or similar extension).
segments/bff.json (1)
Learnt from: basmasking
PR: #412
File: segments/writes.json:23-23
Timestamp: 2025-05-23T20:57:56.396Z
Learning: Segmentation files in the Comify project support index resolution. When a path like ./domain/post.metrics/update
is referenced in segment configuration files, it implicitly refers to ./domain/post.metrics/update/index.ts
(or similar extension).
🧬 Code Graph Analysis (35)
src/domain/tenant/definitions.ts (1)
src/domain/tenant/index.ts (1)
RECORD_TYPE
(2-2)
src/domain/relation/getAggregated/getAggregated.ts (3)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/domain/post/createWithComment/createWithComment.ts (2)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)
src/domain/tenant/getByOriginConverted/getByOriginConverted.ts (3)
src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/tenant/getByOriginConverted/validateData.ts (1)
validateData
(20-28)src/domain/tenant/getByOrigin/getByOrigin.ts (1)
getByOrigin
(9-24)
src/integrations/runtime/authenticationMiddleware.ts (1)
src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (1)
AuthenticationMiddleware
(20-232)
src/domain/tenant/getByOrigin/TenantNotFound.ts (1)
src/integrations/runtime/errors/NotFound.ts (1)
NotFound
(4-7)
src/domain/creator/generateNickname/generateNickname.ts (3)
src/domain/creator/cleanNickname/cleanNickname.ts (1)
cleanNickname
(5-11)src/domain/creator/generateNickname/retrieveByNickname.ts (1)
retrieveByNickname
(7-15)src/domain/creator/generateNickname/retrieveByStartNickname.ts (1)
retrieveByStartNickname
(8-18)
src/domain/notification/getRecentAggregated/getRecentAggregated.ts (3)
src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/notification/getRecent/getRecent.ts (1)
getRecent
(8-19)src/domain/notification/aggregate/aggregate.ts (1)
aggregate
(10-24)
src/domain/post/explore/retrieveData.ts (3)
src/domain/relation/getFollowing/retrieveData.ts (1)
retrieveData
(8-16)src/domain/relation/getFollowers/retrieveData.ts (1)
retrieveData
(8-16)src/integrations/database/definitions/types.ts (1)
RecordQuery
(20-20)
src/webui/main.tsx (2)
src/webui/contexts/AppContext.tsx (1)
AppContextProvider
(29-36)src/webui/App.tsx (1)
App
(10-26)
src/domain/post/exploreAggregated/exploreAggregated.ts (5)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/post/explore/explore.ts (1)
explore
(9-17)src/domain/post/aggregate/aggregate.ts (1)
aggregate
(13-34)
src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (4)
src/integrations/authentication/definitions/interfaces.ts (1)
IdentityProvider
(4-19)src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
request
(51-54)request
(56-74)src/integrations/runtime/middlewares/TenantMiddleware.ts (3)
request
(23-43)request
(45-56)request
(58-61)src/integrations/utilities/crypto.ts (1)
generateKey
(24-32)
src/domain/creator/getByNickname/getByNickname.ts (1)
src/domain/creator/getByNickname/NicknameNotFound.ts (1)
NicknameNotFound
(4-10)
src/domain/relation/getFollowingAggregated/getFollowingAggregated.ts (6)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/index.ts (1)
Tenant
(4-4)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/creator/aggregate/types.ts (1)
AggregatedData
(13-13)src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/integrations/runtime/originMiddleware.ts (1)
src/integrations/runtime/middlewares/OriginMiddleware.ts (1)
OriginMiddleware
(21-90)
src/integrations/runtime/tenantMiddleware.ts (1)
src/integrations/runtime/middlewares/TenantMiddleware.ts (1)
TenantMiddleware
(6-62)
src/domain/tenant/tenant.ts (2)
src/domain/tenant/index.ts (1)
Tenant
(4-4)src/domain/tenant/types.ts (1)
Tenant
(13-13)
src/domain/creator/create/types.ts (1)
src/domain/creator/types.ts (1)
DataModel
(14-14)
src/domain/creator/create/createData.ts (3)
src/domain/post/create/createData.ts (1)
createData
(6-17)src/domain/creator/types.ts (1)
DataModel
(14-14)src/integrations/utilities/crypto.ts (1)
generateId
(19-22)
src/webui/features/hooks/useIdentify.ts (1)
src/domain/creator/getMe/getMe.ts (1)
getMe
(8-11)
src/domain/post/getByCreatorAggregated/getByCreatorAggregated.ts (4)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/post/aggregate/aggregate.ts (1)
aggregate
(13-34)
src/webui/features/hooks/useCreatorFollowing.ts (1)
src/domain/relation/getFollowing/getFollowing.ts (1)
getFollowing
(8-13)
src/domain/creator/getMe/getMe.ts (1)
src/domain/creator/getById/getById.ts (1)
getById
(8-24)
src/domain/post/create/validateData.ts (2)
src/domain/definitions.ts (2)
requiredIdValidation
(9-17)optionalIdValidation
(19-27)src/domain/post/create/types.ts (1)
ValidationModel
(6-6)
src/domain/creator/getById/CreatorNotFound.ts (1)
src/integrations/runtime/errors/NotFound.ts (1)
NotFound
(4-7)
src/domain/post/getByParentAggregated/getByParentAggregated.ts (1)
src/domain/post/aggregate/aggregate.ts (1)
aggregate
(13-34)
src/webui/components/common/TenantContainer.tsx (1)
src/webui/components/common/hooks/useTenant.ts (1)
useTenant
(9-18)
src/domain/tenant/types.ts (2)
src/domain/tenant/index.ts (2)
DataModel
(4-4)Tenant
(4-4)src/domain/types.ts (1)
BaseDataModel
(8-8)
src/domain/creator/generateNickname/retrieveByStartNickname.ts (3)
src/integrations/database/implementations/mongodb/MongoDb.ts (1)
sort
(256-272)src/integrations/database/definitions/types.ts (1)
RecordSort
(23-23)src/integrations/database/definitions/constants.ts (1)
SortDirections
(10-14)
src/domain/tenant/getByOrigin/getByOrigin.ts (4)
src/domain/tenant/index.ts (2)
DataModel
(4-4)RECORD_TYPE
(2-2)src/domain/tenant/types.ts (1)
DataModel
(13-13)src/integrations/database/definitions/types.ts (1)
RecordQuery
(20-20)src/domain/tenant/getByOrigin/TenantNotFound.ts (1)
TenantNotFound
(4-10)
src/domain/relation/exploreAggregated/exploreAggregated.ts (3)
src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/relation/explore/explore.ts (1)
explore
(10-22)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/domain/relation/getFollowersAggregated/getFollowersAggregated.ts (3)
src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/relation/getFollowers/getFollowers.ts (1)
getFollowers
(8-13)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/integrations/runtime/middlewares/OriginMiddleware.ts (4)
src/integrations/validation/definitions/types.ts (1)
ValidationSchema
(55-55)src/integrations/runtime/middlewares/TenantMiddleware.ts (3)
request
(23-43)request
(45-56)request
(58-61)src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (12)
request
(51-58)request
(60-87)request
(89-105)request
(107-130)request
(132-139)request
(194-211)request
(213-216)request
(228-231)response
(218-221)response
(223-226)key
(151-154)key
(156-166)src/integrations/runtime/errors/BadRequest.ts (1)
BadRequest
(4-7)
src/domain/tenant/getByOriginConverted/validateData.ts (3)
src/integrations/validation/definitions/types.ts (1)
ValidationSchema
(55-55)src/domain/tenant/getByOriginConverted/types.ts (1)
ValidationModel
(4-4)src/domain/tenant/getByOriginConverted/InvalidOrigin.ts (1)
InvalidOrigin
(4-7)
src/integrations/runtime/middlewares/TenantMiddleware.ts (2)
src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
request
(51-54)request
(56-74)src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (8)
request
(51-58)request
(60-87)request
(89-105)request
(107-130)request
(132-139)request
(194-211)request
(213-216)request
(228-231)
🪛 Biome (1.9.4)
src/assets/localhost.css
[error] 1-2: An empty block isn't allowed.
Consider removing the empty block or adding styles inside it.
(lint/suspicious/noEmptyBlock)
💤 Files with no reviewable changes (3)
- services/gateway.json
- src/integrations/runtime/tearDownGateway.ts
- src/integrations/runtime/setUpGateway.ts
🧰 Additional context used
🧠 Learnings (2)
src/domain/tenant/getByOriginConverted/index.ts (1)
Learnt from: basmasking
PR: #412
File: segments/writes.json:23-23
Timestamp: 2025-05-23T20:57:56.396Z
Learning: Segmentation files in the Comify project support index resolution. When a path like ./domain/post.metrics/update
is referenced in segment configuration files, it implicitly refers to ./domain/post.metrics/update/index.ts
(or similar extension).
segments/bff.json (1)
Learnt from: basmasking
PR: #412
File: segments/writes.json:23-23
Timestamp: 2025-05-23T20:57:56.396Z
Learning: Segmentation files in the Comify project support index resolution. When a path like ./domain/post.metrics/update
is referenced in segment configuration files, it implicitly refers to ./domain/post.metrics/update/index.ts
(or similar extension).
🧬 Code Graph Analysis (35)
src/domain/tenant/definitions.ts (1)
src/domain/tenant/index.ts (1)
RECORD_TYPE
(2-2)
src/domain/relation/getAggregated/getAggregated.ts (3)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/domain/post/createWithComment/createWithComment.ts (2)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)
src/domain/tenant/getByOriginConverted/getByOriginConverted.ts (3)
src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/tenant/getByOriginConverted/validateData.ts (1)
validateData
(20-28)src/domain/tenant/getByOrigin/getByOrigin.ts (1)
getByOrigin
(9-24)
src/integrations/runtime/authenticationMiddleware.ts (1)
src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (1)
AuthenticationMiddleware
(20-232)
src/domain/tenant/getByOrigin/TenantNotFound.ts (1)
src/integrations/runtime/errors/NotFound.ts (1)
NotFound
(4-7)
src/domain/creator/generateNickname/generateNickname.ts (3)
src/domain/creator/cleanNickname/cleanNickname.ts (1)
cleanNickname
(5-11)src/domain/creator/generateNickname/retrieveByNickname.ts (1)
retrieveByNickname
(7-15)src/domain/creator/generateNickname/retrieveByStartNickname.ts (1)
retrieveByStartNickname
(8-18)
src/domain/notification/getRecentAggregated/getRecentAggregated.ts (3)
src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/notification/getRecent/getRecent.ts (1)
getRecent
(8-19)src/domain/notification/aggregate/aggregate.ts (1)
aggregate
(10-24)
src/domain/post/explore/retrieveData.ts (3)
src/domain/relation/getFollowing/retrieveData.ts (1)
retrieveData
(8-16)src/domain/relation/getFollowers/retrieveData.ts (1)
retrieveData
(8-16)src/integrations/database/definitions/types.ts (1)
RecordQuery
(20-20)
src/webui/main.tsx (2)
src/webui/contexts/AppContext.tsx (1)
AppContextProvider
(29-36)src/webui/App.tsx (1)
App
(10-26)
src/domain/post/exploreAggregated/exploreAggregated.ts (5)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/post/explore/explore.ts (1)
explore
(9-17)src/domain/post/aggregate/aggregate.ts (1)
aggregate
(13-34)
src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (4)
src/integrations/authentication/definitions/interfaces.ts (1)
IdentityProvider
(4-19)src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
request
(51-54)request
(56-74)src/integrations/runtime/middlewares/TenantMiddleware.ts (3)
request
(23-43)request
(45-56)request
(58-61)src/integrations/utilities/crypto.ts (1)
generateKey
(24-32)
src/domain/creator/getByNickname/getByNickname.ts (1)
src/domain/creator/getByNickname/NicknameNotFound.ts (1)
NicknameNotFound
(4-10)
src/domain/relation/getFollowingAggregated/getFollowingAggregated.ts (6)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/index.ts (1)
Tenant
(4-4)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/creator/aggregate/types.ts (1)
AggregatedData
(13-13)src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/integrations/runtime/originMiddleware.ts (1)
src/integrations/runtime/middlewares/OriginMiddleware.ts (1)
OriginMiddleware
(21-90)
src/integrations/runtime/tenantMiddleware.ts (1)
src/integrations/runtime/middlewares/TenantMiddleware.ts (1)
TenantMiddleware
(6-62)
src/domain/tenant/tenant.ts (2)
src/domain/tenant/index.ts (1)
Tenant
(4-4)src/domain/tenant/types.ts (1)
Tenant
(13-13)
src/domain/creator/create/types.ts (1)
src/domain/creator/types.ts (1)
DataModel
(14-14)
src/domain/creator/create/createData.ts (3)
src/domain/post/create/createData.ts (1)
createData
(6-17)src/domain/creator/types.ts (1)
DataModel
(14-14)src/integrations/utilities/crypto.ts (1)
generateId
(19-22)
src/webui/features/hooks/useIdentify.ts (1)
src/domain/creator/getMe/getMe.ts (1)
getMe
(8-11)
src/domain/post/getByCreatorAggregated/getByCreatorAggregated.ts (4)
src/domain/authentication/types.ts (1)
Requester
(8-8)src/domain/tenant/types.ts (1)
Tenant
(13-13)src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/post/aggregate/aggregate.ts (1)
aggregate
(13-34)
src/webui/features/hooks/useCreatorFollowing.ts (1)
src/domain/relation/getFollowing/getFollowing.ts (1)
getFollowing
(8-13)
src/domain/creator/getMe/getMe.ts (1)
src/domain/creator/getById/getById.ts (1)
getById
(8-24)
src/domain/post/create/validateData.ts (2)
src/domain/definitions.ts (2)
requiredIdValidation
(9-17)optionalIdValidation
(19-27)src/domain/post/create/types.ts (1)
ValidationModel
(6-6)
src/domain/creator/getById/CreatorNotFound.ts (1)
src/integrations/runtime/errors/NotFound.ts (1)
NotFound
(4-7)
src/domain/post/getByParentAggregated/getByParentAggregated.ts (1)
src/domain/post/aggregate/aggregate.ts (1)
aggregate
(13-34)
src/webui/components/common/TenantContainer.tsx (1)
src/webui/components/common/hooks/useTenant.ts (1)
useTenant
(9-18)
src/domain/tenant/types.ts (2)
src/domain/tenant/index.ts (2)
DataModel
(4-4)Tenant
(4-4)src/domain/types.ts (1)
BaseDataModel
(8-8)
src/domain/creator/generateNickname/retrieveByStartNickname.ts (3)
src/integrations/database/implementations/mongodb/MongoDb.ts (1)
sort
(256-272)src/integrations/database/definitions/types.ts (1)
RecordSort
(23-23)src/integrations/database/definitions/constants.ts (1)
SortDirections
(10-14)
src/domain/tenant/getByOrigin/getByOrigin.ts (4)
src/domain/tenant/index.ts (2)
DataModel
(4-4)RECORD_TYPE
(2-2)src/domain/tenant/types.ts (1)
DataModel
(13-13)src/integrations/database/definitions/types.ts (1)
RecordQuery
(20-20)src/domain/tenant/getByOrigin/TenantNotFound.ts (1)
TenantNotFound
(4-10)
src/domain/relation/exploreAggregated/exploreAggregated.ts (3)
src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/relation/explore/explore.ts (1)
explore
(10-22)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/domain/relation/getFollowersAggregated/getFollowersAggregated.ts (3)
src/domain/common/validateRange/validateRange.ts (1)
validateRange
(31-39)src/domain/relation/getFollowers/getFollowers.ts (1)
getFollowers
(8-13)src/domain/relation/aggregate/aggregate.ts (1)
aggregate
(8-18)
src/integrations/runtime/middlewares/OriginMiddleware.ts (4)
src/integrations/validation/definitions/types.ts (1)
ValidationSchema
(55-55)src/integrations/runtime/middlewares/TenantMiddleware.ts (3)
request
(23-43)request
(45-56)request
(58-61)src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (12)
request
(51-58)request
(60-87)request
(89-105)request
(107-130)request
(132-139)request
(194-211)request
(213-216)request
(228-231)response
(218-221)response
(223-226)key
(151-154)key
(156-166)src/integrations/runtime/errors/BadRequest.ts (1)
BadRequest
(4-7)
src/domain/tenant/getByOriginConverted/validateData.ts (3)
src/integrations/validation/definitions/types.ts (1)
ValidationSchema
(55-55)src/domain/tenant/getByOriginConverted/types.ts (1)
ValidationModel
(4-4)src/domain/tenant/getByOriginConverted/InvalidOrigin.ts (1)
InvalidOrigin
(4-7)
src/integrations/runtime/middlewares/TenantMiddleware.ts (2)
src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
request
(51-54)request
(56-74)src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (8)
request
(51-58)request
(60-87)request
(89-105)request
(107-130)request
(132-139)request
(194-211)request
(213-216)request
(228-231)
🪛 Biome (1.9.4)
src/assets/localhost.css
[error] 1-2: An empty block isn't allowed.
Consider removing the empty block or adding styles inside it.
(lint/suspicious/noEmptyBlock)
🔇 Additional comments (145)
src/webui/components/application/LegalInfo.tsx (1)
11-11
: LGTM! Copyright year updated correctly.Simple and appropriate copyright year update for 2025.
eslint.config.js (1)
18-19
: LGTM! Docker directory appropriately excluded from linting.Adding the "docker" directory to the ignore patterns is the correct approach for excluding infrastructure files from linting processes.
src/domain/tenant/definitions.ts (1)
2-2
: LGTM! Clean domain constant definition.The
RECORD_TYPE
constant provides a centralized identifier for tenant records, following good domain-driven design practices.src/webui/contexts/AppContext.tsx (1)
2-2
: LGTM! Minor formatting improvement.Good formatting correction adding proper spacing in the import statement.
package.json (1)
41-41
: Verify jitar v0.10.0 for potential breaking changesThe bump from 0.9.3 to 0.10.0 for both
jitar
and@jitar/plugin-vite
aligns with your tenant-aware implementation. However, no detailed changelog was found via web search, and pre-1.0 semver allows breaking changes in minor releases.Action items:
- Confirm
jitar@0.10.0
is published on npm.- Review the official changelog or GitHub releases for breaking changes between v0.9.3 and v0.10.0.
- Test all tenant-aware functionality with the upgraded versions.
Also applies to: lines 54-54
src/domain/post/create/InvalidPost.ts (1)
4-4
: Approval: InvalidReaction references replaced with InvalidPostVerified that:
- No occurrences of
InvalidReaction
remain in the codebase.InvalidPost
is defined insrc/domain/post/create/InvalidPost.ts
, imported and thrown invalidateData.ts
, and re-exported inindex.ts
.All references have been correctly updated. Great semantic improvement—approving these changes.
src/domain/tenant/getByOriginConverted/index.ts (1)
2-2
: LGTM! Follows established project patterns.This barrel file correctly follows the project's convention for index resolution, as confirmed by the retrieved learning. The re-export pattern provides a clean interface for the tenant origin conversion functionality.
docs/integrations/AUTHENTICATION.md (1)
36-36
: Documentation correctly reflects the multi-tenant authentication changes.The change from
OPENID_REDIRECT_URI
toOPENID_REDIRECT_PATH
with a relative path aligns well with the multi-tenancy implementation where redirect URLs need to be constructed dynamically based on the request origin/tenant.src/domain/post/types.ts (1)
11-11
: Excellent addition of tenantId for multi-tenant data isolation.The
tenantId
field is correctly implemented as a required readonly property, ensuring proper tenant scoping for all post data. This foundational change supports the multi-tenancy architecture effectively.src/domain/tenant/getByOriginConverted/InvalidOrigin.ts (1)
1-7
: Well-structured error class for tenant origin validation.The
InvalidOrigin
error class is properly implemented, extendingValidationError
and serving as a semantic marker for origin validation failures. The empty class body is appropriate for this specialized error type.src/integrations/runtime/tearDownBff.ts (2)
2-2
: Proper consolidation of identity provider lifecycle management.The import addition correctly brings the identity provider into the BFF teardown process, aligning with the architectural shift away from separate gateway lifecycle management.
8-8
: Consistent disconnection pattern implementation.The identity provider disconnection logic follows the same robust pattern as the existing event broker disconnection, with proper connection state checking and concurrent execution via Promise.allSettled.
src/integrations/runtime/setUpBff.ts (3)
2-2
: Correct integration of identity provider into BFF setup.The import properly brings the identity provider into the BFF setup process, supporting the consolidated authentication architecture for multi-tenancy.
8-10
: Robust concurrent connection implementation.The identity provider connection is properly added to the Promise.allSettled array, ensuring efficient concurrent initialization alongside the event broker.
17-17
: Proper error handling with cleanup logic.The error handling correctly includes identity provider disconnection, maintaining consistency with the connection attempt and ensuring proper cleanup on setup failure.
docker-compose.yml (1)
12-12
: MONGO_INIT_PATH configuration verified
MONGO_INIT_PATH
is defined inexample.env
.- The
docker/mongodb/
directory exists and can be mounted.No further action required.
src/integrations/runtime/originMiddleware.ts (1)
2-4
: Well-implemented singleton pattern for middleware.The singleton export pattern is appropriate for middleware and the implementation follows good practices. The actual middleware logic (from the relevant code snippets) includes proper origin validation, secure cookie handling, and error management.
src/webui/main.tsx (1)
6-6
: Import statement follows proper conventions.The import statement correctly imports
TenantContainer
from the components index file, maintaining consistency with the existing import patterns.segments/reads.json (2)
31-31
: Proper JSON formatting with trailing comma.Good addition of the trailing comma to maintain proper JSON syntax for the new entry.
33-33
: ✅ Tenant access entry validated
- Verified that
src/domain/tenant/getByOrigin/getByOrigin.ts
exists.- The
"protected"
access level is consistent with other domain resource entries and appropriate for tenant data.No changes required.
src/domain/tenant/getByOriginConverted/types.ts (1)
2-4
: Clean type definition for tenant origin validation.The
ValidationModel
type properly uses thePick
utility to extract only theorigin
property fromTenant
, which is appropriate for validation scenarios where only the origin needs to be validated.src/webui/components/index.ts (1)
22-22
: Properly integrated component export.The
TenantContainer
export follows the established pattern and maintains alphabetical ordering with other component exports.src/domain/tenant/getByOrigin/TenantNotFound.ts (1)
4-10
: Well-structured error class for tenant resolution failures.The
TenantNotFound
error class properly extends theNotFound
base class and provides a descriptive error message that includes the origin context, which will be helpful for debugging tenant resolution issues.src/integrations/authentication/implementations/openid/create.ts (1)
9-12
: Consistent refactoring for origin-aware authentication.The change from
OPENID_REDIRECT_URI
toOPENID_REDIRECT_PATH
and corresponding variable renaming is well-coordinated, supporting the multitenancy architecture where redirect URLs are dynamically constructed based on request origin.src/domain/creator/create/types.ts (1)
4-4
: Proper integration of tenant context in creator validation.Adding
tenantId
to theValidationModel
type appropriately extends creator validation to support multitenancy, ensuring that creator creation operations are tenant-scoped.src/webui/features/hooks/useCreator.ts (1)
5-5
: Parameter consistency and initialization verified.
getByNicknameAggregated(requester, tenant, nickname)
andgetAggregated(requester, tenant, followerId, followingId)
both acceptrequester
andtenant
in the correct order.- All other domain hooks follow the same
(requester, tenant, …)
signature.- The imported
requester
andtenant
are the initialized defaults fromdomain/authentication
anddomain/tenant
, respectively.No further changes required.
src/integrations/runtime/tenantMiddleware.ts (1)
1-6
: Clean and effective middleware configuration.The approach of exporting a pre-configured middleware instance is clean and follows good separation of concerns. The middleware will handle tenant resolution and caching based on request origins as intended for the multi-tenancy implementation.
src/webui/features/hooks/useNotifications.ts (1)
16-16
: Correct tenant parameter integration.The addition of the
tenant
parameter togetRecentNotifications
correctly implements tenant-scoped data retrieval while maintaining the hook's existing API.src/domain/creator/getMeAggregated/getMeAggregated.ts (2)
3-3
: Proper tenant type integration.The addition of the
Tenant
type import correctly supports the tenant-aware refactoring.
9-11
: Correct tenant parameter propagation.The function signature and internal call to
getMe
properly propagate the tenant context, maintaining the aggregation logic while adding tenant scoping for multi-tenant support.src/domain/creator/getMe/getMe.ts (2)
3-3
: Proper tenant type integration.The
Tenant
type import correctly supports the tenant-aware functionality.
8-11
: Correct tenant-scoped data retrieval.The function properly passes
tenant.id
togetById
, which ensures tenant isolation by filtering records based on both creator ID and tenant ID. This correctly implements multi-tenant data scoping.src/domain/post/create/createData.ts (2)
6-6
: Logical parameter ordering for tenant integration.The placement of
tenantId
as the second parameter (aftercreatorId
) follows a logical hierarchy where core identity parameters come first, followed by optional content parameters.
8-16
: Proper tenant association in post data.The
tenantId
is correctly included in the returnedDataModel
, ensuring all created posts are properly associated with their tenant for multi-tenant data isolation.src/domain/tenant/getByOrigin/index.ts (1)
2-3
: LGTM! Clean barrel export pattern.The re-export structure provides a clean API surface for the tenant domain's origin-based lookup functionality.
src/domain/creator/getById/CreatorNotFound.ts (1)
4-10
: LGTM! Consistent tenant-scoped error handling.The error class correctly implements tenant-aware error handling with a descriptive message format that includes both the creator ID and tenant context.
src/domain/tenant/types.ts (1)
4-11
: Well-designed tenant type definitions.The type structure effectively supports multi-domain tenancy:
DataModel
withorigins[]
allows tenants to have multiple domainsTenant
with singleorigin
represents the resolved tenant for a specific request- Readonly properties ensure immutability of domain objects
src/domain/post/aggregate/aggregate.ts (1)
13-13
: LGTM! Consistent tenant parameter addition.The function signature correctly adds tenant context for tenant-scoped aggregation.
src/domain/tenant/getByOrigin/getByOrigin.ts (1)
11-14
: CONTAINS operator support confirmedThe
CONTAINS
operator is implemented in both database drivers:
- MongoDB (
src/integrations/database/implementations/mongodb/MongoDb.ts
): mapped to$regex
- In-memory (
src/integrations/database/implementations/memory/Memory.ts
): usesString.includes()
No changes required.
src/domain/creator/generateNickname/retrieveByNickname.ts (1)
7-12
: LGTM: Proper tenant isolation implemented.The addition of
tenantId
parameter and corresponding database query filter correctly implements tenant-scoped data access. This ensures nickname lookups are isolated within tenant boundaries, preventing potential cross-tenant data leakage.src/webui/features/hooks/usePostsFollowing.ts (1)
16-16
: LGTM: Consistent tenant parameter propagation.The function call correctly passes the tenant context as the second parameter, maintaining consistency with the tenant-aware architecture.
src/webui/features/hooks/useHighlight.ts (2)
7-7
: LGTM: Consistent tenant import pattern.The tenant import follows the established pattern for tenant-aware data fetching.
18-18
: LGTM: Proper tenant context propagation.The function call correctly includes tenant parameter in the expected position.
src/webui/features/hooks/useCreatorPosts.ts (2)
7-7
: LGTM: Consistent tenant import.The tenant import follows the established pattern for tenant context access.
17-17
: LGTM: Proper tenant-aware creator posts fetching.The function call correctly includes tenant context while maintaining the logical parameter order: requester, tenant, creator ID, and options.
src/webui/features/hooks/useIdentify.ts (2)
8-8
: LGTM: Consistent tenant import pattern.The tenant import maintains consistency with the established multi-tenant architecture.
30-30
: LGTM: Secure tenant-scoped identity retrieval.The function call correctly passes tenant context to
getMe
, which according to the relevant code snippet (src/domain/creator/getMe/getMe.ts
) usestenant.id
to scope the identity lookup. This ensures users can only access their identity within the correct tenant context, providing proper tenant isolation.src/domain/notification/aggregate/aggregate.ts (1)
5-5
: LGTM! Tenant context properly added and propagated.The tenant parameter addition follows the consistent pattern across the codebase. The function correctly:
- Imports the
Tenant
type- Updates the function signature to include the tenant parameter
- Propagates tenant context to both
getRelationData
andgetPostData
callsThis ensures proper tenant scoping for notification aggregation.
Also applies to: 10-10, 13-14
src/domain/creator/getByNicknameAggregated/getByNicknameAggregated.ts (2)
2-4
: LGTM! Proper imports for tenant-aware function signature.The import statements correctly add the required types for the updated function signature.
9-9
: Incorrect assumption aboutaggregate
signatureThe
aggregate
function insrc/domain/creator/aggregate/aggregate.ts
is declared as:export default async function aggregate(data: DataModel): Promise<AggregatedData>—so it only requires the
data
parameter. All three callers in the creator domain correctly invokeaggregate(data)
. No changes are needed.Likely an incorrect or invalid review comment.
src/domain/post/getByCreatorAggregated/getByCreatorAggregated.ts (1)
6-6
: LGTM! Correct tenant context propagation throughout the function.The implementation properly:
- Imports the
Tenant
type- Updates the function signature to include the tenant parameter
- Passes all required parameters (
requester
,tenant
,item
) to theaggregate
function, which matches the expected signature fromsrc/domain/post/aggregate/aggregate.ts
This ensures consistent tenant-scoped post aggregation.
Also applies to: 14-14, 20-20
src/domain/creator/getByEmail/getByEmail.ts (1)
7-7
: LGTM! Proper tenant-scoped database query implementation.The function correctly implements tenant isolation by:
- Adding
tenantId
parameter to the function signature- Including both
tenantId
conditions in the database query with EQUALS comparisons- Ensuring creators can only be retrieved within their tenant scope
This prevents cross-tenant data access and maintains proper data isolation.
Also applies to: 9-12
src/domain/creator/create/validateData.ts (1)
5-5
: LGTM! Comprehensive tenant validation implementation.The validation logic correctly incorporates tenant context by:
- Importing
requiredIdValidation
for consistent ID validation patterns- Adding
tenantId
as a required field in the validation schema- Updating the function signature to accept
tenantId
from the ValidationModel- Including
tenantId
in the validator call to ensure it's validated alongside other fieldsThis ensures creators cannot be created without a valid tenant context, maintaining proper multi-tenant data integrity.
Also applies to: 22-22, 26-26, 28-28
src/domain/creator/getById/getById.ts (2)
8-14
: Excellent tenant isolation implementation.The addition of
tenantId
parameter and filtering ensures proper tenant data isolation, which is critical for multi-tenant security. The query structure correctly enforces that records can only be accessed within their tenant scope.
16-21
: Good error handling with tenant context.Using
database.findRecord
with the tenant-scoped query and including bothid
andtenantId
in the error message provides clear debugging information while maintaining security boundaries.src/domain/tenant/getByOriginConverted/validateData.ts (2)
8-18
: Strong origin validation for tenant security.The validation schema properly enforces URL format and required constraints, which is critical for secure tenant resolution. This prevents potential injection attacks and ensures only valid origins are processed.
20-28
: Appropriate error handling for validation failures.The function correctly throws a custom
InvalidOrigin
error with validation messages, providing clear feedback while maintaining security boundaries for tenant origin validation.src/domain/tenant/index.ts (1)
1-7
: Clean domain module organization.The barrel export pattern provides a clean API surface for the tenant domain, making it easy for other modules to consume tenant-related types and constants.
src/domain/post/create/create.ts (2)
10-16
: Proper tenant integration in post creation.The addition of
tenantId
parameter and its propagation tocreateData
ensures tenant-scoped post creation. The parameter placement is logical and maintains the existing function contract pattern.
26-37
: Excellent error handling preservation.The error handling logic correctly maintains data consistency by cleaning up the post on failure, while the tenant context doesn't interfere with the cleanup process.
src/domain/relation/getFollowingAggregated/getFollowingAggregated.ts (1)
11-17
: Effective tenant integration in aggregation.The addition of the
tenant
parameter and its propagation to theaggregate
function ensures tenant-scoped data access during relation aggregation. The concurrent processing withPromise.all
maintains performance efficiency.src/webui/components/common/hooks/useTenant.ts (2)
9-18
: Well-structured tenant data fetching hook.The hook properly encapsulates tenant data fetching logic with appropriate memoization and state management. The integration with
useLoadData
provides a consistent loading state pattern.
4-4
: I couldn’t locatesrc/webui/components/common/hooks/useTenant.ts
in the repo—no files match “useTenant.ts”. Can you please confirm the path or filename?src/domain/post/explore/explore.ts (1)
9-16
: Excellent tenant-aware implementation.The function correctly integrates tenant context by:
- Adding the
Tenant
parameter in the appropriate position- Passing
tenant.id
to the data retrieval function- Maintaining the existing business logic while adding tenant scoping
This follows the established multi-tenancy pattern consistently.
src/webui/features/hooks/useCreatorFollowing.ts (2)
7-7
: Tenant integration follows established pattern.The tenant import and usage aligns with the multi-tenancy architecture being implemented across the application.
17-17
: VerifiedgetFollowingAggregated
signature matches tenant parameter. No changes required.The call in
useCreatorFollowing.ts
correctly passes(requester, tenant, creator.id, { limit, offset: page * limit })
to:export default async function getFollowingAggregated( requester: Requester, tenant: Tenant, followerId: string, range: Range ): Promise<AggregatedData[]>Everything aligns—tenant integration is correct.
src/webui/features/hooks/usePost.ts (1)
7-18
: Consistent tenant-aware implementation.The hook properly integrates tenant context by:
- Adding the tenant import
- Passing tenant parameter to the
get
function call- Maintaining the existing conditional logic
This follows the established multi-tenancy pattern consistently across the codebase.
src/domain/relation/aggregate/aggregate.ts (1)
8-10
: Proper tenant-scoped aggregation implementation.The function correctly implements tenant-aware aggregation by:
- Adding the
Tenant
parameter to the function signature- Passing
tenant.id
to thegetCreatorData
call for proper tenant scoping- Preserving the existing aggregation logic
This ensures that relation aggregation respects tenant boundaries.
src/webui/features/hooks/useCreatePostComicReaction.ts (2)
8-8
: LGTM: Tenant import added correctly.The tenant import follows the established pattern for multi-tenancy support integration.
14-15
: LGTM: Consistent tenant parameter propagation.Both
createComicReaction
andgetReaction
function calls have been updated consistently to include the tenant parameter, ensuring proper tenant scoping for comic reaction operations.src/integrations/runtime/authenticationMiddleware.ts (3)
12-12
: LGTM: Environment variable updated for path-based redirects.The change from
AUTHENTICATION_CLIENT_URI
toAUTHENTICATION_CLIENT_PATH
and corresponding variable rename aligns with the architectural shift to path-based redirects, as confirmed by theAuthenticationMiddleware
implementation expecting aredirectPath
parameter.
14-14
: LGTM: Whitelist updated for tenant functionality.Adding
'domain/tenant/getByOriginConverted'
to the whitelist is necessary to allow tenant origin resolution to bypass authentication, which is essential for the multi-tenancy support.
16-16
: LGTM: Constructor call updated consistently.The parameter name change to
redirectPath
maintains consistency with the environment variable renaming and theAuthenticationMiddleware
constructor signature.src/webui/features/hooks/usePostsRecommended.ts (2)
6-6
: LGTM: Tenant import added correctly.The tenant import follows the established pattern for multi-tenancy support integration.
16-16
: LGTM: Tenant parameter added to domain function call.The
getPostsRecommended
call has been updated to include the tenant parameter, ensuring proper tenant scoping for recommended posts retrieval while maintaining the hook's existing API.src/domain/relation/getAggregated/getAggregated.ts (3)
2-4
: LGTM: Type imports added correctly.The
Requester
andTenant
type imports are properly added to support the new function signature parameters.
9-9
: LGTM: Function signature updated for multi-tenancy.The function signature has been properly extended to include
requester
andtenant
parameters, enabling tenant-aware relation aggregation.
13-13
: LGTM: Tenant parameter propagated to aggregate function.The
aggregate
function call correctly passes the tenant parameter, as confirmed by the relevant code snippet showingaggregate(tenant: Tenant, data: DataModel)
signature. Theget
function call appropriately remains unchanged as it appears to be a simple data retrieval operation.src/domain/post/exploreAggregated/exploreAggregated.ts (3)
6-6
: LGTM: Tenant type import added correctly.The
Tenant
type import is properly added to support the new function parameter.
12-12
: LGTM: Function signature updated for tenant awareness.The function signature has been properly extended to include the
tenant
parameter, enabling tenant-scoped post exploration and aggregation.
16-16
: LGTM: Tenant parameter propagated consistently.Both the
explore
andaggregate
function calls have been updated to include the tenant parameter, as confirmed by the relevant code snippets. This ensures proper tenant scoping throughout the post exploration and aggregation pipeline while preserving the existing range validation logic.Also applies to: 18-18
src/domain/tenant/getByOriginConverted/getByOriginConverted.ts (1)
6-16
: Verify thatgetByOrigin
always returns an object with anid
propertyBefore merging, please confirm that the return type of
getByOrigin(origin)
includes a non-optionalid
field to avoid runtime errors ingetByOriginConverted
. If the underlying type is missing or marksid
as optional, you’ll need to:
- Update the type/interface for the tenant data model in
src/domain/tenant/getByOrigin.ts
(or its associated types file) to includeid: string
(or appropriate type).- Or add a runtime null/undefined check on
tenant.id
before returning fromgetByOriginConverted
.Files to review:
src/domain/tenant/getByOriginConverted/getByOriginConverted.ts
(callsgetByOrigin
)src/domain/tenant/getByOrigin.ts
(implementation and return type)- Any
types.ts
ormodels.ts
defining the tenant DataModel or interfacesrc/webui/features/hooks/useCreatorFollowers.ts (1)
7-7
: Ignore tenant availability and dependency concerns.The
tenant
import is a module‐level constant of typeTenant
(always defined) and cannot beundefined
. You’re calling the correct overload—getFollowersAggregated(requester, tenant, creator.id, {…})
—which matches its signature. Sincetenant
never changes at runtime, it doesn’t need to be in the hook’s dependency array. No updates are required here.Likely an incorrect or invalid review comment.
src/domain/creator/generateNickname/retrieveByStartNickname.ts (1)
8-8
: AllretrieveByStartNickname
call sites have been updatedI searched for every call to
retrieveByStartNickname
and confirmed they all pass bothnickname
andtenantId
. The only usage is in:
src/domain/creator/generateNickname/generateNickname.ts
const foundData = await retrieveByStartNickname( `${existingData.nickname}_`, tenantId );No other invocations exist. This breaking change is already handled; no further updates are needed.
services/standalone.json (2)
5-5
: Gateway setup/teardown removal verifiedNo occurrences of
setupGateway
ortearDownGateway
remain in the codebase. The removal of gateway initialization is intentional and does not introduce any breakages.
15-19
: Middleware execution order verifiedBoth new middleware files are present and correctly interdependent:
- src/integrations/runtime/originMiddleware.ts exists.
- src/integrations/runtime/tenantMiddleware.ts exists and calls
#getOrigin(request)
before resolving or caching tenants.The sequence origin → authentication → tenant matches the intended request flow. No further changes needed.
src/webui/features/hooks/useExplorePosts.ts (1)
16-16
: Verify explorePosts signature includes tenant
I wasn’t able to locate theexplorePosts
declaration in the repo—please confirm that its signature has been updated to accepttenant
as the second argument to match this call and avoid runtime errors:return explorePosts(requester, tenant, { limit, offset: page * limit });
Key locations to check:
- The file under which
explorePosts
is defined (e.g. insrc/domain/post/
or its index/export file)- Ensure the signature reads:
function explorePosts(requester, tenant, options) { … }src/domain/relation/explore/explore.ts (3)
4-4
: LGTM: Tenant type import added correctly.The import for the
Tenant
type is properly added to support the multi-tenancy implementation.
10-10
: LGTM: Function signature updated for tenant awareness.The function signature correctly includes the new
tenant: Tenant
parameter, maintaining the logical parameter order.
16-16
: LGTM: Tenant ID properly propagated to getOtherCreators.The tenant context is correctly passed by extracting
tenant.id
and placing it as the first argument togetOtherCreators
, which aligns with the multi-tenant architecture pattern.src/domain/post/getByParentAggregated/getByParentAggregated.ts (3)
5-5
: LGTM: Tenant type import added correctly.The import for the
Tenant
type is properly added to support the tenant-aware aggregation.
11-11
: LGTM: Function signature updated consistently.The function signature correctly includes the
tenant: Tenant
parameter, maintaining proper parameter ordering betweenrequester
and business logic parameters.
15-15
: LGTM: Tenant context properly propagated to aggregate function.The tenant parameter is correctly passed to the
aggregate
function for each item. This aligns with the updatedaggregate
function signature shown in the relevant code snippet fromsrc/domain/post/aggregate/aggregate.ts
(lines 12-33).src/domain/notification/getRecentAggregated/getRecentAggregated.ts (3)
6-6
: LGTM: Tenant type import added correctly.The import for the
Tenant
type is properly added to support tenant-aware notification aggregation.
12-12
: LGTM: Function signature updated consistently.The function signature correctly includes the
tenant: Tenant
parameter with proper parameter ordering.
18-18
: LGTM: Tenant context properly propagated to aggregate function.The tenant parameter is correctly passed to the
aggregate
function for each notification item. This aligns with the updated notificationaggregate
function signature shown in the relevant code snippet fromsrc/domain/notification/aggregate/aggregate.ts
(lines 9-23).src/webui/features/hooks/useExploreCreators.ts (1)
16-16
: LGTM: Tenant parameter correctly added to exploreRelations call.The tenant parameter is properly passed to the
exploreRelations
function call, maintaining the correct parameter order as expected by the backend domain function.src/domain/post/getByIdAggregated/getByIdAggregated.ts (3)
3-3
: LGTM: Tenant type import added correctly.The import for the
Tenant
type is properly added to support tenant-aware post aggregation.
11-11
: LGTM: Function signature updated consistently.The function signature correctly includes the
tenant: Tenant
parameter, following the established pattern for tenant-aware domain functions.
15-15
: LGTM: Tenant context properly passed to aggregate function.The tenant parameter is correctly passed to the
aggregate
function, ensuring tenant-scoped data aggregation for individual post retrieval.src/domain/post/create/validateData.ts (1)
13-13
: LGTM: Consistent tenant integration in validation schema.The addition of
tenantId
as a required field follows the established validation pattern and maintains consistency with other ID fields. The function signature and validation call are properly updated to include tenant context.Also applies to: 19-19, 30-30
src/domain/creator/generateNickname/generateNickname.ts (1)
9-9
: LGTM: Proper tenant scoping for nickname generation.The function correctly integrates tenant context by passing
tenantId
to both retrieval functions. This ensures nickname uniqueness is scoped per tenant while maintaining the existing collision resolution logic.Also applies to: 13-13, 20-20
src/domain/creator/getByNickname/getByNickname.ts (1)
8-8
: LGTM: Solid tenant-scoped nickname lookup implementation.The function properly integrates tenant context in the database query and improves code clarity by renaming the variable from
data
tocreator
. The compound query ensures proper tenant isolation while maintaining existing error handling patterns.Also applies to: 10-13, 15-15, 17-17, 22-22
src/domain/creator/aggregate/types.ts (1)
7-7
: LGTM! Proper separation of tenant context from aggregated data.The exclusion of
tenantId
fromAggregatedData
follows good design patterns by keeping tenant context separate from core business data. This aligns with the explicit tenant parameter approach used throughout the domain functions.services/bff.json (1)
9-13
: LGTM! Middleware pipeline order is logically structured.The middleware processing order correctly establishes the multi-tenant request pipeline:
originMiddleware
- extracts request origin (foundational)authenticationMiddleware
- handles origin-aware authenticationtenantMiddleware
- manages tenant context based on originEach middleware builds upon the context established by the previous one.
src/domain/creator/getByIdAggregated/getByIdAggregated.ts (1)
6-8
: Parameter order is correct; no changes needed.I verified that
getById
insrc/domain/creator/getById/getById.ts
is declared as:export default async function getById(id: string, tenantId: string): Promise<DataModel>so calling
getById(id, tenantId)
fromgetByIdAggregated
matches its signature.src/domain/post/createWithComment/createWithComment.ts (2)
4-4
: LGTM! Proper tenant type import.The import of the
Tenant
type from the tenant domain is correctly added to support the new tenant parameter.
8-12
: LGTM! Tenant context properly propagated.The function signature correctly includes the
tenant
parameter, andtenant.id
is properly passed tocreatePost
, replacing the previousundefined
value. This ensures tenant-scoped post creation.src/integrations/authentication/definitions/interfaces.ts (1)
12-14
: LGTM! Origin-aware authentication interface properly defined.The addition of the
origin
parameter to bothgetLoginUrl
andlogin
methods enables dynamic authentication flows based on request origin. This properly supports the multi-tenant architecture by allowing tenant-specific authentication handling.src/domain/creator/create/create.ts (1)
7-9
: LGTM! Tenant context properly integrated.The function signature correctly adds
tenantId
as the first parameter and properly passes it tocreateData
. This follows the consistent pattern established across the multi-tenancy refactoring.src/domain/post/explore/retrieveData.ts (1)
8-16
: LGTM! Tenant-scoped querying implemented correctly.The function properly adds
tenantId
parameter and includes it in the query filter using theEQUALS
condition. This ensures that only posts belonging to the specified tenant are retrieved, which is essential for proper multi-tenant data isolation.src/domain/creator/create/createData.ts (1)
6-14
: LGTM! Tenant context correctly added to data creation.The function properly adds
tenantId
as the first parameter and includes it in the returned data model. This follows the same pattern established in other domaincreateData
functions and ensures all creator records are properly associated with their tenant.src/webui/features/hooks/usePostReactions.ts (1)
7-17
: Approved: tenant context integration verifiedVerified that:
src/domain/tenant/index.ts
exports a defaulttenant
object of typeTenant
.getByParentAggregated
(imported asgetReactionsByPost
) signature isasync function(requester, tenant, postId, range)
.usePostReactions
correctly importstenant
and passes it as the second argument, matching other hooks’ patterns.No further changes needed.
src/domain/post/createWithComic/createWithComic.ts (1)
4-12
: LGTM! Tenant context correctly propagated to post creation.The function properly adds the
tenant
parameter with correct typing and passestenant.id
to thecreatePost
function. This maintains the tenant context throughout the post creation flow while preserving the existing comic creation logic.src/domain/post/getRecommended/getRecommended.ts (2)
8-8
: LGTM: Function signature correctly updated for multi-tenancy.The parameter decomposition from
Requester
object to separaterequesterId
andtenantId
strings aligns well with the tenant-aware refactoring pattern seen throughout the codebase.
14-16
: LGTM: Proper tenant filtering implemented.The query correctly filters posts by tenant using the
EQUALS
operator ontenantId
, ensuring proper tenant isolation. ThecreatorId
filter change fromrequester
torequesterId
is also correct.src/webui/features/hooks/useCreatePostCommentReaction.ts (2)
8-8
: LGTM: Tenant import correctly added.The import statement properly brings in the tenant context needed for the hook's functionality.
14-15
: LGTM: Tenant context properly propagated to domain functions.Both
createCommentReaction
andgetReaction
calls correctly include thetenant
parameter, ensuring tenant-aware comment reaction operations. The parameter ordering (requester, tenant, then function-specific params) is consistent with the multi-tenancy pattern.src/domain/post/getRecommendedAggregated/getRecommendedAggregated.ts (3)
6-6
: LGTM: Tenant type import and parameter addition.The
Tenant
type import is properly added, and the function signature correctly includes the tenant parameter in a logical position after the requester.Also applies to: 12-12
16-16
: LGTM: Correct parameter decomposition for getRecommended call.The call properly destructures the
requester
andtenant
objects to passrequester.id
andtenant.id
as separate parameters, aligning with the updatedgetRecommended
function signature.
18-18
: LGTM: Tenant context propagated through aggregation.The
aggregate
function call correctly includes thetenant
parameter, ensuring that tenant context is maintained throughout the data aggregation process.src/domain/relation/getFollowersAggregated/getFollowersAggregated.ts (2)
5-5
: LGTM: Tenant type import and parameter addition.The
Tenant
type import is properly added, and the function signature correctly includes the tenant parameter in a logical position after the requester.Also applies to: 11-11
17-17
: LGTM: Tenant context correctly passed to aggregate function.The
aggregate
function call properly passes thetenant
parameter as the first argument, which aligns with the updated function signature shown in the relevant code snippets fromsrc/domain/relation/aggregate/aggregate.ts
.src/domain/creator/register/register.ts (2)
12-12
: LGTM: Function signature correctly updated with tenantId parameter.The addition of
tenantId
as the first parameter ensures tenant context is properly established for creator registration operations.
19-19
: LGTM: Tenant context properly propagated to dependent functions.Both
generateNickname
andcreate
function calls correctly pass thetenantId
parameter, ensuring tenant-scoped nickname uniqueness and proper data association. The parameter ordering (tenantId first) is consistent with the multi-tenancy pattern.Also applies to: 25-25
example.env (2)
26-26
: Well-designed change for multi-tenancy support.Converting from absolute URIs to relative paths enables dynamic URL construction based on tenant origins, which is essential for multi-tenant applications where different tenants may have different base URLs.
Also applies to: 31-31
66-66
: Good addition for tenant-specific database initialization.The new
MONGO_INIT_PATH
supports tenant-specific MongoDB initialization, which aligns perfectly with the multi-tenancy objectives.src/domain/notification/getByIdAggregated/getByIdAggregated.ts (1)
3-3
: Consistent tenant-aware implementation.The addition of the
tenant
parameter and its propagation to theaggregate
function follows the established pattern for multi-tenancy support. ThegetById
call appropriately remains unchanged as it likely fetches by unique identifier rather than requiring tenant scoping.Also applies to: 9-9, 13-13
src/domain/creator/getOthers/getOthers.ts (1)
9-9
: Critical tenant isolation implementation.The addition of
tenantId
parameter and the corresponding database query filtering is essential for preventing cross-tenant data leakage. The AND logic properly combines tenant scoping with the existing ID exclusion, ensuring creators can only access others within their tenant boundary.Also applies to: 11-16
src/domain/relation/exploreAggregated/exploreAggregated.ts (1)
5-5
: Proper tenant context propagation.The tenant parameter is correctly added to the function signature and properly propagated to both
explore
andaggregate
functions. The parameter ordering is consistent with the established pattern shown in the relevant code snippets.Also applies to: 12-12, 16-16, 18-18
src/domain/authentication/login/login.ts (2)
2-2
: Good practice with explicit type imports.Converting to explicit type imports improves clarity and helps with build optimization by clearly distinguishing runtime imports from type-only imports.
Also applies to: 6-6, 8-8
10-10
: Critical tenant-aware authentication implementation.The addition of the
tenant
parameter and its proper usage in bothgetCreatorByEmail
andregisterCreator
ensures that user lookup and registration are properly scoped to the tenant boundary. This prevents cross-tenant user access and maintains proper data isolation in the authentication flow.Also applies to: 12-12, 15-15
src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
1-19
: LGTM: Well-structured imports and validation schema.The imports are properly organized, the cookie name follows conventions, and the URL validation schema is correctly configured with the required flag.
76-84
: LGTM: Proper validation implementation.The validation logic correctly uses the schema and throws appropriate errors for invalid origins.
src/integrations/authentication/implementations/openid/OpenID.ts (2)
19-19
: LGTM: Configuration property renamed for clarity.The rename from
redirectUri
toredirectPath
better reflects the usage of relative paths in the multi-tenant architecture.
55-57
: LGTM: Proper URL construction for multi-tenant support.The addition of the origin parameter and URL construction using
new URL()
correctly handles dynamic redirect URLs for different tenants.src/integrations/runtime/middlewares/TenantMiddleware.ts (4)
6-14
: LGTM: Clean middleware structure with configurable tenant path.The class structure is well-designed with appropriate caching mechanism and configurable tenant resolution path.
16-21
: LGTM: Clear request routing logic.The conditional routing between tenant fetching and regular request handling is well-implemented and easy to understand.
45-56
: LGTM: Proper tenant context injection.The method correctly injects cached tenant data into request arguments when available, allowing graceful degradation when tenant data isn't cached.
58-61
: LGTM: Consistent origin extraction pattern.The method follows the same pattern as other middleware files. The type assertion is safe given that OriginMiddleware validates and sets the origin header before this middleware runs.
src/integrations/runtime/middlewares/AuthenticationMiddleware.ts (5)
24-32
: LGTM: Parameter naming updated for consistency.The rename from
redirectUrl
toredirectPath
aligns with the multi-tenant architecture changes and maintains consistency across the codebase.
51-57
: LGTM: Origin-aware login URL generation.The method correctly extracts the origin and passes it to the identity provider for dynamic login URL generation based on the requesting tenant.
63-76
: LGTM: Improved session management with proper cleanup.Excellent improvements:
- Origin-aware session creation
- Proper session cleanup on failure (logout if response is not 200)
- Early return prevents processing failed authentications
These changes improve error handling and prevent orphaned sessions.
223-226
: LGTM: Proper origin-aware redirect URL construction.The method correctly constructs redirect URLs using the origin and relative path with proper URL handling via the URL constructor.
228-231
: LGTM: Consistent origin extraction pattern.The new method follows the established pattern for origin extraction across middleware files and safely assumes the header is present due to OriginMiddleware validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
test/domain/authentication/login.spec.ts (1)
21-21
: Fix test description to match actual function signature.The test description shows
.login(identity, tenant)
but the actual function signature islogin(tenant: Tenant, identity: Identity)
with tenant as the first parameter.- describe('.login(identity, tenant)', () => + describe('.login(tenant, identity)', () =>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (86)
docker/mongodb/init.js
(1 hunks)src/domain/authentication/login/login.ts
(1 hunks)src/domain/creator/aggregate/types.ts
(1 hunks)src/domain/creator/create/types.ts
(1 hunks)src/domain/creator/create/validateData.ts
(2 hunks)src/domain/creator/generateNickname/generateNickname.ts
(1 hunks)src/domain/creator/generateNickname/retrieveByNickname.ts
(1 hunks)src/domain/creator/generateNickname/retrieveByStartNickname.ts
(1 hunks)src/domain/creator/getByEmail/getByEmail.ts
(1 hunks)src/domain/creator/getById/CreatorNotFound.ts
(1 hunks)src/domain/creator/getById/getById.ts
(1 hunks)src/domain/creator/getByIdAggregated/getByIdAggregated.ts
(1 hunks)src/domain/creator/getByNickname/getByNickname.ts
(1 hunks)src/domain/creator/getByNicknameAggregated/getByNicknameAggregated.ts
(1 hunks)src/domain/creator/getMe/getMe.ts
(1 hunks)src/domain/creator/getMeAggregated/getMeAggregated.ts
(1 hunks)src/domain/creator/getOthers/getOthers.ts
(1 hunks)src/domain/creator/register/register.ts
(1 hunks)src/domain/creator/types.ts
(1 hunks)src/domain/creator/updateNickname/retrieveByNickname.ts
(1 hunks)src/domain/creator/updateNickname/updateNickname.ts
(1 hunks)src/domain/notification/aggregate/aggregate.ts
(1 hunks)src/domain/notification/getByIdAggregated/getByIdAggregated.ts
(1 hunks)src/domain/notification/getRecentAggregated/getRecentAggregated.ts
(1 hunks)src/domain/post/aggregate/aggregate.ts
(1 hunks)src/domain/post/create/create.ts
(1 hunks)src/domain/post/create/createData.ts
(1 hunks)src/domain/post/create/types.ts
(1 hunks)src/domain/post/create/validateData.ts
(2 hunks)src/domain/post/createWithComic/createWithComic.ts
(1 hunks)src/domain/post/createWithComment/createWithComment.ts
(1 hunks)src/domain/post/explore/explore.ts
(1 hunks)src/domain/post/explore/retrieveData.ts
(1 hunks)src/domain/post/exploreAggregated/exploreAggregated.ts
(1 hunks)src/domain/post/getByCreatorAggregated/getByCreatorAggregated.ts
(1 hunks)src/domain/post/getByFollowingAggregated/getByFollowingAggregated.ts
(1 hunks)src/domain/post/getById/getById.ts
(1 hunks)src/domain/post/getByIdAggregated/getByIdAggregated.ts
(1 hunks)src/domain/post/getByParent/getByParent.ts
(1 hunks)src/domain/post/getByParentAggregated/getByParentAggregated.ts
(1 hunks)src/domain/post/getRecommended/getRecommended.ts
(1 hunks)src/domain/post/getRecommendedAggregated/getRecommendedAggregated.ts
(1 hunks)src/domain/post/remove/remove.ts
(3 hunks)src/domain/post/types.ts
(1 hunks)src/domain/rating/toggle/toggle.ts
(1 hunks)src/domain/relation/establish/establish.ts
(1 hunks)src/domain/relation/explore/explore.ts
(1 hunks)src/domain/relation/exploreAggregated/exploreAggregated.ts
(1 hunks)src/domain/relation/getAggregated/getAggregated.ts
(1 hunks)src/domain/relation/getFollowersAggregated/getFollowersAggregated.ts
(1 hunks)src/domain/relation/getFollowingAggregated/getFollowingAggregated.ts
(1 hunks)src/domain/tenant/getByOriginConverted/types.ts
(1 hunks)src/domain/tenant/getByOriginConverted/validateData.ts
(1 hunks)src/webui/editor/model/Bubble.ts
(1 hunks)src/webui/features/hooks/useAddComicPost.ts
(2 hunks)src/webui/features/hooks/useCreatePostComicReaction.ts
(1 hunks)src/webui/features/hooks/useCreatePostCommentReaction.ts
(1 hunks)src/webui/features/hooks/useCreator.ts
(2 hunks)src/webui/features/hooks/useCreatorFollowers.ts
(2 hunks)src/webui/features/hooks/useCreatorFollowing.ts
(2 hunks)src/webui/features/hooks/useCreatorPosts.ts
(2 hunks)src/webui/features/hooks/useEstablishRelation.ts
(1 hunks)src/webui/features/hooks/useExploreCreators.ts
(2 hunks)src/webui/features/hooks/useExplorePosts.ts
(2 hunks)src/webui/features/hooks/useHighlight.ts
(2 hunks)src/webui/features/hooks/useIdentify.ts
(2 hunks)src/webui/features/hooks/useNotifications.ts
(2 hunks)src/webui/features/hooks/usePost.ts
(2 hunks)src/webui/features/hooks/usePostReactions.ts
(2 hunks)src/webui/features/hooks/usePostsFollowing.ts
(2 hunks)src/webui/features/hooks/usePostsRecommended.ts
(2 hunks)src/webui/features/hooks/useRemovePost.ts
(2 hunks)src/webui/features/hooks/useTogglePostRating.ts
(1 hunks)src/webui/features/hooks/useUpdateNickname.ts
(2 hunks)test/domain/authentication/login.spec.ts
(2 hunks)test/domain/creator/updateNickname.spec.ts
(2 hunks)test/domain/notification/getRecentAggregated.spec.ts
(3 hunks)test/domain/post/createWithComic.spec.ts
(2 hunks)test/domain/post/getByFollowingAggregated.spec.ts
(2 hunks)test/domain/post/getRecommendedAggregated.spec.ts
(2 hunks)test/domain/post/remove.spec.ts
(2 hunks)test/domain/rating/toggle.spec.ts
(2 hunks)test/domain/relation/establish.spec.ts
(2 hunks)test/domain/relation/exploreAggregated.spec.ts
(3 hunks)test/domain/relation/getFollowersAggregated.spec.ts
(2 hunks)test/domain/relation/getFollowingAggregated.spec.ts
(2 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/webui/editor/model/Bubble.ts
- src/domain/tenant/getByOriginConverted/validateData.ts
🚧 Files skipped from review as they are similar to previous changes (75)
- src/domain/creator/types.ts
- src/domain/tenant/getByOriginConverted/types.ts
- src/domain/creator/generateNickname/retrieveByNickname.ts
- src/domain/authentication/login/login.ts
- src/domain/post/exploreAggregated/exploreAggregated.ts
- src/webui/features/hooks/useCreator.ts
- src/domain/post/aggregate/aggregate.ts
- src/domain/post/getByCreatorAggregated/getByCreatorAggregated.ts
- src/webui/features/hooks/useExplorePosts.ts
- src/webui/features/hooks/useAddComicPost.ts
- test/domain/creator/updateNickname.spec.ts
- src/webui/features/hooks/useUpdateNickname.ts
- src/webui/features/hooks/useCreatorFollowers.ts
- src/webui/features/hooks/usePost.ts
- src/domain/creator/create/types.ts
- src/domain/post/getById/getById.ts
- src/domain/post/explore/retrieveData.ts
- src/webui/features/hooks/useRemovePost.ts
- src/domain/creator/getByNickname/getByNickname.ts
- src/domain/notification/aggregate/aggregate.ts
- src/domain/creator/getMe/getMe.ts
- src/domain/creator/getByEmail/getByEmail.ts
- src/domain/creator/create/validateData.ts
- src/domain/creator/getById/CreatorNotFound.ts
- src/webui/features/hooks/useCreatorPosts.ts
- test/domain/post/remove.spec.ts
- src/domain/creator/generateNickname/retrieveByStartNickname.ts
- src/webui/features/hooks/useEstablishRelation.ts
- src/domain/creator/register/register.ts
- src/domain/post/types.ts
- src/webui/features/hooks/useExploreCreators.ts
- src/domain/creator/getMeAggregated/getMeAggregated.ts
- src/domain/relation/getFollowingAggregated/getFollowingAggregated.ts
- src/domain/creator/getOthers/getOthers.ts
- src/webui/features/hooks/useCreatorFollowing.ts
- src/webui/features/hooks/useHighlight.ts
- src/domain/creator/updateNickname/updateNickname.ts
- src/domain/post/getRecommended/getRecommended.ts
- src/domain/creator/getByIdAggregated/getByIdAggregated.ts
- src/domain/relation/establish/establish.ts
- src/domain/notification/getRecentAggregated/getRecentAggregated.ts
- src/domain/creator/aggregate/types.ts
- src/webui/features/hooks/useIdentify.ts
- src/domain/post/create/types.ts
- src/webui/features/hooks/usePostsFollowing.ts
- src/webui/features/hooks/useCreatePostCommentReaction.ts
- src/webui/features/hooks/usePostsRecommended.ts
- src/webui/features/hooks/useNotifications.ts
- src/domain/creator/getById/getById.ts
- src/domain/relation/getAggregated/getAggregated.ts
- test/domain/rating/toggle.spec.ts
- src/domain/post/getRecommendedAggregated/getRecommendedAggregated.ts
- test/domain/relation/establish.spec.ts
- src/domain/creator/getByNicknameAggregated/getByNicknameAggregated.ts
- src/domain/post/create/validateData.ts
- src/domain/relation/getFollowersAggregated/getFollowersAggregated.ts
- src/domain/post/getByParentAggregated/getByParentAggregated.ts
- src/domain/rating/toggle/toggle.ts
- src/domain/creator/updateNickname/retrieveByNickname.ts
- src/domain/post/create/createData.ts
- src/webui/features/hooks/useCreatePostComicReaction.ts
- src/domain/post/createWithComment/createWithComment.ts
- src/domain/creator/generateNickname/generateNickname.ts
- src/domain/post/create/create.ts
- src/domain/post/createWithComic/createWithComic.ts
- src/domain/relation/explore/explore.ts
- src/domain/relation/exploreAggregated/exploreAggregated.ts
- src/domain/post/remove/remove.ts
- src/domain/post/getByParent/getByParent.ts
- src/domain/post/explore/explore.ts
- src/webui/features/hooks/usePostReactions.ts
- src/webui/features/hooks/useTogglePostRating.ts
- src/domain/post/getByFollowingAggregated/getByFollowingAggregated.ts
- src/domain/notification/getByIdAggregated/getByIdAggregated.ts
- src/domain/post/getByIdAggregated/getByIdAggregated.ts
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/components/common/TenantContainer.tsx:20-20
Timestamp: 2025-07-23T11:11:01.974Z
Learning: In the Comify multi-tenant application, tenant IDs used in file paths (like CSS stylesheets in /assets/${tenant.id}.css) are protected by the repository architecture. Manipulating tenant IDs will either return no file or another legitimate tenant's stylesheet, but cannot be used for path traversal attacks since tenant IDs are controlled and validated at the domain level.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/domain/post/aggregate/aggregate.ts:16-16
Timestamp: 2025-07-22T20:42:32.320Z
Learning: In the Comify application, only Creator, Post, and Notification domains have tenantId fields. Comics and Comments are not directly accessible from the frontend and are only retrieved as part of post aggregation. Tenant scoping is enforced at the aggregate root level (Posts) rather than requiring every related entity to have tenant fields. This architectural pattern maintains tenant isolation at the entry point boundaries.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/domain/creator/types.ts:10-10
Timestamp: 2025-07-22T17:39:34.327Z
Learning: In multi-tenant creator domain operations, the update function is intentionally designed to be requester-scoped (self-update only) rather than tenant-scoped. Creators cannot switch tenants, and updates are performed by authenticated users on their own records only, eliminating the need for explicit tenant filtering in update operations.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/domain/creator/types.ts:10-10
Timestamp: 2025-07-22T17:39:34.327Z
Learning: In the creator domain, the base update function is designed as a low-level utility that performs database operations without tenant scoping. Security and tenant isolation are enforced at higher-level domain functions (like updateFullName, updateNickname) which ensure requesters can only modify their own records. The tenantId field is readonly to prevent modifications, and this separation of concerns creates a cleaner, more secure architecture.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/components/common/TenantContainer.tsx:14-24
Timestamp: 2025-07-23T11:08:07.428Z
Learning: In the TenantContainer component, the tenant CSS link is only added once per application session since the tenant is static and bound to the URL. The tenant only changes with full page reloads, so there's no need for cleanup logic to prevent CSS link accumulation within a single session.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: segments/bff.json:48-48
Timestamp: 2025-07-22T21:11:15.693Z
Learning: The tenant domain uses a two-tier data model: the database `DataModel` contains an `id` and an array of valid `origins`, while the public `Tenant` type returned by `getByOriginConverted` contains only `id` and `origin` (singular). This conversion serves as data minimization, where `id` is needed for stylesheet retrieval and `origin` is the validated browser-sent origin. This architecture implements proper security through data filtering at the public interface level.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/features/hooks/usePostsFollowing.ts:6-6
Timestamp: 2025-07-22T20:29:33.566Z
Learning: In Jitar applications, static imports of context objects like `tenant` from `^/domain/tenant` and `requester` from `^/domain/authentication` are intentionally static placeholders that serve as type-safe function signature matches. At runtime, these are dynamically replaced through Jitar's parameter injection mechanism via middleware (TenantMiddleware and AuthenticationMiddleware) using special parameter keys like `*tenant`. This allows for compile-time type safety while providing runtime flexibility for multi-tenant and authentication contexts.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/features/hooks/useExplorePosts.ts:14-18
Timestamp: 2025-07-23T08:26:06.202Z
Learning: In Jitar applications, the tenant context remains static throughout the application session lifecycle. It's determined by the URL/domain at application load time and only changes when the domain changes, which triggers a full application reload. Therefore, tenant dependencies in React hooks like useCallback don't need to be included in dependency arrays since they don't change during the component's lifecycle.
docker/mongodb/init.js (7)
Learnt from: basmasking
PR: #428
File: segments/bff.json:48-48
Timestamp: 2025-07-22T21:11:15.693Z
Learning: The tenant domain uses a two-tier data model: the database DataModel
contains an id
and an array of valid origins
, while the public Tenant
type returned by getByOriginConverted
contains only id
and origin
(singular). This conversion serves as data minimization, where id
is needed for stylesheet retrieval and origin
is the validated browser-sent origin. This architecture implements proper security through data filtering at the public interface level.
Learnt from: basmasking
PR: #428
File: src/domain/post/aggregate/aggregate.ts:16-16
Timestamp: 2025-07-22T20:42:32.320Z
Learning: In the Comify application, only Creator, Post, and Notification domains have tenantId fields. Comics and Comments are not directly accessible from the frontend and are only retrieved as part of post aggregation. Tenant scoping is enforced at the aggregate root level (Posts) rather than requiring every related entity to have tenant fields. This architectural pattern maintains tenant isolation at the entry point boundaries.
Learnt from: basmasking
PR: #428
File: src/webui/components/common/TenantContainer.tsx:20-20
Timestamp: 2025-07-23T11:11:01.974Z
Learning: In the Comify multi-tenant application, tenant IDs used in file paths (like CSS stylesheets in /assets/${tenant.id}.css) are protected by the repository architecture. Manipulating tenant IDs will either return no file or another legitimate tenant's stylesheet, but cannot be used for path traversal attacks since tenant IDs are controlled and validated at the domain level.
Learnt from: basmasking
PR: #428
File: src/domain/tenant/getByOrigin/getByOrigin.ts:9-9
Timestamp: 2025-07-22T20:53:29.380Z
Learning: In the tenant domain, getByOrigin
is an internal utility function that is not directly callable from external code. It can only be accessed through the public getByOriginConverted
function, which performs proper input validation using a schema that requires the origin to be a valid URL. This follows an architectural pattern where validation occurs at the public interface level rather than being duplicated in internal utility functions.
Learnt from: basmasking
PR: #428
File: src/domain/creator/types.ts:10-10
Timestamp: 2025-07-22T17:39:34.327Z
Learning: In the creator domain, the base update function is designed as a low-level utility that performs database operations without tenant scoping. Security and tenant isolation are enforced at higher-level domain functions (like updateFullName, updateNickname) which ensure requesters can only modify their own records. The tenantId field is readonly to prevent modifications, and this separation of concerns creates a cleaner, more secure architecture.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
test/domain/post/getRecommendedAggregated.spec.ts (3)
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/domain/post/aggregate/aggregate.ts:16-16
Timestamp: 2025-07-22T20:42:32.320Z
Learning: In the Comify application, only Creator, Post, and Notification domains have tenantId fields. Comics and Comments are not directly accessible from the frontend and are only retrieved as part of post aggregation. Tenant scoping is enforced at the aggregate root level (Posts) rather than requiring every related entity to have tenant fields. This architectural pattern maintains tenant isolation at the entry point boundaries.
test/domain/post/getByFollowingAggregated.spec.ts (1)
Learnt from: basmasking
PR: #428
File: src/domain/post/aggregate/aggregate.ts:16-16
Timestamp: 2025-07-22T20:42:32.320Z
Learning: In the Comify application, only Creator, Post, and Notification domains have tenantId fields. Comics and Comments are not directly accessible from the frontend and are only retrieved as part of post aggregation. Tenant scoping is enforced at the aggregate root level (Posts) rather than requiring every related entity to have tenant fields. This architectural pattern maintains tenant isolation at the entry point boundaries.
test/domain/post/createWithComic.spec.ts (5)
Learnt from: basmasking
PR: #428
File: src/domain/post/aggregate/aggregate.ts:16-16
Timestamp: 2025-07-22T20:42:32.320Z
Learning: In the Comify application, only Creator, Post, and Notification domains have tenantId fields. Comics and Comments are not directly accessible from the frontend and are only retrieved as part of post aggregation. Tenant scoping is enforced at the aggregate root level (Posts) rather than requiring every related entity to have tenant fields. This architectural pattern maintains tenant isolation at the entry point boundaries.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: segments/bff.json:48-48
Timestamp: 2025-07-22T21:11:15.693Z
Learning: The tenant domain uses a two-tier data model: the database DataModel
contains an id
and an array of valid origins
, while the public Tenant
type returned by getByOriginConverted
contains only id
and origin
(singular). This conversion serves as data minimization, where id
is needed for stylesheet retrieval and origin
is the validated browser-sent origin. This architecture implements proper security through data filtering at the public interface level.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/usePostsFollowing.ts:6-6
Timestamp: 2025-07-22T20:29:33.566Z
Learning: In Jitar applications, static imports of context objects like tenant
from ^/domain/tenant
and requester
from ^/domain/authentication
are intentionally static placeholders that serve as type-safe function signature matches. At runtime, these are dynamically replaced through Jitar's parameter injection mechanism via middleware (TenantMiddleware and AuthenticationMiddleware) using special parameter keys like *tenant
. This allows for compile-time type safety while providing runtime flexibility for multi-tenant and authentication contexts.
test/domain/authentication/login.spec.ts (4)
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/usePostsFollowing.ts:6-6
Timestamp: 2025-07-22T20:29:33.566Z
Learning: In Jitar applications, static imports of context objects like tenant
from ^/domain/tenant
and requester
from ^/domain/authentication
are intentionally static placeholders that serve as type-safe function signature matches. At runtime, these are dynamically replaced through Jitar's parameter injection mechanism via middleware (TenantMiddleware and AuthenticationMiddleware) using special parameter keys like *tenant
. This allows for compile-time type safety while providing runtime flexibility for multi-tenant and authentication contexts.
Learnt from: basmasking
PR: #428
File: segments/bff.json:48-48
Timestamp: 2025-07-22T21:11:15.693Z
Learning: The tenant domain uses a two-tier data model: the database DataModel
contains an id
and an array of valid origins
, while the public Tenant
type returned by getByOriginConverted
contains only id
and origin
(singular). This conversion serves as data minimization, where id
is needed for stylesheet retrieval and origin
is the validated browser-sent origin. This architecture implements proper security through data filtering at the public interface level.
test/domain/relation/exploreAggregated.spec.ts (2)
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
Learnt from: basmasking
PR: #428
File: src/webui/features/hooks/useAddComicPost.ts:7-7
Timestamp: 2025-07-22T21:04:44.466Z
Learning: The Comify project uses index resolution extensively with index.ts files for each domain feature. These index files commonly re-export default exports from internal modules as named exports (e.g., export { default as tenant } from './tenant'
), allowing for consistent named import syntax like import { tenant } from '^/domain/tenant'
while maintaining modular organization.
🧬 Code Graph Analysis (8)
test/domain/post/getRecommendedAggregated.spec.ts (2)
src/domain/post/getRecommendedAggregated/getRecommendedAggregated.ts (1)
getRecommendedAggregated
(12-21)test/domain/post/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)
test/domain/notification/getRecentAggregated.spec.ts (2)
src/domain/notification/getRecentAggregated/getRecentAggregated.ts (1)
getRecentAggregated
(12-21)test/domain/notification/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)
test/domain/post/getByFollowingAggregated.spec.ts (3)
src/domain/post/getByFollowingAggregated/getByFollowingAggregated.ts (1)
getByFollowingAggregated
(12-21)test/domain/post/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)test/domain/post/fixtures/requesters.fixture.ts (1)
REQUESTERS
(7-14)
test/domain/relation/getFollowersAggregated.spec.ts (2)
test/domain/relation/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)test/domain/relation/fixtures/values.fixture.ts (1)
VALUES
(2-23)
test/domain/post/createWithComic.spec.ts (2)
src/domain/post/createWithComic/createWithComic.ts (1)
createWithComic
(8-13)test/domain/post/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)
test/domain/authentication/login.spec.ts (5)
src/domain/authentication/login/login.ts (1)
login
(10-27)test/domain/authentication/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)test/domain/authentication/fixtures/identities.fixture.ts (1)
IDENTITIES
(6-64)test/domain/authentication/fixtures/values.fixture.ts (1)
VALUES
(2-81)src/domain/creator/generateNickname/TooManySimilarNicknames.ts (1)
TooManySimilarNicknames
(4-10)
test/domain/relation/exploreAggregated.spec.ts (5)
src/domain/relation/explore/explore.ts (1)
explore
(10-22)test/domain/relation/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)src/domain/definitions.ts (1)
SortOrders
(6-9)src/domain/relation/definitions.ts (1)
SortOrders
(8-8)test/domain/relation/fixtures/values.fixture.ts (1)
VALUES
(2-23)
test/domain/relation/getFollowingAggregated.spec.ts (2)
test/domain/relation/fixtures/tenants.fixture.ts (1)
TENANTS
(4-4)test/domain/relation/fixtures/values.fixture.ts (1)
VALUES
(2-23)
🔇 Additional comments (19)
docker/mongodb/init.js (2)
2-2
: LGTM! Correct database switching syntax.The use of
getSiblingDB('comify')
properly switches to the application database for initialization.
3-9
: LGTM! Well-structured tenant initialization for local development.The tenant document correctly follows the established two-tier data model with
_id
andorigins
array. Including both ports 3000 and 5173 effectively supports different local development scenarios (Node.js server and Vite dev server).test/domain/notification/getRecentAggregated.spec.ts (3)
6-6
: LGTM! Import updated correctly for tenant support.The addition of
TENANTS
to the imports is consistent with the multi-tenancy implementation and aligns with the function signature changes.
20-20
: LGTM! Function call updated correctly for tenant-first signature.The parameter order correctly reflects the updated function signature with tenant as the first parameter.
39-39
: LGTM! Consistent parameter ordering maintained.The second function call correctly follows the same tenant-first parameter pattern, maintaining consistency across the test cases.
test/domain/post/getByFollowingAggregated.spec.ts (2)
4-4
: Import update correctly adds TENANTS fixture.The addition of
TENANTS
to the import statement properly supports the tenant-aware function signature.
18-18
: Function call correctly updated for tenant-aware signature.The
getByFollowingAggregated
call now properly passesTENANTS.default
as the first parameter, matching the new function signature that requires a tenant context.test/domain/post/getRecommendedAggregated.spec.ts (2)
5-5
: Import statement properly updated for tenant support.The addition of
TENANTS
to the fixtures import correctly provides the tenant context needed for the updated function signature.
19-19
: Function call correctly updated with tenant parameter.The
getRecommendedAggregated
call now properly includesTENANTS.default
as the first argument, aligning with the tenant-aware function signature.test/domain/post/createWithComic.spec.ts (2)
9-9
: Import correctly extended to include tenant fixtures.The addition of
TENANTS
to the import statement properly supports the tenant-awarecreateWithComic
function.
23-23
: Function call updated correctly for tenant context.The
createWithComic
call now properly passesTENANTS.default
as the first parameter, matching the updated function signature that requires tenant context.test/domain/authentication/login.spec.ts (2)
7-7
: Import statement correctly updated with TENANTS fixture.The addition of
TENANTS
to the import supports the tenant-aware login function signature.
25-68
: All login function calls correctly updated with tenant parameter.All test cases properly pass
TENANTS.default
as the first argument to thelogin
function, correctly implementing the tenant-aware function signature.test/domain/relation/getFollowersAggregated.spec.ts (2)
6-6
: Import statement properly updated to include TENANTS.The addition of
TENANTS
to the fixtures import correctly provides tenant context for the function call.
17-17
: Function call correctly updated with tenant parameter.The
getFollowers
call now properly includesTENANTS.default
as the first argument, implementing the tenant-aware function signature.test/domain/relation/getFollowingAggregated.spec.ts (2)
6-6
: LGTM: Tenant fixture import added correctly.The addition of
TENANTS
to the import statement is consistent with the multi-tenancy refactor and provides the necessary tenant context for the updated test.
17-17
: LGTM: Function call updated correctly for tenant-aware architecture.The addition of
TENANTS.default
as the first parameter correctly implements the updated function signature that requires tenant context for proper data scoping. The parameter order follows the expected pattern of tenant, requester, and other arguments.test/domain/relation/exploreAggregated.spec.ts (2)
7-7
: LGTM: Tenant fixture import added correctly.The addition of
TENANTS
to the import statement properly provides the tenant context fixture needed for the updated test cases.
18-18
: LGTM: All function calls updated consistently for tenant-aware architecture.All test cases correctly add
TENANTS.default
as the first parameter to theexplore
function calls, properly implementing the updated function signature that requires tenant context. The parameter positioning is consistent and preserves the original test logic across all test scenarios.Also applies to: 27-27, 33-33, 40-40, 47-47
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
23-49
: LGTM! Solid middleware logic with proper validation flow.The middleware correctly implements the origin extraction and validation flow. The non-null assertion on line 39 is safe since
validateOriginValue
would throw if origin is undefined.Consider adding a comment to clarify the non-null assertion:
this.#validateOriginValue(origin); + // Origin is guaranteed to be defined after validation request.setHeader('origin', origin!);
56-74
: Consider using more robust cookie parsing.The manual cookie parsing works for basic cases but could be improved for edge cases where cookie values contain special characters.
Consider using a more robust approach:
#getOriginFromCookie(request: Request): string | undefined { const header = request.getHeader('cookie'); if (header === undefined) { return; } - for (const cookie of header.split(';')) - { - const [key, value] = cookie.split('='); - - if (key.trim() === ORIGIN_COOKIE_NAME) - { - return value?.trim(); - } - } + for (const cookie of header.split(';')) + { + const equalIndex = cookie.indexOf('='); + if (equalIndex === -1) continue; + + const key = cookie.substring(0, equalIndex).trim(); + const value = cookie.substring(equalIndex + 1).trim(); + + if (key === ORIGIN_COOKIE_NAME) + { + return value; + } + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
docker-compose.yml
(1 hunks)example.env
(2 hunks)segments/bff.json
(3 hunks)segments/notification.json
(0 hunks)src/domain/notification/getById/getById.ts
(0 hunks)src/domain/notification/getById/index.ts
(0 hunks)src/domain/notification/getByIdAggregated/getByIdAggregated.ts
(0 hunks)src/domain/notification/getByIdAggregated/index.ts
(0 hunks)src/integrations/runtime/middlewares/OriginMiddleware.ts
(1 hunks)
💤 Files with no reviewable changes (5)
- segments/notification.json
- src/domain/notification/getById/index.ts
- src/domain/notification/getByIdAggregated/index.ts
- src/domain/notification/getById/getById.ts
- src/domain/notification/getByIdAggregated/getByIdAggregated.ts
✅ Files skipped from review due to trivial changes (1)
- docker-compose.yml
🚧 Files skipped from review as they are similar to previous changes (2)
- example.env
- segments/bff.json
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/components/common/TenantContainer.tsx:20-20
Timestamp: 2025-07-23T11:11:01.974Z
Learning: In the Comify multi-tenant application, tenant IDs used in file paths (like CSS stylesheets in /assets/${tenant.id}.css) are protected by the repository architecture. Manipulating tenant IDs will either return no file or another legitimate tenant's stylesheet, but cannot be used for path traversal attacks since tenant IDs are controlled and validated at the domain level.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/domain/post/aggregate/aggregate.ts:16-16
Timestamp: 2025-07-22T20:42:32.320Z
Learning: In the Comify application, only Creator, Post, and Notification domains have tenantId fields. Comics and Comments are not directly accessible from the frontend and are only retrieved as part of post aggregation. Tenant scoping is enforced at the aggregate root level (Posts) rather than requiring every related entity to have tenant fields. This architectural pattern maintains tenant isolation at the entry point boundaries.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/domain/creator/types.ts:10-10
Timestamp: 2025-07-22T17:39:34.327Z
Learning: In multi-tenant creator domain operations, the update function is intentionally designed to be requester-scoped (self-update only) rather than tenant-scoped. Creators cannot switch tenants, and updates are performed by authenticated users on their own records only, eliminating the need for explicit tenant filtering in update operations.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/domain/creator/types.ts:10-10
Timestamp: 2025-07-22T17:39:34.327Z
Learning: In the creator domain, the base update function is designed as a low-level utility that performs database operations without tenant scoping. Security and tenant isolation are enforced at higher-level domain functions (like updateFullName, updateNickname) which ensure requesters can only modify their own records. The tenantId field is readonly to prevent modifications, and this separation of concerns creates a cleaner, more secure architecture.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/components/common/TenantContainer.tsx:14-24
Timestamp: 2025-07-23T11:08:07.428Z
Learning: In the TenantContainer component, the tenant CSS link is only added once per application session since the tenant is static and bound to the URL. The tenant only changes with full page reloads, so there's no need for cleanup logic to prevent CSS link accumulation within a single session.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: segments/bff.json:48-48
Timestamp: 2025-07-22T21:11:15.693Z
Learning: The tenant domain uses a two-tier data model: the database `DataModel` contains an `id` and an array of valid `origins`, while the public `Tenant` type returned by `getByOriginConverted` contains only `id` and `origin` (singular). This conversion serves as data minimization, where `id` is needed for stylesheet retrieval and `origin` is the validated browser-sent origin. This architecture implements proper security through data filtering at the public interface level.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/features/hooks/usePostsFollowing.ts:6-6
Timestamp: 2025-07-22T20:29:33.566Z
Learning: In Jitar applications, static imports of context objects like `tenant` from `^/domain/tenant` and `requester` from `^/domain/authentication` are intentionally static placeholders that serve as type-safe function signature matches. At runtime, these are dynamically replaced through Jitar's parameter injection mechanism via middleware (TenantMiddleware and AuthenticationMiddleware) using special parameter keys like `*tenant`. This allows for compile-time type safety while providing runtime flexibility for multi-tenant and authentication contexts.
Learnt from: basmasking
PR: MaskingTechnology/comify#428
File: src/webui/features/hooks/useExplorePosts.ts:14-18
Timestamp: 2025-07-23T08:26:06.202Z
Learning: In Jitar applications, the tenant context remains static throughout the application session lifecycle. It's determined by the URL/domain at application load time and only changes when the domain changes, which triggers a full application reload. Therefore, tenant dependencies in React hooks like useCallback don't need to be included in dependency arrays since they don't change during the component's lifecycle.
src/integrations/runtime/middlewares/OriginMiddleware.ts (3)
Learnt from: basmasking
PR: #428
File: src/domain/tenant/getByOrigin/getByOrigin.ts:9-9
Timestamp: 2025-07-22T20:53:29.380Z
Learning: In the tenant domain, getByOrigin
is an internal utility function that is not directly callable from external code. It can only be accessed through the public getByOriginConverted
function, which performs proper input validation using a schema that requires the origin to be a valid URL. This follows an architectural pattern where validation occurs at the public interface level rather than being duplicated in internal utility functions.
Learnt from: basmasking
PR: #428
File: segments/bff.json:48-48
Timestamp: 2025-07-22T21:11:15.693Z
Learning: The tenant domain uses a two-tier data model: the database DataModel
contains an id
and an array of valid origins
, while the public Tenant
type returned by getByOriginConverted
contains only id
and origin
(singular). This conversion serves as data minimization, where id
is needed for stylesheet retrieval and origin
is the validated browser-sent origin. This architecture implements proper security through data filtering at the public interface level.
Learnt from: basmasking
PR: #428
File: src/domain/post/create/types.ts:6-6
Timestamp: 2025-07-22T20:50:22.314Z
Learning: The Comify application uses a custom validation architecture where domain validation logic is decoupled from external validation libraries through an integrations layer. The current implementation uses Zod (src/integrations/validation/implementations/zod/Zod.ts) but can be easily switched to other validation libraries. Domain validation requirements remain consistent regardless of the underlying validation library, with validation schemas defined using custom validation functions like requiredIdValidation.
🔇 Additional comments (2)
src/integrations/runtime/middlewares/OriginMiddleware.ts (2)
1-19
: LGTM! Well-structured imports and validation schema.The imports are appropriate, the cookie name follows conventions, and the validation schema correctly enforces URL validation for the origin parameter.
86-89
: Verify cookie security settings work in all environments.The cookie security settings are appropriate for production but may cause issues in development environments without HTTPS due to the
SameSite=None; Secure
combination.Consider adding environment-specific cookie settings or ensure development uses HTTPS. You may want to verify this works correctly in your development setup.
Fixes #375
Changes proposed in this pull request:
@MaskingTechnology/comify