Skip to content

Conversation

sosweetham
Copy link
Member

@sosweetham sosweetham commented Aug 2, 2025

Description of change

evoting setup

Issue Number

n/a

Type of change

  • New (a change which implements a new feature)

How the change has been tested

n/a

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

New Features

  • Introduced user authentication and registration pages, including login, logout, and register flows.
  • Added a protected application layout that enforces authentication and redirects unauthenticated users with a mandatory disclaimer acceptance.
  • Implemented a poll creation form with expanded voting modes ("normal", "point", "rank") and visibility options ("public", "private") featuring enhanced UI.
  • Added a navigation component with improved accessibility and integration with authentication state.
  • Introduced a backend API with user, poll, and vote management, including poll creation, voting, and result retrieval.
  • Added database schema and entities for users, polls, votes, and authentication, along with migration scripts.
  • Provided Docker Compose and TypeORM configurations for local development and database management.
  • Added JWT utilities for token signing and verification.
  • Integrated a TypeORM adapter for authentication data persistence.
  • Added authentication middleware and route guards for API security.

Bug Fixes

  • Improved validation and error handling in poll creation and voting flows.

Style

  • Applied consistent formatting and styling across UI components and configuration files.

Chores

  • Added and updated package dependencies for both frontend and backend.
  • Included scripts and configuration files for project setup, development, and database reset.

@sosweetham sosweetham requested a review from coodos as a code owner August 2, 2025 13:47
Copy link
Contributor

coderabbitai bot commented Aug 2, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces a comprehensive eVoting platform and API backend. It adds new authentication, poll, and voting logic, TypeORM entity definitions, migrations, and utility modules for JWT and TypeORM integration. The frontend receives new authentication pages, navigation, enhanced poll creation, and refactored UI components. Some legacy plugins are removed and configuration files are added or updated for Docker, TypeScript, and package management.

Changes

Cohort / File(s) Change Summary
API Backend: Core Setup & Auth
platforms/evoting-api/package.json, platforms/evoting-api/tsconfig.json, platforms/evoting-api/src/index.ts, platforms/evoting-api/src/auth.ts, platforms/evoting-api/src/utils/typeorm-adapter.ts, platforms/evoting-api/src/utils/jwt.ts, platforms/evoting-api/reset.sh
Adds backend project scaffolding, TypeScript config, Express server setup, BetterAuth integration with TypeORM adapter, JWT utility, and a database reset script.
API Backend: Entities & Migrations
platforms/evoting-api/src/database/entities/*, platforms/evoting-api/src/database/data-source.ts, platforms/evoting-api/src/database/migrations/1754132648735-migration.ts, platforms/evoting-api/src/types/express.d.ts
Introduces TypeORM entities for users, sessions, accounts, verifications, polls, votes, and legacy social features; sets up migrations and Express type augmentation.
API Backend: Polls & Voting
platforms/evoting-api/src/controllers/poll.controller.ts, platforms/evoting-api/src/services/poll.service.ts, platforms/evoting-api/src/middleware/auth.ts
Implements poll and voting logic, validation, controller endpoints, and authentication middleware.
API Backend: Legacy Social Features
platforms/evoting-api/src/database/old/entities/*, platforms/evoting-api/src/database/old/migrations/*
Adds legacy entities and migrations for chat, posts, comments, and social relationships.
Frontend: Auth & Navigation
platforms/eVoting/src/app/(auth)/login/page.tsx, platforms/eVoting/src/app/(auth)/logout/page.tsx, platforms/eVoting/src/app/(auth)/register/page.tsx, platforms/eVoting/src/components/navigation.tsx, platforms/eVoting/src/lib/auth-client.ts, platforms/eVoting/src/app/(app)/layout.tsx
Adds login, logout, and registration pages; refactors navigation to use Next.js and new auth client; introduces authenticated layout.
Frontend: Poll Creation
platforms/eVoting/src/app/(app)/create/page.tsx
Expands poll creation schema to support new modes and visibility, updates UI, and simplifies form handling.
Frontend: UI Components & Config
platforms/eVoting/src/components/ui/card.tsx, platforms/eVoting/src/components/ui/dropdown-menu.tsx, platforms/eVoting/tsconfig.json, platforms/eVoting/package.json, platforms/eVoting/src/components/ui/dialog.tsx
Applies formatting/style updates to UI components, updates dependencies, refines TypeScript and package configurations, and removes dialog close button.
DevOps & Infrastructure
evoting.compose.yml, infrastructure/control-panel/project.inlang/.gitignore
Adds Docker Compose config for Postgres and a .gitignore for cache.
Removed: Inlang Plugins
infrastructure/control-panel/project.inlang/cache/plugins/2sy648wh9sugi, infrastructure/control-panel/project.inlang/cache/plugins/ygx0uiahq6uw
Removes two inlang SDK/plugin files implementing message format and parsing logic.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Frontend (eVoting)
  participant AuthClient
  participant API Server
  participant Database

  User->>Frontend (eVoting): Accesses protected page
  Frontend (eVoting)->>AuthClient: Check session
  alt Not authenticated
    Frontend (eVoting)->>User: Redirect to /login
    User->>Frontend (eVoting): Submits login form
    Frontend (eVoting)->>AuthClient: signIn(email, password)
    AuthClient->>API Server: POST /api/auth/*
    API Server->>Database: Query user credentials
    Database-->>API Server: User record
    API Server-->>AuthClient: Auth token/session
    AuthClient-->>Frontend (eVoting): Session established
    Frontend (eVoting)->>User: Redirect to app
  else Authenticated
    Frontend (eVoting)->>User: Render app layout
  end
Loading
sequenceDiagram
  participant User
  participant Frontend (eVoting)
  participant API Server
  participant Database

  User->>Frontend (eVoting): Submits poll creation form
  Frontend (eVoting)->>API Server: POST /poll (with poll data)
  API Server->>Database: Insert poll record
  Database-->>API Server: Poll created
  API Server-->>Frontend (eVoting): Poll confirmation

  User->>Frontend (eVoting): Casts vote
  Frontend (eVoting)->>API Server: POST /poll/:id/vote (with vote data)
  API Server->>Database: Validate & insert vote
  Database-->>API Server: Vote recorded
  API Server-->>Frontend (eVoting): Vote confirmation
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • sosweetham
  • coodos

Poem

🐇
New features bloom in code’s fresh spring,
Polls and votes and users bring,
Auth flows hop with tokens bright,
Entities line up left and right.
Docker hums, migrations run,
UI’s polished, work well done—
A rabbit’s joy: release begun!

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/evoting

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 74

♻️ Duplicate comments (1)
platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1)

1-20: Duplicate migration exists in pictique-api.

This migration is nearly identical to platforms/pictique-api/src/database/migrations/1749281568709-migration.ts. Consider whether this code duplication is intentional or if these should be consolidated.

The migration logic itself appears correct for converting from direct message recipients to a chat-based model.

🧹 Nitpick comments (32)
infrastructure/control-panel/project.inlang/.gitignore (1)

1-1: Explicitly target the directory with a trailing slash

Appending / clarifies that the ignore rule applies to the cache directory rather than any file named cache.

-cache
+cache/
evoting.compose.yml (1)

11-12: Consider conditional port exposure.

Exposing PostgreSQL port 5432 directly may not be necessary if the application only connects via Docker network. Consider making it conditional.

        ports:
-            - "5432:5432"
+            - "${POSTGRES_PORT:-5432}:5432"

This allows disabling external access by setting POSTGRES_PORT="" in production.

platforms/evoting-api/src/database/entities/User.ts (1)

17-18: Consider using varchar for image field.

Using text type for image URLs may be inefficient. Consider using varchar with appropriate length limit.

-    @Column("text", { name: "image", nullable: true })
+    @Column("varchar", { name: "image", length: 500, nullable: true })
platforms/evoting-api/src/database/entities/Verification.ts (1)

8-12: Consider adding constraints to identifier and value fields.

For verification entities, you might want to add constraints like uniqueness on identifier or length limits on value depending on the verification type (email codes, phone OTP, etc.).

Consider adding appropriate constraints based on your verification requirements:

-    @Column("text", { name: "identifier", nullable: false })
+    @Column("varchar", { name: "identifier", length: 255, nullable: false })
     identifier: string;

-    @Column("text", { name: "value", nullable: false })
+    @Column("varchar", { name: "value", length: 255, nullable: false })
     value: string;
platforms/eVoting/src/app/(app)/layout.tsx (2)

16-20: Add loading state protection and consider infinite redirect scenarios.

The authentication logic is correct, but consider adding protection against edge cases where the session state might oscillate.

 useEffect(() => {
-    if (!session.data && !session.isPending) {
+    if (!session.data && !session.isPending && router) {
         router.push("/login");
     }
 }, [session.data, session.isPending, router]);

22-24: Enhance loading UI for better user experience.

Consider replacing the basic loading text with a proper loading component or skeleton UI for better user experience.

 if (session.isPending) {
-    return <div>Loading...</div>; // Optional: show loading UI
+    return (
+        <div className="flex items-center justify-center min-h-screen">
+            <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
+        </div>
+    );
 }
platforms/evoting-api/src/database/old/migrations/1749561069022-migration.ts (1)

7-7: Add length constraints to character varying columns.

The character varying columns lack length constraints which could lead to storage inefficiency and potential issues with very long strings.

-await queryRunner.query(`CREATE TABLE "__web3_id_mapping" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "localId" character varying NOT NULL, "metaEnvelopeId" character varying NOT NULL, "entityType" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_4c57c87c4ee60f42d9c6b0861c2" PRIMARY KEY ("id"))`);
+await queryRunner.query(`CREATE TABLE "__web3_id_mapping" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "localId" character varying(255) NOT NULL, "metaEnvelopeId" character varying(255) NOT NULL, "entityType" character varying(100) NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_4c57c87c4ee60f42d9c6b0861c2" PRIMARY KEY ("id"))`);
platforms/eVoting/src/app/(auth)/register/page.tsx (2)

48-48: Fix grammatical error in placeholder text.

-placeholder="Choose a email"
+placeholder="Choose an email"

36-36: Add error handling for missing images.

The hardcoded image sources could fail to load, breaking the UI. Consider adding fallback handling or using Next.js Image component.

-<img src="/Logo.png" alt="eVoting Logo" />
+<img src="/Logo.png" alt="eVoting Logo" onError={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }} />

Also applies to: 84-84

platforms/evoting-api/tsconfig.json (1)

4-4: Consider using ES modules for modern Node.js.

While CommonJS works fine, consider migrating to ES modules for better tree-shaking and modern JavaScript ecosystem compatibility:

-"module": "commonjs",
+"module": "ESNext",
+"moduleResolution": "bundler",

Note: This would require updating import/export syntax throughout the codebase and package.json configuration.

platforms/evoting-api/src/database/data-source.ts (1)

11-11: Verify the .env file path resolution.

The path resolution goes up 4 levels (../../../../.env) which assumes a specific directory structure. This could break if the file structure changes.

Consider using a more robust approach:

-config({ path: path.resolve(__dirname, "../../../../.env") });
+config(); // Uses process.cwd() by default, or specify NODE_ENV-based paths
platforms/evoting-api/src/middleware/auth.ts (1)

24-25: Consider caching user lookups for performance.

Each authenticated request triggers a database query to fetch the user. For high-traffic applications, this could become a performance bottleneck.

Consider implementing user caching or including essential user data in the JWT payload to reduce database hits.

platforms/evoting-api/src/database/entities/Session.ts (1)

11-12: Consider token field security implications.

Storing the full token in plain text could be a security risk if the database is compromised. Consider storing a hash of the token instead.

For enhanced security, consider hashing the token:

-@Column("text", { name: "token", nullable: false })
-token: string;
+@Column("text", { name: "tokenHash", nullable: false })
+tokenHash: string;

Then hash tokens before storage and compare hashes during validation.

platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1)

10-10: Consider CASCADE delete behavior for referential integrity.

The foreign key constraints use ON DELETE NO ACTION which may leave orphaned records. For a chat system, consider whether messages should be deleted when a chat is deleted.

-        await queryRunner.query(`ALTER TABLE "messages" ADD CONSTRAINT "FK_36bc604c820bb9adc4c75cd4115" FOREIGN KEY ("chatId") REFERENCES "chat"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
+        await queryRunner.query(`ALTER TABLE "messages" ADD CONSTRAINT "FK_36bc604c820bb9adc4c75cd4115" FOREIGN KEY ("chatId") REFERENCES "chat"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);

Also applies to: 17-17

platforms/evoting-api/src/database/old/migrations/1749032877158-migration.ts (1)

6-36: Consider breaking large migrations into smaller chunks.

This migration creates many tables and relationships in a single operation. For better maintainability and easier debugging, consider splitting this into smaller, focused migrations (e.g., core entities, then relationships, then indexes).

platforms/evoting-api/src/database/old/entities/Message.ts (2)

19-20: Consider specifying explicit foreign key column names.

While TypeORM will infer foreign key names, being explicit improves clarity and prevents potential issues during schema changes.

-    @ManyToOne(() => User)
+    @ManyToOne(() => User)
+    @JoinColumn({ name: "senderId" })
     sender!: User;

-    @ManyToOne(() => Chat, (e) => e.messages)
+    @ManyToOne(() => Chat, (e) => e.messages)
+    @JoinColumn({ name: "chatId" })
     chat!: Chat;

Also applies to: 25-26


22-23: Consider adding text length constraints for performance.

Large text fields without constraints can impact database performance. Consider adding a reasonable maximum length or using appropriate column type.

-    @Column("text")
+    @Column("text", { length: 10000 }) // or appropriate limit
     text!: string;
platforms/evoting-api/src/index.ts (2)

1-21: Clean up commented-out imports for better maintainability.

The active imports are well-structured, but the extensive commented-out imports create visual clutter and may confuse future developers about which features are actually implemented.

Consider removing commented-out imports or adding a clear TODO comment explaining the implementation plan:

-// import { AuthController } from "./controllers/AuthController";
-// import { CommentController } from "./controllers/CommentController";
-// import { MessageController } from "./controllers/MessageController";
-// import { PostController } from "./controllers/PostController";
-// import { UserController } from "./controllers/UserController";
-// import { WebhookController } from "./controllers/WebhookController";
+// TODO: Implement social media features (posts, comments, messages, webhooks)

52-137: Consider removing extensive commented-out route definitions.

This large block of commented code (85+ lines) creates maintenance overhead and confusion about implemented features. Consider either implementing these routes or removing them to keep the codebase clean.

If these routes are planned for future implementation, consider:

  1. Moving them to a separate documentation file
  2. Creating a TODO list in the README
  3. Implementing them incrementally in separate PRs

This will improve code readability and reduce the chance of merge conflicts.

platforms/evoting-api/src/database/entities/Poll.ts (1)

31-32: Consider limitations of simple-array storage for options.

The simple-array column type stores options as comma-separated values, which could cause issues if option text contains commas. For a more robust solution, consider using JSON storage or a separate PollOption entity.

-@Column("simple-array")
-options: string[]; // stored as comma-separated values
+@Column("json")
+options: string[]; // stored as JSON array

Or for more complex poll options in the future:

@OneToMany(() => PollOption, (option) => option.poll)
options: PollOption[];
platforms/evoting-api/src/database/entities/Account.ts (1)

1-51: Consider adding indexes for performance optimization

Add indexes on frequently queried columns like userId, accountId, and providerId to improve query performance.

Add indexes to the entity:

+import { Column, Entity, Index } from "typeorm";

 @Entity("account")
+@Index(["userId"])
+@Index(["accountId", "providerId"])
 export class Account {
platforms/evoting-api/src/database/entities/Vote.ts (1)

19-22: Fix misleading comment for RankVoteData

The comment states "1 = top pick, 2 = next, etc." but the type definition shows points: number, which is inconsistent. Based on the context, this should clarify the ranking system.

 export type RankVoteData = {
     option: string;
-    points: number; // 1 = top pick, 2 = next, etc.
+    rank: number; // 1 = top pick, 2 = second choice, etc.
 }[];
platforms/eVoting/src/components/navigation.tsx (1)

103-109: Use Next.js Link component for logout consistency

For consistency with other navigation items and to benefit from Next.js prefetching, use the Link component for logout navigation.

-                                        <DropdownMenuItem asChild>
-                                            <a
-                                                href="/logout"
-                                                className="flex items-center w-full"
-                                            >
-                                                <LogOut className="w-4 h-4 mr-2" />
-                                                Logout
-                                            </a>
-                                        </DropdownMenuItem>
+                                        <DropdownMenuItem asChild>
+                                            <Link
+                                                href="/logout"
+                                                className="flex items-center w-full"
+                                            >
+                                                <LogOut className="w-4 h-4 mr-2" />
+                                                Logout
+                                            </Link>
+                                        </DropdownMenuItem>

Apply the same change to the mobile menu logout link at lines 216-224.

Also applies to: 216-224

platforms/eVoting/src/app/(app)/create/page.tsx (2)

92-94: Implement poll creation API call

The form submission handler is empty. The TODO comment indicates this needs implementation.

Would you like me to help implement the API call to create a poll? Based on the codebase structure, this would likely call the /polls endpoint with the form data.


325-326: Consider using stable keys instead of array indices

While the comment acknowledges the use of array indices as keys, this can cause issues with form state when options are reordered. Consider generating stable IDs for each option.

You could maintain option objects with IDs instead of just strings:

type OptionItem = { id: string; value: string };
const [options, setOptions] = useState<OptionItem[]>([
  { id: crypto.randomUUID(), value: "" },
  { id: crypto.randomUUID(), value: "" }
]);

Then use option.id as the key instead of the index.

platforms/evoting-api/src/utils/typeorm-adapter.ts (1)

286-317: Consider pagination limits for findMany

The findMany method defaults to 100 records but this might be too high for some use cases.

             const result = await repository.find({
                 where: findOptions,
-                take: limit || 100,
+                take: Math.min(limit || 20, 100), // Cap at 100, default to 20
                 skip: offset || 0,

This prevents potential performance issues from large result sets while still allowing flexibility.

infrastructure/web3-adapter/src/evault/evault.js (1)

127-128: Remove or explain the biome-ignore comment

The biome-ignore comment should either be removed or include a proper explanation.

-        // biome-ignore lint/style/noNonNullAssertion: <explanation>
+        // lastError is guaranteed to be set because we only reach here after at least one attempt
         throw lastError;
platforms/evoting-api/src/database/old/entities/User.ts (1)

35-36: Clarify the purpose of the "ename" field.

The field name ename is ambiguous. Consider using a more descriptive name like externalName, evaultName, or whatever it represents in your domain model.

infrastructure/web3-adapter/src/mapper/mapper.js (4)

1-5: Use ES modules instead of CommonJS for consistency.

The file uses CommonJS exports while the TypeORM entities use ES modules. Consider using ES modules throughout the codebase for consistency.

-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.getValueByPath = getValueByPath;
-exports.fromGlobal = fromGlobal;
-exports.toGlobal = toGlobal;
+export { getValueByPath, fromGlobal, toGlobal };

43-46: Improve string parsing logic for robustness.

The current parsing logic using includes and split is fragile and could fail with nested parentheses or edge cases.

Consider using a regex pattern for more robust parsing:

-    if (value.includes("(") && value.includes(")")) {
-        value = value.split("(")[1].split(")")[0];
-    }
+    const match = value.match(/\(([^)]+)\)/);
+    if (match) {
+        value = match[1];
+    }

220-224: Ensure consistent null handling in async operations.

The code uses nullish coalescing (??) inconsistently. Array mapping returns undefined while single values might return null.

 if (Array.isArray(value)) {
-    value = await Promise.all(value.map(async (v) => (await mappingStore.getGlobalId(v)) ?? undefined));
+    value = await Promise.all(value.map(async (v) => {
+        const globalId = await mappingStore.getGlobalId(v);
+        return globalId ?? null;
+    }));
 }
 else {
-    value = (await mappingStore.getGlobalId(value)) ?? undefined;
+    value = (await mappingStore.getGlobalId(value)) ?? null;
 }

234-234: Remove or update the source map reference.

The source map file reference at the end suggests this is compiled code. If this is the source file, remove the source map comment. If it's compiled output, it shouldn't be in the source repository.

-//# sourceMappingURL=mapper.js.map
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa4458e and 093a692.

⛔ Files ignored due to path filters (9)
  • infrastructure/web3-adapter/src/db/index.js.map is excluded by !**/*.map
  • infrastructure/web3-adapter/src/db/mapping.db.js.map is excluded by !**/*.map
  • infrastructure/web3-adapter/src/evault/evault.js.map is excluded by !**/*.map
  • infrastructure/web3-adapter/src/index.js.map is excluded by !**/*.map
  • infrastructure/web3-adapter/src/mapper/mapper.js.map is excluded by !**/*.map
  • infrastructure/web3-adapter/src/mapper/mapper.types.js.map is excluded by !**/*.map
  • platforms/eVoting/public/Logo.png is excluded by !**/*.png
  • platforms/eVoting/public/W3DS.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (50)
  • evoting.compose.yml (1 hunks)
  • infrastructure/control-panel/project.inlang/.gitignore (1 hunks)
  • infrastructure/control-panel/project.inlang/cache/plugins/2sy648wh9sugi (0 hunks)
  • infrastructure/control-panel/project.inlang/cache/plugins/ygx0uiahq6uw (0 hunks)
  • infrastructure/web3-adapter/src/db/index.js (1 hunks)
  • infrastructure/web3-adapter/src/db/mapping.db.js (1 hunks)
  • infrastructure/web3-adapter/src/evault/evault.js (1 hunks)
  • infrastructure/web3-adapter/src/index.js (1 hunks)
  • infrastructure/web3-adapter/src/mapper/mapper.js (1 hunks)
  • infrastructure/web3-adapter/src/mapper/mapper.types.js (1 hunks)
  • platforms/eVoting/package.json (1 hunks)
  • platforms/eVoting/src/app/(app)/create/page.tsx (7 hunks)
  • platforms/eVoting/src/app/(app)/layout.tsx (1 hunks)
  • platforms/eVoting/src/app/(auth)/login/page.tsx (1 hunks)
  • platforms/eVoting/src/app/(auth)/logout/page.tsx (1 hunks)
  • platforms/eVoting/src/app/(auth)/register/page.tsx (1 hunks)
  • platforms/eVoting/src/components/navigation.tsx (8 hunks)
  • platforms/eVoting/src/components/ui/card.tsx (1 hunks)
  • platforms/eVoting/src/components/ui/dropdown-menu.tsx (1 hunks)
  • platforms/eVoting/src/lib/auth-client.ts (1 hunks)
  • platforms/eVoting/tsconfig.json (2 hunks)
  • platforms/evoting-api/package.json (1 hunks)
  • platforms/evoting-api/reset.sh (1 hunks)
  • platforms/evoting-api/src/auth.ts (1 hunks)
  • platforms/evoting-api/src/controllers/poll.controller.ts (1 hunks)
  • platforms/evoting-api/src/database/data-source.ts (1 hunks)
  • platforms/evoting-api/src/database/entities/Account.ts (1 hunks)
  • platforms/evoting-api/src/database/entities/Poll.ts (1 hunks)
  • platforms/evoting-api/src/database/entities/Session.ts (1 hunks)
  • platforms/evoting-api/src/database/entities/User.ts (1 hunks)
  • platforms/evoting-api/src/database/entities/Verification.ts (1 hunks)
  • platforms/evoting-api/src/database/entities/Vote.ts (1 hunks)
  • platforms/evoting-api/src/database/migrations/1754132648735-migration.ts (1 hunks)
  • platforms/evoting-api/src/database/old/entities/Chat.ts (1 hunks)
  • platforms/evoting-api/src/database/old/entities/Comment.ts (1 hunks)
  • platforms/evoting-api/src/database/old/entities/Message.ts (1 hunks)
  • platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (1 hunks)
  • platforms/evoting-api/src/database/old/entities/Post.ts (1 hunks)
  • platforms/evoting-api/src/database/old/entities/User.ts (1 hunks)
  • platforms/evoting-api/src/database/old/migrations/1749032877158-migration.ts (1 hunks)
  • platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1 hunks)
  • platforms/evoting-api/src/database/old/migrations/1749283608071-migration.ts (1 hunks)
  • platforms/evoting-api/src/database/old/migrations/1749561069022-migration.ts (1 hunks)
  • platforms/evoting-api/src/index.ts (1 hunks)
  • platforms/evoting-api/src/middleware/auth.ts (1 hunks)
  • platforms/evoting-api/src/services/poll.service.ts (1 hunks)
  • platforms/evoting-api/src/types/express.d.ts (1 hunks)
  • platforms/evoting-api/src/utils/jwt.ts (1 hunks)
  • platforms/evoting-api/src/utils/typeorm-adapter.ts (1 hunks)
  • platforms/evoting-api/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (2)
  • infrastructure/control-panel/project.inlang/cache/plugins/ygx0uiahq6uw
  • infrastructure/control-panel/project.inlang/cache/plugins/2sy648wh9sugi
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: in the metastate prototype project, prefer using centralized type definitions from `$lib/types` over...
Learnt from: Sahil2004
PR: MetaState-Prototype-Project/prototype#193
File: platforms/metagram/src/lib/store/store.svelte.ts:0-0
Timestamp: 2025-06-07T04:59:24.520Z
Learning: In the MetaState prototype project, prefer using centralized type definitions from `$lib/types` over importing interfaces from component files for better type organization and to avoid circular dependencies.

Applied to files:

  • infrastructure/web3-adapter/src/mapper/mapper.types.js
🧬 Code Graph Analysis (18)
platforms/eVoting/src/app/(auth)/register/page.tsx (2)
platforms/eVoting/src/lib/auth-client.ts (1)
  • authClient (2-5)
platforms/eVoting/src/components/ui/card.tsx (2)
  • Card (80-80)
  • CardHeader (81-81)
platforms/eVoting/src/components/ui/dropdown-menu.tsx (1)
infrastructure/eid-wallet/src/lib/utils/mergeClasses.ts (1)
  • cn (4-6)
platforms/eVoting/src/components/ui/card.tsx (1)
infrastructure/eid-wallet/src/lib/utils/mergeClasses.ts (1)
  • cn (4-6)
platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (2)
platforms/evoting-api/src/database/old/entities/User.ts (1)
  • Entity (15-77)
platforms/evoting-api/src/database/old/entities/Message.ts (1)
  • Entity (14-39)
platforms/evoting-api/src/middleware/auth.ts (2)
platforms/evoting-api/src/utils/jwt.ts (1)
  • verifyToken (9-15)
platforms/evoting-api/src/database/data-source.ts (1)
  • AppDataSource (25-25)
platforms/evoting-api/src/index.ts (2)
platforms/evoting-api/src/database/data-source.ts (1)
  • AppDataSource (25-25)
platforms/evoting-api/src/auth.ts (1)
  • auth (5-11)
platforms/evoting-api/src/database/entities/Session.ts (3)
platforms/evoting-api/src/database/entities/Account.ts (1)
  • Entity (3-51)
platforms/evoting-api/src/database/entities/User.ts (1)
  • Entity (3-33)
platforms/evoting-api/src/database/entities/Verification.ts (1)
  • Entity (3-22)
platforms/eVoting/src/app/(auth)/logout/page.tsx (1)
platforms/eVoting/src/lib/auth-client.ts (1)
  • authClient (2-5)
platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1)
platforms/pictique-api/src/database/migrations/1749281568709-migration.ts (2)
  • Migration1749281568709 (3-20)
  • up (6-11)
platforms/eVoting/src/components/navigation.tsx (3)
platforms/eVoting/src/app/(app)/page.tsx (1)
  • Home (28-354)
platforms/eVoting/src/lib/auth-client.ts (1)
  • authClient (2-5)
infrastructure/eid-wallet/src/lib/ui/Button/index.ts (1)
  • Icon (5-5)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
platforms/evoting-api/src/services/poll.service.ts (1)
  • PollService (52-200)
platforms/evoting-api/src/database/old/entities/Post.ts (3)
platforms/evoting-api/src/database/old/entities/Chat.ts (1)
  • Entity (14-38)
platforms/evoting-api/src/database/old/entities/Comment.ts (1)
  • Entity (5-35)
platforms/evoting-api/src/database/old/entities/User.ts (1)
  • Entity (15-77)
platforms/evoting-api/src/database/old/entities/Comment.ts (2)
platforms/evoting-api/src/database/old/entities/Post.ts (1)
  • Entity (5-41)
platforms/evoting-api/src/database/old/entities/User.ts (1)
  • Entity (15-77)
platforms/evoting-api/src/database/entities/Vote.ts (1)
platforms/evoting-api/src/database/entities/Poll.ts (1)
  • Entity (11-48)
platforms/evoting-api/src/database/old/entities/Message.ts (3)
platforms/evoting-api/src/database/old/entities/Chat.ts (1)
  • Entity (14-38)
platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (1)
  • Entity (12-31)
platforms/evoting-api/src/database/old/entities/User.ts (1)
  • Entity (15-77)
infrastructure/web3-adapter/src/index.js (2)
infrastructure/web3-adapter/src/mapper/mapper.js (2)
  • result (49-49)
  • result (136-136)
infrastructure/web3-adapter/src/index.ts (1)
  • Web3Adapter (9-156)
platforms/evoting-api/src/database/old/entities/User.ts (5)
platforms/evoting-api/src/database/old/entities/Chat.ts (1)
  • Entity (14-38)
platforms/evoting-api/src/database/old/entities/Comment.ts (1)
  • Entity (5-35)
platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (1)
  • Entity (12-31)
platforms/evoting-api/src/database/old/entities/Post.ts (1)
  • Entity (5-41)
platforms/evoting-api/src/database/old/entities/Message.ts (1)
  • Entity (14-39)
infrastructure/web3-adapter/src/evault/evault.js (1)
infrastructure/web3-adapter/src/evault/evault.ts (1)
  • EVaultClient (118-387)
🪛 GitHub Actions: Check Lint
platforms/eVoting/package.json

[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Run 'pnpm install --no-frozen-lockfile' to update the lockfile.

🪛 GitHub Actions: Check Format
platforms/eVoting/package.json

[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Run 'pnpm install --no-frozen-lockfile' to update the lockfile.

🪛 GitHub Actions: Check Code
platforms/eVoting/package.json

[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Use 'pnpm install --no-frozen-lockfile' to bypass this in CI.

🔇 Additional comments (32)
platforms/eVoting/tsconfig.json (1)

4-8: LGTM! Formatting improvement enhances readability.

The multi-line array formatting makes the TypeScript configuration more readable and maintainable without changing any functional behavior. The compiler options are appropriate for a Next.js eVoting platform.

Also applies to: 26-28, 31-37, 38-40

platforms/evoting-api/src/auth.ts (1)

5-11: LGTM! Good authentication setup.

The authentication configuration follows good practices by using environment variables for trusted origins and enabling email/password authentication through the betterAuth library.

platforms/evoting-api/src/types/express.d.ts (1)

1-9: LGTM! Proper TypeScript declaration augmentation.

The Express namespace augmentation correctly extends the Request interface with the optional user property, following TypeScript best practices for declaration merging. This enables type-safe access to authenticated user data throughout the API.

platforms/eVoting/src/components/ui/dropdown-menu.tsx (1)

1-201: LGTM! Consistent formatting improvements.

The formatting changes improve code consistency with proper semicolon usage, indentation, and line breaks. The component logic and functionality remain unchanged, and the implementation follows React best practices with proper forwardRef usage and TypeScript typing.

platforms/eVoting/src/components/ui/card.tsx (2)

26-26: Note the padding reduction in CardHeader.

The padding was reduced from p-6 to p-4. Ensure this visual change aligns with the intended design specifications.


1-86: LGTM! Clean formatting improvements.

The formatting changes improve code consistency and readability. All card components maintain proper TypeScript typing and React forwardRef patterns.

platforms/eVoting/src/app/(app)/layout.tsx (1)

1-32: Enable server-side authentication in the eVoting API

The eVoting backend currently has its authentication imports and middleware commented out, leaving all endpoints unprotected. You should re-enable authMiddleware (and apply authGuard to individual routes as needed) to ensure sensitive operations cannot be accessed without a valid session.

• File: platforms/evoting-api/src/index.ts

  • Uncomment the import of authMiddleware/authGuard
  • Re-apply the middleware to all routes below

Suggested diff:

--- a/platforms/evoting-api/src/index.ts
+++ b/platforms/evoting-api/src/index.ts
@@
-// import { authGuard, authMiddleware } from "./middleware/auth";
+import { authGuard, authMiddleware } from "./middleware/auth";
@@
-// app.use(authMiddleware); // Apply auth middleware to all routes below
+app.use(authMiddleware); // Apply auth middleware to all routes below

Then, for any public route that should remain open, explicitly skip the guard; otherwise, add authGuard to protect individual handlers.

Likely an incorrect or invalid review comment.

platforms/evoting-api/tsconfig.json (1)

1-23: Configuration looks good for TypeORM backend.

The TypeScript configuration is well-suited for a TypeORM-based backend project. The decorator support and relaxed property initialization are appropriate for entity definitions.

platforms/evoting-api/src/database/data-source.ts (2)

16-16: LGTM: Synchronization disabled for production safety.

Good practice to disable synchronization in production environments to prevent accidental schema changes.


1-1: reflect-metadata is already imported at application entry point

The reflect-metadata import in data-source.ts can be safely ignored—it's loaded in your app bootstrap:

• Entry-point import:
platforms/evoting-api/src/index.ts:1 → import "reflect-metadata";

No changes needed here.

Likely an incorrect or invalid review comment.

platforms/evoting-api/src/database/old/entities/Chat.ts (2)

1-38: Question: Why is this entity in the "old" directory?

The file path suggests this is legacy code (platforms/evoting-api/src/database/old/entities/Chat.ts), but it's being added as a new file. This could indicate:

  1. Migration from old schema to new schema
  2. Accidentally placed in wrong directory
  3. Legacy code being reintroduced

Please clarify the intent and consider if this belongs in the main entities directory instead.


25-31: LGTM: Proper many-to-many relationship configuration.

The join table configuration is well-defined with explicit column names and references. This provides good control over the database schema.

platforms/evoting-api/src/middleware/auth.ts (2)

12-15: LGTM: Proper bearer token extraction with fallback.

The middleware correctly checks for the Bearer token format and gracefully continues without authentication if not present, which is appropriate for optional authentication middleware.


39-44: LGTM: Clean separation of concerns.

The authGuard function provides a clean way to enforce authentication on protected routes, with appropriate error response.

platforms/evoting-api/src/database/entities/Session.ts (2)

5-6: LGTM: Proper UUID primary key configuration.

The varchar length of 36 characters is appropriate for UUID format, and using string type is correct for TypeORM UUID handling.


28-32: LGTM: Appropriate nullable fields for session metadata.

IP address and user agent are correctly marked as nullable since they may not always be available or relevant.

platforms/evoting-api/package.json (1)

10-13: TypeORM migration scripts look correct.

The migration scripts properly reference the data source and follow TypeORM conventions. The script structure supports both generation and execution of migrations.

platforms/evoting-api/src/database/old/migrations/1749032877158-migration.ts (2)

6-36: Comprehensive schema creation looks well-designed.

The migration creates a solid foundation for social media functionality with proper relationships, indexing, and CASCADE behavior on join tables. The schema design follows good database practices.


1-4: Ignore mischaracterization of the “old” schema
The migrations and entities under platforms/evoting-api/src/database/old are for the legacy messaging feature (Chat, Comment, Message, etc.), not for eVoting. The file 1749032877158-migration.ts belongs to that legacy schema and doesn’t introduce any new eVoting tables. You can disregard the suggestion to fold these into the main schema.

Likely an incorrect or invalid review comment.

platforms/evoting-api/src/database/old/entities/Message.ts (1)

14-39: Entity structure follows good TypeORM patterns.

The Message entity is well-structured with appropriate relationships and follows the established patterns from other entities in the schema.

platforms/evoting-api/src/index.ts (2)

24-32: LGTM! Proper database initialization with error handling.

The database initialization follows TypeORM best practices with appropriate error handling and process termination on failure.


35-47: LGTM! Comprehensive CORS configuration.

The CORS setup properly handles authentication, webhooks, and various HTTP methods with appropriate fallback for development.

platforms/evoting-api/src/database/old/migrations/1749283608071-migration.ts (2)

3-30: LGTM! Well-structured migration with proper rollback support.

The migration correctly implements the transition from a simple isRead boolean to a granular per-user read status system. The SQL operations are properly ordered and the down migration correctly reverses all changes.


12-15: Good foreign key constraint design.

The different cascade behaviors are well-chosen:

  • message_read_status uses NO ACTION to preserve read receipt history
  • chat_participants uses CASCADE for automatic cleanup

This design maintains data integrity while supporting the expected business logic.

platforms/evoting-api/src/database/old/entities/Comment.ts (1)

5-35: LGTM! Well-designed Comment entity with proper relationships.

The entity structure follows TypeORM best practices:

  • Proper UUID primary key generation
  • Clear many-to-one relationships with User and Post
  • Explicit join table configuration for the likes relationship
  • Standard audit columns and archival flag

The relationships align well with the referenced User and Post entities.

platforms/evoting-api/src/database/migrations/1754132648735-migration.ts (1)

6-11: LGTM! Proper authentication schema setup.

The migration creates a solid foundation for the authentication system with appropriate table structures for better-auth integration:

  • Proper UUID column sizing (36 characters)
  • Appropriate timestamp defaults and nullable fields
  • Email verification with sensible default
platforms/evoting-api/src/database/entities/Poll.ts (1)

19-29: LGTM! Well-defined poll configuration enums.

The mode and visibility enums provide good flexibility:

  • Mode options support different voting mechanisms (normal choice, point allocation, ranking)
  • Visibility controls access appropriately
  • Sensible defaults for both enums
platforms/evoting-api/src/database/entities/Vote.ts (1)

51-59: Well-designed flexible vote data structure

The use of JSONB with discriminated union types (VoteDataByMode) provides excellent flexibility while maintaining type safety. This design elegantly handles different voting modes without requiring separate tables.

platforms/eVoting/src/components/navigation.tsx (1)

149-157: Good accessibility improvements

The addition of keyboard event handlers, proper ARIA labels, and role attributes to the mobile menu backdrop improves accessibility for keyboard and screen reader users.

platforms/eVoting/src/app/(app)/create/page.tsx (1)

126-291: Well-designed voting mode and visibility UI

The form provides an excellent user experience with:

  • Clear visual representation of voting modes with icons and descriptions
  • Intuitive radio button styling that highlights the selected option
  • Proper accessibility with label associations
  • Good use of Tailwind classes for consistent styling
platforms/evoting-api/src/database/old/entities/User.ts (2)

1-14: Clarify the purpose of the "old" directory structure.

This file is located in database/old/entities/, which suggests it might be deprecated or temporary. If this is intended for production use, consider moving it to the main entities directory. If it's deprecated, consider adding a deprecation comment or removing it entirely.


50-65: Join column naming is correct and needs no change

The joinColumn/inverseJoinColumn definitions in both relationships match your SQL migrations and JPA conventions:

  • platforms/evoting-api/src/database/old/entities/User.ts (lines 50–56) – user_followers table:
    • joinColumn user_id → this user’s id
    • inverseJoinColumn follower_id → each follower’s id
  • platforms/evoting-api/src/database/old/entities/User.ts (lines 58–65) – user_following table:
    • joinColumn user_id → this user’s id
    • inverseJoinColumn following_id → each followed user’s id

No changes required here.

Comment on lines +6 to +8
POSTGRES_USER: evoting
POSTGRES_PASSWORD: evoting
POSTGRES_DB: evoting
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Weak default credentials for database.

Using evoting as both username and password creates a security vulnerability, even in development environments. For an eVoting system, this is particularly concerning.

Consider using environment variables with stronger defaults:

        environment:
-            POSTGRES_USER: evoting
-            POSTGRES_PASSWORD: evoting
-            POSTGRES_DB: evoting
+            POSTGRES_USER: ${POSTGRES_USER:-evoting}
+            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-evoting_dev_password_123}
+            POSTGRES_DB: ${POSTGRES_DB:-evoting}

Or add a comment indicating this is for development only:

+    # WARNING: Development only - use strong credentials in production
    db:
        image: postgres:16
🤖 Prompt for AI Agents
In evoting.compose.yml around lines 6 to 8, the database credentials use weak
default values with POSTGRES_USER and POSTGRES_PASSWORD both set to "evoting".
To fix this, replace these hardcoded credentials with environment variables that
can be set externally to stronger, unique values. Alternatively, add a clear
comment indicating these credentials are for development only and should be
changed in production to improve security.

Comment on lines +15 to +27
"dependencies": {
"axios": "^1.6.7",
"better-auth": "^1.3.4",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"eventsource-polyfill": "^0.9.6",
"express": "^4.18.2",
"graphql-request": "^6.1.0",
"jsonwebtoken": "^9.0.2",
"pg": "^8.11.3",
"reflect-metadata": "^0.2.1",
"typeorm": "^0.3.24",
"uuid": "^9.0.1"
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify dependency versions for security and compatibility.

Several dependencies use caret ranges which could introduce breaking changes or security vulnerabilities. For a production voting system, consider pinning exact versions.


🏁 Script executed:

#!/bin/bash
# Check for known vulnerabilities in the specified dependency versions
npm audit --audit-level moderate --json

Length of output: 630


🌐 Web query:

Are there any known security vulnerabilities in better-auth version 1.3.4, jsonwebtoken version 9.0.2, or express version 4.18.2?

💡 Result:

Based on currently available vulnerability databases and recent security bulletins, here is the status for each specified package and version as of August 2025:

1. better-auth version 1.3.4
No known publicly disclosed security vulnerabilities have been identified for better-auth version 1.3.4 as of June 2025[1][9]. Most known issues, such as open redirect and cross-site scripting (XSS) flaws, affect versions prior to 1.1.21 and 1.1.16, respectively, but not 1.3.4[9]. Review of vulnerability statistics up to 2025 notes two open redirect-related vulnerabilities for the "Better Auth" product overall, but there is no direct evidence that version 1.3.4 is affected by any new or outstanding CVEs[1].

2. jsonwebtoken version 9.0.2
There are no known active vulnerabilities affecting jsonwebtoken version 9.0.2. The critical remote code execution vulnerability (CVE-2022-23529) was fully fixed by version 9.0.0, and no new CVEs have been disclosed for 9.x releases up to 9.0.2[2][6][10]. Previous dependency-related issues (such as a ReDoS vulnerability via [email protected]) are also resolved in 9.0.2[8]. Security monitoring platforms and public advisories consistently report [email protected] as free of known vulnerabilities[4].

3. express version 4.18.2
Express 4.18.2 is affected by at least two known vulnerabilities:

  • CVE-2024-29041 (Open Redirect): Express versions prior to 4.19.0 are subject to an open redirect vulnerability in the res.location() and res.redirect() methods, which can be exploited by bypassing URL allow lists via encoded or malformed URLs[3][7]. This flaw is fixed in Express 4.19.2 and later.
  • CVE-2024-52798 (as referenced in recent advisories): Additional issues have been flagged in dependency chains associated with Express 4.18.2[7]. The highest-reported severity is 7.5. Upgrading to 4.19.2 or 5.x is recommended[3][7].

In summary:

Citations:


Upgrade Express to ≥4.19.2 Due to Known Vulnerabilities

Express 4.18.2 is affected by CVE-2024-29041 (open redirect) and other issues; [email protected] and [email protected] have no known CVEs.

• platforms/evoting-api/package.json (Lines 15–27):
– Change
- "express": "^4.18.2"
+ "express": "^4.19.2"

• Add a lockfile (e.g., package-lock.json) and run npm audit to catch future issues.
• Consider pinning critical dependencies or using an npm shrinkwrap to avoid unintended upgrades.

🤖 Prompt for AI Agents
In platforms/evoting-api/package.json between lines 15 and 27, update the
express dependency version from "^4.18.2" to "^4.19.2" to address known security
vulnerabilities. After updating, generate a lockfile such as package-lock.json
by running npm install, then run npm audit to identify any other issues.
Consider pinning critical dependencies or using npm shrinkwrap to prevent
unintended upgrades in the future.

Comment on lines +8 to +10
DROP DATABASE IF EXISTS pic;
CREATE DATABASE pic;
EOF
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix inconsistent database name.

The database name pic doesn't match the eVoting context and appears to be from a different project. Based on the Docker Compose configuration, it should be evoting.

-DROP DATABASE IF EXISTS pic;
-CREATE DATABASE pic;
+DROP DATABASE IF EXISTS evoting;
+CREATE DATABASE evoting;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DROP DATABASE IF EXISTS pic;
CREATE DATABASE pic;
EOF
DROP DATABASE IF EXISTS evoting;
CREATE DATABASE evoting;
EOF
🤖 Prompt for AI Agents
In platforms/evoting-api/reset.sh around lines 8 to 10, the database name used
is `pic`, which is inconsistent with the eVoting project context. Replace all
instances of `pic` with `evoting` to align with the Docker Compose configuration
and project naming conventions.

Comment on lines +10 to +16
useEffect(() => {
const logout = async () => {
await authClient.signOut();
router.push("/login");
};
logout();
}, [router]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and loading state for better user experience.

The logout process lacks error handling and proper loading states, which could lead to poor user experience.

+import { useState } from "react";
+
 export default function LogoutPage() {
     const router = useRouter();
+    const [isLoggingOut, setIsLoggingOut] = useState(true);
+    const [error, setError] = useState<string | null>(null);

     useEffect(() => {
         const logout = async () => {
-            await authClient.signOut();
-            router.push("/login");
+            try {
+                await authClient.signOut();
+                router.push("/login");
+            } catch (err) {
+                setError("Failed to logout. Please try again.");
+                setIsLoggingOut(false);
+            }
         };
         logout();
     }, [router]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
const logout = async () => {
await authClient.signOut();
router.push("/login");
};
logout();
}, [router]);
import { useState } from "react";
export default function LogoutPage() {
const router = useRouter();
const [isLoggingOut, setIsLoggingOut] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const logout = async () => {
try {
await authClient.signOut();
router.push("/login");
} catch (err) {
setError("Failed to logout. Please try again.");
setIsLoggingOut(false);
}
};
logout();
}, [router]);
// ...rest of your component (e.g. render a spinner or error message)
}
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/logout/page.tsx around lines 10 to 16, the
logout function lacks error handling and does not manage a loading state. Add a
loading state variable to indicate when logout is in progress, and wrap the
signOut and router.push calls in a try-catch block to handle potential errors
gracefully. Update the UI or state accordingly to reflect loading and error
conditions for better user experience.

Comment on lines +18 to +24
return (
<div>
<h1>Logout</h1>
<p>You are being logged out.</p>
</div>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve logout UI with proper state feedback.

The current UI doesn't reflect the actual logout state and could be confusing to users.

     return (
         <div>
             <h1>Logout</h1>
-            <p>You are being logged out.</p>
+            {error ? (
+                <div>
+                    <p style={{ color: 'red' }}>{error}</p>
+                    <button onClick={() => router.push("/login")}>
+                        Go to Login
+                    </button>
+                </div>
+            ) : (
+                <p>You are being logged out...</p>
+            )}
         </div>
     );

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/logout/page.tsx around lines 18 to 24, the
logout UI lacks feedback on the logout process state, which may confuse users.
Enhance the component to include state management that reflects the logout
progress, such as showing a loading indicator while logging out and a
confirmation message once completed. Use React state or effects to track and
display these states clearly to improve user experience.

Comment on lines +17 to +30
const handleSubmit = async () => {
setError("");
const res = await authClient.signUp.email({
email,
name: displayName,
password,
});
if (res.error?.message) {
setError(res.error.message);
return;
}
console.log("Registration successful:", res.data);
router.push("/login");
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add form validation and loading state.

The registration form lacks input validation and loading state management, which could lead to poor user experience and invalid submissions.

+const [isLoading, setIsLoading] = useState(false);
+
+const validateForm = () => {
+    if (!email || !displayName || !password) {
+        setError("All fields are required");
+        return false;
+    }
+    if (!/\S+@\S+\.\S+/.test(email)) {
+        setError("Please enter a valid email address");
+        return false;
+    }
+    if (password.length < 8) {
+        setError("Password must be at least 8 characters long");
+        return false;
+    }
+    return true;
+};
+
 const handleSubmit = async () => {
     setError("");
+    
+    if (!validateForm()) return;
+    
+    setIsLoading(true);
     const res = await authClient.signUp.email({
         email,
         name: displayName,
         password,
     });
+    setIsLoading(false);
+    
     if (res.error?.message) {
         setError(res.error.message);
         return;
     }
-    console.log("Registration successful:", res.data);
     router.push("/login");
 };

And update the button:

-<Button className="w-full" onClick={handleSubmit}>
+<Button className="w-full" onClick={handleSubmit} disabled={isLoading}>
+    {isLoading ? "Creating Account..." : "Sign Up"}
-    Sign Up
 </Button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleSubmit = async () => {
setError("");
const res = await authClient.signUp.email({
email,
name: displayName,
password,
});
if (res.error?.message) {
setError(res.error.message);
return;
}
console.log("Registration successful:", res.data);
router.push("/login");
};
// Add loading state and form validation
const [isLoading, setIsLoading] = useState(false);
const validateForm = () => {
if (!email || !displayName || !password) {
setError("All fields are required");
return false;
}
if (!/\S+@\S+\.\S+/.test(email)) {
setError("Please enter a valid email address");
return false;
}
if (password.length < 8) {
setError("Password must be at least 8 characters long");
return false;
}
return true;
};
const handleSubmit = async () => {
setError("");
if (!validateForm()) return;
setIsLoading(true);
const res = await authClient.signUp.email({
email,
name: displayName,
password,
});
setIsLoading(false);
if (res.error?.message) {
setError(res.error.message);
return;
}
router.push("/login");
};
Suggested change
const handleSubmit = async () => {
setError("");
const res = await authClient.signUp.email({
email,
name: displayName,
password,
});
if (res.error?.message) {
setError(res.error.message);
return;
}
console.log("Registration successful:", res.data);
router.push("/login");
};
<Button
className="w-full"
onClick={handleSubmit}
disabled={isLoading}
>
{isLoading ? "Creating Account..." : "Sign Up"}
</Button>
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/register/page.tsx around lines 17 to 30, the
handleSubmit function lacks input validation and loading state management. Add
validation checks for email, displayName, and password before calling signUp to
prevent invalid submissions. Introduce a loading state variable to disable the
submit button and show a loading indicator while the async request is in
progress. Update the submit button to reflect the loading state and prevent
multiple submissions.

setError(res.error.message);
return;
}
console.log("Registration successful:", res.data);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove sensitive data from console logs.

Logging registration data to the console could expose sensitive information in production environments.

-console.log("Registration successful:", res.data);
+// Registration successful - redirecting to login
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log("Registration successful:", res.data);
// Registration successful - redirecting to login
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/register/page.tsx at line 28, remove the
console.log statement that outputs registration data, as it may expose sensitive
information. Instead, either eliminate the log entirely or replace it with a
non-sensitive confirmation message that does not include user data.

Comment on lines +2 to +5
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: "http://localhost:4000",
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace hardcoded localhost URL with environment-based configuration.

The hardcoded baseURL: "http://localhost:4000" will break in production and other environments.

-export const authClient = createAuthClient({
-    /** The base URL of the server (optional if you're using the same domain) */
-    baseURL: "http://localhost:4000",
-});
+export const authClient = createAuthClient({
+    /** The base URL of the server (optional if you're using the same domain) */
+    baseURL: process.env.NEXT_PUBLIC_AUTH_BASE_URL || "http://localhost:4000",
+});

Add NEXT_PUBLIC_AUTH_BASE_URL to your environment configuration files for different deployment environments.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: "http://localhost:4000",
});
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: process.env.NEXT_PUBLIC_AUTH_BASE_URL || "http://localhost:4000",
});
🤖 Prompt for AI Agents
In platforms/eVoting/src/lib/auth-client.ts around lines 2 to 5, the baseURL is
hardcoded to "http://localhost:4000", which will fail in production or other
environments. Replace the hardcoded URL with a reference to an environment
variable, such as process.env.NEXT_PUBLIC_AUTH_BASE_URL, to dynamically set the
baseURL based on the deployment environment. Ensure that
NEXT_PUBLIC_AUTH_BASE_URL is added to the environment configuration files for
all relevant environments.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review continued from previous batch...

Comment on lines 11 to 21
constructor(dbPath) {
// Ensure the directory exists
const fullPath = (0, node_path_1.join)(dbPath, "mappings.db");
this.db = new sqlite3_1.default.Database(fullPath);
// Promisify database methods
this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db));
this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db));
this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db));
// Initialize the database with the required tables
this.initialize();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Async initialization in constructor and missing directory creation

The constructor has several issues:

  1. The comment says "Ensure the directory exists" but no directory creation logic is present
  2. initialize() is an async method but called without await in the constructor, which could lead to race conditions
  3. No validation of the dbPath parameter

Apply this fix:

-    constructor(dbPath) {
-        // Ensure the directory exists
-        const fullPath = (0, node_path_1.join)(dbPath, "mappings.db");
-        this.db = new sqlite3_1.default.Database(fullPath);
+    constructor(dbPath) {
+        if (!dbPath) {
+            throw new Error("dbPath is required");
+        }
+        this.dbPath = dbPath;
+        this.db = null;
         // Promisify database methods
-        this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db));
-        this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db));
-        this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db));
-        // Initialize the database with the required tables
-        this.initialize();
+        this.runAsync = null;
+        this.getAsync = null;
+        this.allAsync = null;
     }
+
+    async ensureInitialized() {
+        if (this.db) return;
+        
+        const fs = require('node:fs/promises');
+        const path = require('node:path');
+        
+        // Ensure the directory exists
+        await fs.mkdir(this.dbPath, { recursive: true });
+        
+        const fullPath = path.join(this.dbPath, "mappings.db");
+        this.db = new sqlite3_1.default.Database(fullPath);
+        
+        // Promisify database methods
+        this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db));
+        this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db));
+        this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db));
+        
+        // Initialize the database with the required tables
+        await this.initialize();
+    }

Then ensure all public methods call await this.ensureInitialized() at the start.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 11 to 21, the
constructor lacks directory creation for the database path, calls the async
initialize() method without awaiting it, and does not validate the dbPath
parameter. Fix this by first validating dbPath to ensure it is a non-empty
string, then create the directory if it does not exist before opening the
database. Change initialize() to be awaited properly by moving async
initialization outside the constructor or by adding an internal flag and an
ensureInitialized() method that public methods can await before proceeding.
Update all public methods to call await this.ensureInitialized() at their start
to avoid race conditions.

Comment on lines 38 to 57
async storeMapping(params) {
// Validate inputs
if (!params.localId || !params.globalId) {
throw new Error("Invalid mapping parameters: all fields are required");
}
console.log("storing mapping g:l", params.globalId, params.localId);
// Check if mapping already exists
const existingMapping = await this.getGlobalId(params.localId);
if (existingMapping) {
return;
}
await this.runAsync(`INSERT INTO id_mappings (local_id, global_id)
VALUES (?, ?)`, [params.localId, params.globalId]);
const storedMapping = await this.getGlobalId(params.localId);
if (storedMapping !== params.globalId) {
console.log("storedMappingError", storedMapping, params.globalId);
console.error("Failed to store mapping");
return;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Race condition and silent failures in storeMapping

Several issues with this method:

  1. Race condition between checking existence and inserting
  2. Silent return when mapping exists (no indication to caller)
  3. Debug console.log statements should be removed
  4. Inefficient verification after insert

Consider using INSERT OR IGNORE and checking affected rows:

     async storeMapping(params) {
         // Validate inputs
         if (!params.localId || !params.globalId) {
             throw new Error("Invalid mapping parameters: all fields are required");
         }
-        console.log("storing mapping g:l", params.globalId, params.localId);
-        // Check if mapping already exists
-        const existingMapping = await this.getGlobalId(params.localId);
-        if (existingMapping) {
-            return;
-        }
-        await this.runAsync(`INSERT INTO id_mappings (local_id, global_id)
-                VALUES (?, ?)`, [params.localId, params.globalId]);
-        const storedMapping = await this.getGlobalId(params.localId);
-        if (storedMapping !== params.globalId) {
-            console.log("storedMappingError", storedMapping, params.globalId);
-            console.error("Failed to store mapping");
-            return;
-        }
+        
+        const result = await this.runAsync(
+            `INSERT OR IGNORE INTO id_mappings (local_id, global_id) VALUES (?, ?)`,
+            [params.localId, params.globalId]
+        );
+        
+        if (result.changes === 0) {
+            // Mapping already exists, check if it's the same
+            const existing = await this.getGlobalId(params.localId);
+            if (existing !== params.globalId) {
+                throw new Error(`Mapping conflict: localId ${params.localId} already mapped to ${existing}`);
+            }
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async storeMapping(params) {
// Validate inputs
if (!params.localId || !params.globalId) {
throw new Error("Invalid mapping parameters: all fields are required");
}
console.log("storing mapping g:l", params.globalId, params.localId);
// Check if mapping already exists
const existingMapping = await this.getGlobalId(params.localId);
if (existingMapping) {
return;
}
await this.runAsync(`INSERT INTO id_mappings (local_id, global_id)
VALUES (?, ?)`, [params.localId, params.globalId]);
const storedMapping = await this.getGlobalId(params.localId);
if (storedMapping !== params.globalId) {
console.log("storedMappingError", storedMapping, params.globalId);
console.error("Failed to store mapping");
return;
}
}
async storeMapping(params) {
// Validate inputs
if (!params.localId || !params.globalId) {
throw new Error("Invalid mapping parameters: all fields are required");
}
const result = await this.runAsync(
`INSERT OR IGNORE INTO id_mappings (local_id, global_id) VALUES (?, ?)`,
[params.localId, params.globalId]
);
if (result.changes === 0) {
// Mapping already exists, check if it's the same
const existing = await this.getGlobalId(params.localId);
if (existing !== params.globalId) {
throw new Error(
`Mapping conflict: localId ${params.localId} already mapped to ${existing}`
);
}
}
}
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js lines 38 to 57, fix the race
condition by replacing the existence check and insert with a single atomic
operation using "INSERT OR IGNORE" to avoid duplicate entries. Remove all
console.log debug statements. Instead of verifying the insert by querying again,
check the number of affected rows returned by the insert operation to confirm
success. Also, modify the method to return a clear indication (e.g., a boolean)
whether the mapping was stored or already existed, avoiding silent returns.

Comment on lines 61 to 75
async getGlobalId(localId) {
if (!localId) {
return null;
}
try {
const result = await this.getAsync(`SELECT global_id
FROM id_mappings
WHERE local_id = ?`, [localId]);
return result?.global_id ?? null;
}
catch (error) {
console.error("Error getting global ID:", error);
return null;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling to distinguish between not found and database errors

The current implementation swallows errors and returns null, making it impossible to distinguish between a missing mapping and a database error.

     async getGlobalId(localId) {
         if (!localId) {
             return null;
         }
-        try {
-            const result = await this.getAsync(`SELECT global_id
-                FROM id_mappings
-                WHERE local_id = ?`, [localId]);
-            return result?.global_id ?? null;
-        }
-        catch (error) {
-            console.error("Error getting global ID:", error);
-            return null;
-        }
+        const result = await this.getAsync(
+            `SELECT global_id FROM id_mappings WHERE local_id = ?`,
+            [localId]
+        );
+        return result?.global_id ?? null;
     }

Let errors propagate to the caller for proper handling.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getGlobalId(localId) {
if (!localId) {
return null;
}
try {
const result = await this.getAsync(`SELECT global_id
FROM id_mappings
WHERE local_id = ?`, [localId]);
return result?.global_id ?? null;
}
catch (error) {
console.error("Error getting global ID:", error);
return null;
}
}
async getGlobalId(localId) {
if (!localId) {
return null;
}
const result = await this.getAsync(
`SELECT global_id FROM id_mappings WHERE local_id = ?`,
[localId]
);
return result?.global_id ?? null;
}
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 61 to 75, the
getGlobalId method currently catches all errors and returns null, which hides
the difference between a missing record and a database error. Remove the
try-catch block so that database errors propagate to the caller, while still
returning null when no mapping is found by checking if the query result is
empty.

Comment on lines 79 to 92
async getLocalId(globalId) {
if (!globalId) {
return null;
}
try {
const result = await this.getAsync(`SELECT local_id
FROM id_mappings
WHERE global_id = ?`, [globalId]);
return result?.local_id ?? null;
}
catch (error) {
return null;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove error suppression for consistent error handling

Similar to getGlobalId, this method suppresses errors which prevents proper error handling.

     async getLocalId(globalId) {
         if (!globalId) {
             return null;
         }
-        try {
-            const result = await this.getAsync(`SELECT local_id
-                FROM id_mappings
-                WHERE global_id = ?`, [globalId]);
-            return result?.local_id ?? null;
-        }
-        catch (error) {
-            return null;
-        }
+        const result = await this.getAsync(
+            `SELECT local_id FROM id_mappings WHERE global_id = ?`,
+            [globalId]
+        );
+        return result?.local_id ?? null;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getLocalId(globalId) {
if (!globalId) {
return null;
}
try {
const result = await this.getAsync(`SELECT local_id
FROM id_mappings
WHERE global_id = ?`, [globalId]);
return result?.local_id ?? null;
}
catch (error) {
return null;
}
}
async getLocalId(globalId) {
if (!globalId) {
return null;
}
const result = await this.getAsync(
`SELECT local_id FROM id_mappings WHERE global_id = ?`,
[globalId]
);
return result?.local_id ?? null;
}
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 79 to 92, the
getLocalId method currently suppresses errors by catching them and returning
null, which prevents consistent error handling. Remove the try-catch block so
that any errors thrown during the database query propagate naturally, allowing
callers to handle them properly, similar to the getGlobalId method.

Comment on lines 122 to 129
close() {
try {
this.db.close();
}
catch (error) {
console.error("Error closing database connection:", error);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve database closure handling

The close method needs improvements:

  1. Should check if already closed
  2. Should nullify the db reference
  3. Remove console.error
     close() {
-        try {
-            this.db.close();
-        }
-        catch (error) {
-            console.error("Error closing database connection:", error);
-        }
+        if (this.db) {
+            this.db.close((err) => {
+                if (err) {
+                    throw new Error(`Failed to close database: ${err.message}`);
+                }
+            });
+            this.db = null;
+            this.runAsync = null;
+            this.getAsync = null;
+            this.allAsync = null;
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
close() {
try {
this.db.close();
}
catch (error) {
console.error("Error closing database connection:", error);
}
}
close() {
if (this.db) {
this.db.close((err) => {
if (err) {
throw new Error(`Failed to close database: ${err.message}`);
}
});
this.db = null;
this.runAsync = null;
this.getAsync = null;
this.allAsync = null;
}
}
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 122 to 129,
improve the close method by first checking if the database connection is already
closed before attempting to close it, then after closing, set the db reference
to null to avoid stale references, and replace the console.error with proper
error handling or logging mechanism as per project standards.

Comment on lines 21 to 26
if (res.error?.message) {
console.error("Login failed:", res.error.message);
return;
}
console.log("Login successful:", res.data);
router.push("/");
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove console logging of authentication data.

Logging authentication responses to console poses a security risk as it may expose sensitive user data or tokens.

-        if (res.error?.message) {
-            console.error("Login failed:", res.error.message);
-            return;
-        }
-        console.log("Login successful:", res.data);
+        if (res.error?.message) {
+            // TODO: Show user-friendly error message
+            return;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (res.error?.message) {
console.error("Login failed:", res.error.message);
return;
}
console.log("Login successful:", res.data);
router.push("/");
if (res.error?.message) {
// TODO: Show user-friendly error message
return;
}
router.push("/");
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx between lines 21 and 26,
remove all console logging statements that output authentication response data,
including both error and success logs, to prevent exposing sensitive user
information. Replace these logs with appropriate user feedback mechanisms or
silent handling without printing authentication details to the console.

Comment on lines +42 to +45
<div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
<span>Scan the QR using your</span>
<span className="font-bold underline">eID App</span>
<span>to login</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

UI text inconsistency with actual authentication method.

The UI mentions "Scan the QR using your eID App" but the actual implementation uses email/password authentication. This creates user confusion.

Either implement QR/eID authentication or update the UI text to match the email/password flow:

-                    <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
-                        <span>Scan the QR using your</span>
-                        <span className="font-bold underline">eID App</span>
-                        <span>to login</span>
-                    </div>
+                    <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
+                        <span>Enter your credentials to login</span>
+                    </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
<span>Scan the QR using your</span>
<span className="font-bold underline">eID App</span>
<span>to login</span>
<div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
<span>Enter your credentials to login</span>
</div>
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx around lines 42 to 45, the UI
text incorrectly instructs users to scan a QR code with the eID App, while the
actual authentication method is email/password. To fix this, update the UI text
to clearly describe the email/password login process instead of mentioning QR
code scanning or the eID App, ensuring the displayed instructions match the
implemented authentication flow.

Comment on lines +58 to +70
<Input
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
type="text"
/>
<Input
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
/>
<Button onClick={handleSubmit}>Submit</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation and improve error handling.

The form lacks client-side validation and proper error feedback to users.

+    const [error, setError] = useState("");
+    const [isLoading, setIsLoading] = useState(false);
+
     const handleSubmit = async () => {
+        setError("");
+        
+        if (!email || !password) {
+            setError("Please enter both email and password");
+            return;
+        }
+        
+        setIsLoading(true);
         const res = await authClient.signIn.email({
             email,
             password,
         });
+        setIsLoading(false);
+        
         if (res.error?.message) {
+            setError(res.error.message);
             return;
         }
         router.push("/");
     };

Add error display in the JSX:

+                    {error && (
+                        <div className="text-red-500 text-sm">{error}</div>
+                    )}
                     <Input
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Input
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
type="text"
/>
<Input
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
/>
<Button onClick={handleSubmit}>Submit</Button>
// --- at the top of your component, alongside the existing useState hooks:
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async () => {
setError("");
if (!email || !password) {
setError("Please enter both email and password");
return;
}
setIsLoading(true);
const res = await authClient.signIn.email({
email,
password,
});
setIsLoading(false);
if (res.error?.message) {
setError(res.error.message);
return;
}
router.push("/");
};
return (
<div>
{/* error message */}
{error && (
<div className="text-red-500 text-sm">{error}</div>
)}
<Input
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
type="text"
/>
<Input
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
/>
<Button onClick={handleSubmit}>
Submit
</Button>
</div>
);
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx around lines 58 to 70, the
input fields lack client-side validation and there is no error feedback shown to
users. Add validation logic to check the email format and password requirements
before submission. Implement state to track validation errors and display
appropriate error messages in the JSX near the inputs. Also, update the
handleSubmit function to prevent submission if validation fails and show
relevant error feedback to the user.

Comment on lines +31 to +32
// const { isAuthenticated, user } = useAuth();
const isAuthenticated = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove hardcoded authentication status

The isAuthenticated variable is hardcoded to true, which bypasses the actual authentication check from the session. This could expose authenticated UI to unauthenticated users.

-    // const { isAuthenticated, user } = useAuth();
-    const isAuthenticated = true;
+    const session = authClient.useSession();
+    const isAuthenticated = !!session.data?.user;

Then update line 40 to remove the duplicate session declaration:

-    const session = authClient.useSession();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// const { isAuthenticated, user } = useAuth();
const isAuthenticated = true;
// Replace the hardcoded auth flag with a real session check
- // const { isAuthenticated, user } = useAuth();
- const isAuthenticated = true;
+ const session = authClient.useSession();
+ const isAuthenticated = !!session.data?.user;
// … later in the file, remove the duplicate declaration
// (drop this line)
// const session = authClient.useSession();
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/navigation.tsx around lines 31 to 32, remove
the hardcoded assignment of isAuthenticated to true and uncomment the original
line that destructures isAuthenticated and user from useAuth(). Then, at line
40, remove the duplicate session declaration to avoid redundancy and potential
conflicts.

{session.data?.user?.name ||
session.data?.user?.email ||
"User"}
username
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove stray "username" text

There's a stray "username" text that will be rendered in the UI.

                                                {session.data?.user?.name ||
                                                    session.data?.user?.email ||
                                                    "User"}
-                                                username
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
username
{session.data?.user?.name ||
session.data?.user?.email ||
"User"}
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/navigation.tsx at line 212, there is a stray
"username" text that will be rendered unintentionally in the UI. Remove this
standalone "username" text from the JSX to prevent it from appearing in the
rendered output.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
platforms/evoting-api/src/controllers/poll.controller.ts (1)

16-44: Missing authentication validation in createPoll.

The method doesn't validate that the user is authenticated before creating a poll. The service expects a userId parameter, but if req.user is undefined, the poll will be created without an owner.

Add authentication check:

 async createPoll(req: Request, res: Response) {
+    if (!req.user || !req.user.id) {
+        return res.status(401).json({ error: "Authentication required" });
+    }
+
     const { title, mode, visibility, options, deadline } = req.body;

Note: The parameter passing issue from the previous review has been correctly addressed - the controller now properly destructures the request body and passes individual parameters to the service.

platforms/evoting-api/src/services/poll.service.ts (3)

11-33: Inconsistent rank vote validation between type guard and inline validation.

The isValidRankVote function validates data as an array of objects with option and points properties (matching the RankVoteData type), but the inline validation in castVote (lines 148-158) expects an array of strings. This inconsistency will cause runtime errors.

Either update the inline validation to match the type guard:

 case "rank":
-    if (
-        !Array.isArray(data) ||
-        data.length !== poll.options.length ||
-        data.some((d) => typeof d !== "string") ||
-        new Set(data).size !== data.length ||
-        data.some((option) => !poll.options.includes(option))
-    ) {
+    if (!isValidRankVote(data, poll.options)) {
         throw new Error("Invalid vote for rank mode");
     }
     break;

Or update both the type and validation function to use string arrays if that's the intended format.

Also applies to: 148-158


89-94: Privacy concern: Votes are included when fetching polls.

Including votes in poll queries could expose voting data inappropriately. Consider whether votes should be visible and to whom.

Remove votes from default queries:

 async getPolls(visibility?: "public" | "private"): Promise<Poll[]> {
     return this.pollRepository.find({
         where: visibility ? { visibility } : {},
-        relations: ["votes"],
     });
 }

Similarly for getPollById:

 async getPollById(pollId: string): Promise<Poll | null> {
     return await this.pollRepository.findOne({
         where: { id: pollId },
-        relations: ["votes"],
     });
 }

Add a separate method to get poll results when appropriate with proper authorization.


134-146: Use validation function instead of inline validation for point mode.

The inline validation duplicates the logic in isValidPointVote function, creating maintenance issues.

Replace with the validation function:

 case "point":
-    if (
-        !Array.isArray(data) ||
-        data.length === 0 ||
-        data.some(
-            (d) =>
-                typeof d.option !== "string" ||
-                typeof d.points !== "number" ||
-                !poll.options.includes(d.option),
-        )
-    ) {
+    if (!isValidPointVote(data, poll.options)) {
         throw new Error("Invalid vote for point mode");
     }
     break;
🧹 Nitpick comments (1)
platforms/evoting-api/src/controllers/poll.controller.ts (1)

76-92: Consider extracting normal mode validation for consistency.

While the validation logic is correct, normal mode uses inline validation while point and rank modes use imported functions. For consistency and reusability, consider creating an isValidNormalVote function.

Add to poll.service.ts:

export function isValidNormalVote(
    data: unknown,
    pollOptions: string[],
): data is string[] {
    return (
        Array.isArray(data) &&
        data.length > 0 &&
        data.every(d => typeof d === "string" && pollOptions.includes(d))
    );
}

Then update the controller:

-if (poll.mode === "normal" && !Array.isArray(data)) {
+if (poll.mode === "normal" && !isValidNormalVote(data, pollOptions)) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 093a692 and 4b41c8d.

📒 Files selected for processing (2)
  • platforms/evoting-api/src/controllers/poll.controller.ts (1 hunks)
  • platforms/evoting-api/src/services/poll.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
platforms/evoting-api/src/services/poll.service.ts (3)
  • PollService (52-200)
  • isValidPointVote (35-50)
  • isValidRankVote (11-33)
platforms/evoting-api/src/services/poll.service.ts (2)
platforms/evoting-api/src/database/entities/Vote.ts (3)
  • RankVoteData (19-22)
  • PointVoteData (14-17)
  • VoteDataByMode (26-29)
platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
  • Vote (23-573)
🔇 Additional comments (2)
platforms/evoting-api/src/controllers/poll.controller.ts (1)

65-67: Good authentication validation!

The authentication check is properly implemented here, ensuring only authenticated users can cast votes.

platforms/evoting-api/src/services/poll.service.ts (1)

35-50: Well-implemented point vote validation.

The validation function correctly checks for array structure, uniqueness of options, and proper types.

Comment on lines +46 to +54
async getPoll(req: Request, res: Response) {
try {
const poll = await this.pollService.getPollById(req.params.id);
if (!poll) return res.status(404).json({ error: "Poll not found" });
res.json(poll);
} catch (err: unknown) {
res.status(500).json({ error: (err as Error).message });
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider authorization for private polls.

The method retrieves any poll without checking if the user has permission to view it. Private polls might need authorization checks.


🏁 Script executed:

#!/bin/bash
# Check if Poll entity has visibility-related fields or owner information
ast-grep --pattern 'class Poll {
  $$$
}'

Length of output: 2833


🏁 Script executed:

#!/bin/bash
# Locate the implementation of getPollById in PollService
rg "getPollById" -A10 -n platforms/evoting-api/src

Length of output: 6013


Enforce authorization on private polls

getPoll currently returns any poll—including those marked "private"—without checking who’s requesting it, and the Poll entity has no owner or ACL to enforce restrictions. To prevent unauthorized access:

• platforms/evoting-api/src/database/entities/Poll.ts
– Add an owner relation (e.g. @ManyToOne(() => User, user => user.polls) owner: User)
• platforms/evoting-api/src/services/poll.service.ts (or create a new method)
– When loading a private poll, verify that the current user is the owner (throw a 403 if not)
• platforms/evoting-api/src/controllers/poll.controller.ts#getPoll
– After calling getPollById, check poll.visibility === "private" and enforce the owner check before calling res.json

Implementing these changes will ensure private polls remain accessible only to their creators.

🤖 Prompt for AI Agents
In platforms/evoting-api/src/controllers/poll.controller.ts around lines 46 to
54, the getPoll method returns private polls without authorization checks. To
fix this, first update platforms/evoting-api/src/database/entities/Poll.ts to
add an owner relation linking Poll to User. Then, in
platforms/evoting-api/src/services/poll.service.ts, modify or add a method to
verify that if a poll is private, the requesting user is the owner, throwing a
403 error if not authorized. Finally, in getPoll, after retrieving the poll,
check if poll.visibility is "private" and enforce the ownership check before
sending the response, returning a 403 status if the user is not the owner.

Comment on lines +97 to +101
async castVote(
pollId: string,
userId: string,
data: VoteDataByMode, // should be validated before calling
): Promise<Vote> {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Type mismatch in castVote parameter.

The data parameter is typed as VoteDataByMode which expects {mode, data} structure, but the method actually receives and validates just the data portion (string[], PointVoteData, or RankVoteData).

Update the type to match actual usage:

 async castVote(
     pollId: string,
     userId: string,
-    data: VoteDataByMode, // should be validated before calling
+    data: string[] | PointVoteData | RankVoteData,
 ): Promise<Vote> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async castVote(
pollId: string,
userId: string,
data: VoteDataByMode, // should be validated before calling
): Promise<Vote> {
async castVote(
pollId: string,
userId: string,
data: string[] | PointVoteData | RankVoteData,
): Promise<Vote> {
🤖 Prompt for AI Agents
In platforms/evoting-api/src/services/poll.service.ts around lines 97 to 101,
the castVote method's data parameter is incorrectly typed as VoteDataByMode,
which expects an object with mode and data properties, but the method actually
receives only the data portion (string[], PointVoteData, or RankVoteData).
Change the type of the data parameter to accept only the data portion types
directly, matching the actual input and validation logic.

@Sahil2004 Sahil2004 self-assigned this Aug 7, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (3)
platforms/eVoting/src/app/(auth)/login/page.tsx (3)

23-27: Remove console logging of authentication data

Logging authentication responses poses a security risk as it may expose sensitive tokens or user data in production.

-        if (res.error?.message) {
-            console.error("Login failed:", res.error.message);
-            setError(res.error.message);
-            return;
-        }
-        console.log("Login successful:", res.data);
+        if (res.error?.message) {
+            setError(res.error.message);
+            return;
+        }

44-47: UI text doesn't match authentication implementation

The UI mentions "Scan the QR using your eID App" but the actual implementation uses email/password authentication.

-                    <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
-                        <span>Scan the QR using your</span>
-                        <span className="font-bold underline">eID App</span>
-                        <span>to login</span>
-                    </div>
+                    <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
+                        <span>Enter your credentials to login</span>
+                    </div>

17-29: Add input validation and loading state

The form lacks client-side validation and loading feedback during authentication.

+    const [isLoading, setIsLoading] = useState(false);
+
     const handleSubmit = async () => {
+        if (!email || !password) {
+            setError("Please enter both email and password");
+            return;
+        }
+        setIsLoading(true);
         const res = await authClient.signIn.email({
             email,
             password,
         });
+        setIsLoading(false);
         if (res.error?.message) {
             setError(res.error.message);
             return;
         }
         router.push("/");
     };

And update the button:

-                    <Button onClick={handleSubmit}>Submit</Button>
+                    <Button onClick={handleSubmit} disabled={isLoading}>
+                        {isLoading ? "Signing in..." : "Submit"}
+                    </Button>

Also applies to: 65-77

🧹 Nitpick comments (3)
platforms/eVoting/src/app/(auth)/login/page.tsx (1)

72-72: Capitalize password placeholder for consistency

The password placeholder should be capitalized to match the email field.

-                        placeholder="password"
+                        placeholder="Password"
platforms/eVoting/src/app/(app)/layout.tsx (2)

102-104: Simplify empty return statement

Use null instead of empty fragment for cleaner code.

-            ) : (
-                <></>
-            )}
+            ) : null}

74-77: Remove duplicate disclaimer text

The disclaimer contains redundant text about the app being in development.

                                     <p>
-                                        The app is still in development, so we
-                                        kindly ask for your understanding
-                                        regarding any potential issues. If you
+                                        If you
                                         experience issues or have feedback, feel
                                         free to contact us at:
                                     </p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fbe7b0 and 8940bed.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • platforms/eVoting/package.json (1 hunks)
  • platforms/eVoting/src/app/(app)/layout.tsx (1 hunks)
  • platforms/eVoting/src/app/(auth)/login/page.tsx (1 hunks)
  • platforms/eVoting/src/app/(auth)/register/page.tsx (1 hunks)
  • platforms/eVoting/src/components/ui/dialog.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • platforms/eVoting/package.json
  • platforms/eVoting/src/app/(auth)/register/page.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-07T04:59:24.520Z
Learnt from: Sahil2004
PR: MetaState-Prototype-Project/prototype#193
File: platforms/metagram/src/lib/store/store.svelte.ts:0-0
Timestamp: 2025-06-07T04:59:24.520Z
Learning: In the MetaState prototype project, prefer using centralized type definitions from `$lib/types` over importing interfaces from component files for better type organization and to avoid circular dependencies.

Applied to files:

  • platforms/eVoting/src/components/ui/dialog.tsx
📚 Learning: 2025-04-16T18:04:28.983Z
Learnt from: coodos
PR: MetaState-Prototype-Project/prototype#99
File: infrastructure/w3id/tests/w3id.test.ts:48-57
Timestamp: 2025-04-16T18:04:28.983Z
Learning: In test files, suggestions to add defensive coding patterns (like extra null checks) are often unnecessary, as tests are designed to fail explicitly when expectations aren't met. The test in `infrastructure/w3id/tests/w3id.test.ts` validates that `id.logs` is an instance of `IDLogManager` before accessing its repository property.

Applied to files:

  • platforms/eVoting/src/app/(auth)/login/page.tsx
🧬 Code Graph Analysis (2)
platforms/eVoting/src/components/ui/dialog.tsx (1)
infrastructure/eid-wallet/src/lib/utils/mergeClasses.ts (1)
  • cn (4-6)
platforms/eVoting/src/app/(auth)/login/page.tsx (3)
platforms/eVoting/src/lib/auth-client.ts (1)
  • authClient (2-5)
platforms/eVoting/src/components/ui/card.tsx (2)
  • Card (80-80)
  • CardHeader (81-81)
platforms/blabsy/src/components/input/input.tsx (1)
  • Input (43-290)
🔇 Additional comments (1)
platforms/eVoting/src/app/(app)/layout.tsx (1)

22-33: Good authentication state handling

The session management correctly handles loading states and redirects unauthenticated users.

<Dialog open>
<DialogContent
className="max-w-lg mx-auto backdrop-blur-md p-6 rounded-lg"
onInteractOutside={() => router.push("/logout")}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reconsider aggressive logout on outside interaction

Logging out users when they click outside the disclaimer dialog may be too harsh. Users might accidentally click outside while reading.

Consider warning users first or removing this behavior:

-                        onInteractOutside={() => router.push("/logout")}
+                        onInteractOutside={(e) => {
+                            e.preventDefault();
+                            // Optionally show a warning that they must accept to continue
+                        }}
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(app)/layout.tsx at line 43, the current code logs
out users immediately when they click outside the disclaimer dialog, which can
be too aggressive. Modify this behavior to either show a warning or confirmation
prompt before logging out, or remove the automatic logout on outside interaction
entirely to prevent accidental logouts.

Comment on lines +86 to +89
<p className="font-bold text-md">
The code is only valid for 60 seconds
</p>
<p>Please refresh the page if it expires</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove misleading expiry message

The message about code validity doesn't apply to email/password authentication.

-                    <span className="flex flex-col gap-2 items-center">
-                        <p className="font-bold text-md">
-                            The code is only valid for 60 seconds
-                        </p>
-                        <p>Please refresh the page if it expires</p>
-                    </span>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx around lines 86 to 89, remove
the paragraph elements that state "The code is only valid for 60 seconds" and
"Please refresh the page if it expires" because these messages are misleading
for email/password authentication. Simply delete these lines to avoid confusion.

Comment on lines 32 to +49
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
>
{children}
</DialogPrimitive.Content>
</DialogPortal>
));
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Missing close button may impact user experience

The DialogContent component no longer includes a close button (X icon), which was previously present. This removal means users cannot easily dismiss dialogs unless the parent component provides an alternative closing mechanism.

Consider either:

  1. Re-adding the close button for better UX
  2. Ensuring all dialog implementations provide clear dismissal options

🏁 Script executed:

#!/bin/bash
# Description: Check how dialogs are being used and if they have alternative close mechanisms

# Search for Dialog usage to verify if close mechanisms are provided
rg -A 10 "DialogContent" --glob "*.tsx" --glob "*.jsx" | head -50

# Check if DialogClose is being used elsewhere
rg "DialogClose" --glob "*.tsx" --glob "*.jsx"

Length of output: 5251


🏁 Script executed:

#!/bin/bash
set -e
echo "Displaying the first 200 lines of the file:"
sed -n '1,200p' platforms/eVoting/src/components/ui/dialog.tsx

Length of output: 3860


🏁 Script executed:

#!/bin/bash
# Check for explicit DialogClose usage in group-charter-manager page
rg "<DialogClose" --glob "platforms/group-charter-manager/src/app/charter/[id]/*.tsx"

Length of output: 236


🏁 Script executed:

#!/bin/bash
# Search for actual usage of <DialogClose> in group-charter-manager pages to confirm if consumers add close buttons
rg "<DialogClose" platforms/group-charter-manager/src/app

Length of output: 59


Ensure dialogs include a clear close control

The base DialogContent no longer renders a default “X” close button, so none of your dialogs show a dismissal control unless every consumer adds <DialogClose> manually. We audited the usages (e.g. in platforms/group-charter-manager/src/app/charter/[id]/page.tsx) and found no <DialogClose> instances.

To restore an accessible, discoverable close action, choose one of the following:

  • Re-introduce a built-in close button in DialogContent (e.g. at the top-right corner):
    <DialogPrimitive.Content >
      <DialogClose asChild className="absolute top-4 right-4">
        <button aria-label="Close"><X /></button>
      </DialogClose>
      {children}
    </DialogPrimitive.Content>
  • Or update every dialog usage to include <DialogClose> in its markup and ensure it’s styled/positioned consistently.

Files needing attention:

  • platforms/eVoting/src/components/ui/dialog.tsx → wrap <DialogPrimitive.Content> children with a default <DialogClose> or document the requirement.
  • Downstream usages (e.g. platforms/group-charter-manager/src/app/charter/[id]/page.tsx) → add <DialogClose> if you opt to keep it opt-in.
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/ui/dialog.tsx around lines 32 to 49, the
DialogContent component no longer includes a default close button, causing
dialogs to lack a dismissal control unless consumers add <DialogClose> manually.
To fix this, re-introduce a built-in close button inside the
DialogPrimitive.Content element by adding a <DialogClose> component wrapping a
button with an accessible label and close icon, positioned at the top-right
corner. This ensures all dialogs have a consistent, accessible close control
without requiring every usage to add it manually.

@coodos coodos merged commit dfca2d9 into main Aug 7, 2025
2 of 4 checks passed
@coodos coodos deleted the feat/evoting branch August 7, 2025 18:20
@coderabbitai coderabbitai bot mentioned this pull request Aug 22, 2025
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants