Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions evoting.compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
db:
image: postgres:16
container_name: dev-evoting-db
environment:
POSTGRES_USER: evoting
POSTGRES_PASSWORD: evoting
POSTGRES_DB: evoting
Comment on lines +6 to +8
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.

volumes:
- ./db/data:/var/lib/postgresql/data
ports:
- "5432:5432"
1 change: 1 addition & 0 deletions infrastructure/control-panel/project.inlang/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cache

This file was deleted.

This file was deleted.

77 changes: 40 additions & 37 deletions platforms/eVoting/package.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,42 @@
{
"name": "evoting",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-label": "^2.1.3",
"@radix-ui/react-radio-group": "^1.2.4",
"@radix-ui/react-slot": "^1.2.0",
"@tailwindcss/typography": "^0.5.16",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.453.0",
"next": "15.4.2",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hook-form": "^7.55.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.24.2"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.4.2",
"tailwindcss": "^4",
"typescript": "^5"
}
"name": "evoting",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^5.2.1",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.3",
"@radix-ui/react-radio-group": "^1.2.4",
"@radix-ui/react-slot": "^1.2.0",
"@tailwindcss/typography": "^0.5.16",
"better-auth": "^1.3.4",
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 the better-auth version for security and stability.

The better-auth library at version ^1.3.4 is a relatively new authentication solution. Ensure this version is stable and doesn't have known security vulnerabilities.


🌐 Web query:

What is the latest stable version of better-auth library and are there any known security issues with version 1.3.4?

💡 Result:

As of August 2, 2025, the latest stable version of the Better Auth library is 1.3.3. (better-auth.com)

Regarding version 1.3.4, there is no information available in the provided sources. It's possible that this version has not been released yet or that details about it are not publicly accessible.

However, earlier versions of Better Auth have had known security vulnerabilities. For instance, versions prior to 1.1.6 were susceptible to an open redirect vulnerability in the email verification endpoint, which could allow attackers to redirect users to malicious websites. (github.com)

Additionally, versions before 1.1.21 had a similar open redirect issue due to improper validation of the callbackURL parameter. (nvd.nist.gov)

To ensure your application remains secure, it's recommended to use the latest stable version of Better Auth and regularly monitor official channels for updates on security patches.

Citations:


Update better-auth dependency to a valid, secure release

The package.json currently pins "better-auth": "^1.3.4", but version 1.3.4 isn’t published. The latest stable release is 1.3.3, so attempting to install 1.3.4 will fail.

• Change the dependency to "better-auth": "^1.3.3".
• Be aware that Better Auth versions prior to 1.1.21 (CVE-2025-27143) and 1.1.6 (GHSA-8jhw-6pjj-8723) had open-redirect vulnerabilities—avoid regressing to those.
• Subscribe to the official changelog and security advisories so you can update safely when 1.3.4 (or newer) is released.

Suggested diff:

- "better-auth": "^1.3.4",
+ "better-auth": "^1.3.3",
📝 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
"better-auth": "^1.3.4",
"better-auth": "^1.3.3",
🤖 Prompt for AI Agents
In platforms/eVoting/package.json at line 18, the dependency "better-auth" is
set to "^1.3.4", which is not a published version and causes installation
failures. Change the version to "^1.3.3" to use the latest stable release.
Ensure this version is secure and does not regress to vulnerable versions below
1.1.21 or 1.1.6. Also, monitor official changelogs and advisories for future
updates.

"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.453.0",
"next": "15.4.2",
"next-qrcode": "^2.5.1",
"react": "19.1.0",
"react-dom": "19.1.0",
Comment on lines +23 to +26
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 React 19 and Next.js compatibility.

Using React 19.1.0 with Next.js 15.4.2 represents major version updates. Ensure these versions are compatible and stable for production use.


🌐 Web query:

Is React 19.1.0 compatible with Next.js 15.4.2 and are there any known compatibility issues or breaking changes?

💡 Result:

React 19.1.0 is officially compatible with Next.js 15.4.2, but you must be aware of breaking changes and potential compatibility issues, especially with third-party libraries and deprecated APIs[1][8][4].

Compatibility and Known Issues:

  • Next.js 15.4.2 is built to support React 19.x, and upgrading both together is the recommended path for Next.js projects[8][4].
  • React 19.1.0 introduces several breaking changes, such as removal of legacy context APIs, string refs, and UMD builds, and modifies the handling of ref (now treated as a regular prop rather than a special JSX attribute)[1][3][7]. These can disrupt libraries or custom code that depend on old behaviors.
  • Developers report compatibility problems with some UI libraries, such as Ant Design, mainly due to changes in ref handling and deprecated API removals in React 19, which Next.js 15 surfaces[2]. For example, accessing element.ref is no longer supported: you must use props.ref instead, or adapt to the new context and ref patterns[2].
  • Peer dependency conflicts are common after upgrading, because some packages have not yet officially declared React 19/Next.js 15 support, causing installation errors with npm v7+ unless you use --force to bypass them[5][6]. Forcing installations may risk runtime errors, so thorough testing is advised.

Summary of Breaking Changes Most Likely to Cause Issues:

  • Legacy context API (contextTypes/getChildContext) and string refs are completely removed. Only use the modern Context API and callback refs or createRef[1][3][7].
  • defaultProps is not supported on function components—use ES6 default parameters instead[7].
  • UMD builds are gone; you must use ES modules, and the new JSX transform is now required[1][3].
  • Error handling and hydration error reporting are revamped, which may affect debugging and custom error boundary logic[1][7][3].
  • Next.js and React now require modern browsers, with no support for Internet Explorer unless polyfilled[1].

Best Practices for Upgrading:

  • Run the React upgrade codemods and Next.js upgrade scripts before attempting manual installation[4][7].
  • Audit all dependencies—especially UI libraries and tooling plugins—for React 19/Next.js 15 compatibility before upgrading your main codebase[5][6].
  • If you must use libraries that lag behind in compatibility, use npm install --force as a temporary workaround and monitor for runtime problems, reporting issues to maintainers as needed[6].
  • Test your application thoroughly for hydration errors, layout issues, and ref-related warnings after upgrading.

Conclusion:
You can use React 19.1.0 with Next.js 15.4.2, but expect major API changes and possible compatibility issues, particularly with older or third-party libraries not optimized for the new React APIs. The most common breaking changes relate to ref handling, legacy context, and defaultProps, so review your code and dependencies accordingly[1][2][3][4][5][6][7][8].

Citations:


React 19.1.0 + Next.js 15.4.2 Upgrade: Confirm Breaking Changes and Migration Steps

File: platforms/eVoting/package.json
Lines: 22–25

        "next": "15.4.2",
        "next-qrcode": "^2.5.1",
        "react": "19.1.0",
        "react-dom": "19.1.0",

Upgrading both React and Next.js together is officially supported, but introduces major breaking changes. Before merging to production:

  • Run the official React 19 codemods and Next.js 15 upgrade scripts
    • React guide: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
    • Next.js blog: https://nextjs.org/blog/next-15-4
  • Audit all dependencies (UI libraries, tooling/plugins) for React 19/Next.js 15 support
    • Watch for peer-dependency conflicts—avoid using npm install --force long-term
  • Migrate away from removed APIs:
    • Legacy context (contextTypes/getChildContext) → modern Context API
    • String refs → callback refs or createRef
    defaultProps on function components → ES6 default parameters
  • Switch to ES modules & the new JSX transform; drop any UMD build patterns
  • Thoroughly test for hydration errors, ref-handling changes, and revised error-boundary behavior

Verify all issues are addressed before shipping.

🤖 Prompt for AI Agents
In platforms/eVoting/package.json lines 22 to 25, upgrading React to 19.1.0 and
Next.js to 15.4.2 introduces major breaking changes. Before merging, run the
official React 19 codemods and Next.js 15 upgrade scripts to update deprecated
APIs and syntax. Audit all dependencies for compatibility with React 19 and
Next.js 15, resolving any peer-dependency conflicts without forcing installs.
Refactor code to replace legacy context, string refs, and defaultProps on
function components with modern alternatives. Also, switch to ES modules and the
new JSX transform, then thoroughly test for hydration, ref, and error-boundary
issues to ensure stability.

"react-hook-form": "^7.55.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^4.0.14"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.4.2",
"tailwindcss": "^4",
"typescript": "^5"
}
}
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: Update the lockfile to resolve pipeline failures.

The CI pipeline is failing because pnpm-lock.yaml is out of sync with the package.json dependencies. This blocks all automated checks.

Run the following command to fix the lockfile:

pnpm install --no-frozen-lockfile

Then commit the updated pnpm-lock.yaml file.

🧰 Tools
🪛 GitHub Actions: Check Lint

[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

[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

[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.

🤖 Prompt for AI Agents
In platforms/eVoting/package.json lines 1 to 42, the pnpm-lock.yaml file is out
of sync with the dependencies listed, causing CI pipeline failures. To fix this,
run the command "pnpm install --no-frozen-lockfile" locally to update the
lockfile, then commit the updated pnpm-lock.yaml file to the repository to
resolve the pipeline issues.

Binary file added platforms/eVoting/public/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions platforms/eVoting/public/W3DS.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
"use client";

import { useState, useEffect } from "react";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Plus, X, Eye, UserX } from "lucide-react";
import {
Plus,
X,
Eye,
UserX,
ChartLine,
ListOrdered,
CircleUser,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { useToast } from "@/hooks/use-toast";
import { useAuth } from "@/hooks/useAuth";
import { isUnauthorizedError } from "@/lib/authUtils";
import Link from "next/link";

const createPollSchema = z.object({
title: z.string().min(1, "Poll title is required"),
mode: z.enum(["public", "private"]),
mode: z.enum(["normal", "point", "rank"]),
visibility: z.enum(["public", "private"]),
options: z
.array(z.string().min(1, "Option cannot be empty"))
.min(2, "At least 2 options required"),
Expand All @@ -26,32 +33,16 @@ const createPollSchema = z.object({
.refine((val) => {
if (!val) return true; // Allow empty deadline
const date = new Date(val);
return !isNaN(date.getTime()) && date > new Date();
return !Number.isNaN(date.getTime()) && date > new Date();
}, "Deadline must be a valid future date"),
});

type CreatePollForm = z.infer<typeof createPollSchema>;

export default function CreatePoll() {
const { toast } = useToast();
const { isAuthenticated, isLoading: authLoading } = useAuth();
const [options, setOptions] = useState<string[]>(["", ""]);

// TODO: Redirect to login if not authenticated
// useEffect(() => {
// if (!authLoading && !isAuthenticated) {
// toast({
// title: "Unauthorized",
// description: "You are logged out. Logging in again...",
// variant: "destructive",
// });
// setTimeout(() => {
// window.location.href = "/api/login";
// }, 500);
// return;
// }
// }, [isAuthenticated, authLoading, toast]);

const {
register,
handleSubmit,
Expand All @@ -62,13 +53,20 @@ export default function CreatePoll() {
resolver: zodResolver(createPollSchema),
defaultValues: {
title: "",
mode: "public",
mode: "normal",
visibility: "public",
options: ["", ""],
deadline: "",
},
});

handleSubmit((data) => {
console.log("Form submitted:", data);
console.log(data);
});
Comment on lines +63 to +66
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 immediate handleSubmit invocation

The handleSubmit function is being called immediately on every render, which is incorrect. This code should be removed as it serves no purpose and logs on every render.

-    handleSubmit((data) => {
-        console.log("Form submitted:", data);
-        console.log(data);
-    });
-
📝 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
handleSubmit((data) => {
console.log("Form submitted:", data);
console.log(data);
});
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(app)/create/page.tsx around lines 63 to 66, the
handleSubmit function is being invoked immediately during render, causing
unnecessary logging on every render. Remove the immediate invocation of
handleSubmit and the associated console.log statements to prevent this behavior.
Instead, ensure handleSubmit is only called as an event handler when the form is
submitted.


const watchedMode = watch("mode");
const watchedVisibility = watch("visibility");

const addOption = () => {
const newOptions = [...options, ""];
Expand Down Expand Up @@ -132,7 +130,107 @@ export default function CreatePoll() {
<RadioGroup
value={watchedMode}
onValueChange={(value) =>
setValue("mode", value as "public" | "private")
setValue(
"mode",
value as "normal" | "point" | "rank"
)
}
className="mt-2"
>
<div className="flex items-center space-x-4">
<Label className="flex items-center cursor-pointer">
<RadioGroupItem
value="normal"
className="sr-only"
/>
<div
className={`border-2 rounded-lg p-4 flex-1 transition-all ${
watchedMode === "normal"
? "border-(--crimson) bg-(--crimson-50)"
: "border-gray-300 hover:border-(--crimson)"
}`}
>
<div className="flex items-center">
<CircleUser className="text-(--crimson) w-6 h-6 mr-3" />
<div>
<div className="font-semibold text-gray-900">
1P 1V
</div>
<div className="text-sm text-gray-600">
One person, one vote
</div>
</div>
</div>
</div>
</Label>

<Label className="flex items-center cursor-pointer">
<RadioGroupItem
value="point"
className="sr-only"
/>
<div
className={`border-2 rounded-lg p-4 flex-1 transition-all ${
watchedMode === "point"
? "border-(--crimson) bg-(--crimson-50)"
: "border-gray-300 hover:border-(--crimson)"
}`}
>
<div className="flex items-center">
<ChartLine className="text-(--crimson) w-6 h-6 mr-3" />
<div>
<div className="font-semibold text-gray-900">
PBV
</div>
<div className="text-sm text-gray-600">
Each voter gets 100 points
</div>
</div>
</div>
</div>
</Label>

<Label className="flex items-center cursor-pointer">
<RadioGroupItem
value="rank"
className="sr-only"
/>
<div
className={`border-2 rounded-lg p-4 flex-1 transition-all ${
watchedMode === "rank"
? "border-(--crimson) bg-(--crimson-50)"
: "border-gray-300 hover:border-(--crimson)"
}`}
>
<div className="flex items-center">
<ListOrdered className="text-(--crimson) w-6 h-6 mr-3" />
<div>
<div className="font-semibold text-gray-900">
RBV
</div>
<div className="text-sm text-gray-600">
Voters can rank order the
choices
</div>
</div>
</div>
</div>
</Label>
</div>
</RadioGroup>
</div>

<div>
<Label className="text-sm font-semibold text-gray-700">
Vote Visibility
</Label>
<RadioGroup
value={watchedVisibility}
onValueChange={(value) =>
setValue(
"visibility",
value as "public" | "private"
)
}
className="mt-2"
>
Expand All @@ -144,7 +242,7 @@ export default function CreatePoll() {
/>
<div
className={`border-2 rounded-lg p-4 flex-1 transition-all ${
watchedMode === "public"
watchedVisibility === "public"
? "border-(--crimson) bg-(--crimson-50)"
: "border-gray-300 hover:border-(--crimson)"
}`}
Expand All @@ -170,7 +268,7 @@ export default function CreatePoll() {
/>
<div
className={`border-2 rounded-lg p-4 flex-1 transition-all ${
watchedMode === "private"
watchedVisibility === "private"
? "border-(--crimson) bg-(--crimson-50)"
: "border-gray-300 hover:border-(--crimson)"
}`}
Expand Down Expand Up @@ -224,6 +322,7 @@ export default function CreatePoll() {
<div className="mt-2 space-y-3">
{options.map((option, index) => (
<div
// biome-ignore lint/suspicious/noArrayIndexKey: jatt dont care OOOOOOOOOO
key={index}
className="flex items-center space-x-2"
>
Expand Down Expand Up @@ -278,21 +377,8 @@ export default function CreatePoll() {
</Link>
<Button
type="submit"
// disabled={createPollMutation.isPending}
disabled={false} // TODO: replace with actual loading state
className="flex-1 bg-(--crimson) hover:bg-(--crimson-50) hover:text-(--crimson) hover:border-(--crimson) border text-white"
>
{/* {createPollMutation.isPending ? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
Creating...
</>
) : (
<>
<Plus className="w-4 h-4 mr-2" />
Create Vote
</>
)} */}
Create Vote
</Button>
</div>
Expand Down
Loading
Loading