diff --git a/src/app/[id]/page.tsx b/src/app/[id]/page.tsx
index cd5772f..5e7cbf6 100644
--- a/src/app/[id]/page.tsx
+++ b/src/app/[id]/page.tsx
@@ -20,6 +20,7 @@ import { BillQuestions } from "@/components/BillDetail/BillQuestions";
import { Separator } from "@/components/ui/separator";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
+import { DEV_OPEN_ACCESS } from "@/lib/auth-guards";
import { BillTenets } from "@/components/BillDetail/BillTenets";
import { JudgementValue } from "@/components/Judgement/judgement.component";
import { buildAbsoluteUrl, buildRelativePath } from "@/utils/basePath";
@@ -89,7 +90,7 @@ export default async function BillDetail({ params }: Params) {
← Back to bills
- {session?.user && (
+ {(session?.user || DEV_OPEN_ACCESS) && (
Edit
diff --git a/src/app/api/[id]/reprocess/route.ts b/src/app/api/[id]/reprocess/route.ts
index 63a50ad..4255100 100644
--- a/src/app/api/[id]/reprocess/route.ts
+++ b/src/app/api/[id]/reprocess/route.ts
@@ -4,6 +4,7 @@ import { connectToDatabase } from "@/lib/mongoose";
import { Bill, type BillDocument } from "@/models/Bill";
import { User } from "@/models/User";
import { authOptions } from "@/lib/auth";
+import { DEV_OPEN_ACCESS } from "@/lib/auth-guards";
import {
type ApiBillDetail,
fetchBillMarkdown,
@@ -24,21 +25,25 @@ export async function POST(
_request: Request,
{ params }: { params: Promise<{ id: string }> },
) {
- const session = await getServerSession(authOptions);
- if (!session?.user?.email) {
- return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ // DEV ONLY: open access — skip the session/allowlist checks entirely.
+ if (!DEV_OPEN_ACCESS) {
+ const session = await getServerSession(authOptions);
+ if (!session?.user?.email) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
+
+ // Verify user is on the allowlist; do not create
+ await connectToDatabase();
+ const dbUser = await User.findOne({
+ emailLower: session.user.email.toLowerCase(),
+ });
+ if (!dbUser) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
}
await connectToDatabase();
- // Verify user is on the allowlist; do not create
- const dbUser = await User.findOne({
- emailLower: session.user.email.toLowerCase(),
- });
- if (!dbUser) {
- return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
- }
-
const { id } = await params;
const existing = (await Bill.findOne({ billId: id })
diff --git a/src/app/api/[id]/route.ts b/src/app/api/[id]/route.ts
index e953709..f1c4f07 100644
--- a/src/app/api/[id]/route.ts
+++ b/src/app/api/[id]/route.ts
@@ -4,27 +4,33 @@ import { connectToDatabase } from "@/lib/mongoose";
import { Bill } from "@/models/Bill";
import { User } from "@/models/User";
import { authOptions } from "@/lib/auth";
+import { DEV_OPEN_ACCESS } from "@/lib/auth-guards";
import { BASE_PATH } from "@/utils/basePath";
export async function POST(
request: Request,
{ params }: { params: Promise<{ id: string }> },
) {
- const session = await getServerSession(authOptions);
- if (!session?.user?.email) {
- return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
- }
+ // DEV ONLY: open access — skip the session/allowlist checks entirely.
+ if (!DEV_OPEN_ACCESS) {
+ const session = await getServerSession(authOptions);
+ if (!session?.user?.email) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
- await connectToDatabase();
+ await connectToDatabase();
- // Verify user exists in DB; do not create
- const dbUser = await User.findOne({
- emailLower: session.user.email.toLowerCase(),
- });
- if (!dbUser) {
- return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ // Verify user exists in DB; do not create
+ const dbUser = await User.findOne({
+ emailLower: session.user.email.toLowerCase(),
+ });
+ if (!dbUser) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
}
+ await connectToDatabase();
+
const contentType = request.headers.get("content-type")?.toLowerCase() || "";
let title: string | undefined;
diff --git a/src/env.ts b/src/env.ts
index b12aa9d..f571e5b 100644
--- a/src/env.ts
+++ b/src/env.ts
@@ -14,7 +14,7 @@ function optional(
return value && value.trim() !== "" ? value : undefined;
}
-const ENDPOINT = "https://civics-project-kiyv.vercel.app";
+const ENDPOINT = "https://api.civicsproject.org";
export const env = {
NODE_ENV: process.env.NODE_ENV || "development",
diff --git a/src/lib/auth-guards.ts b/src/lib/auth-guards.ts
index 0f0510e..12c82c5 100644
--- a/src/lib/auth-guards.ts
+++ b/src/lib/auth-guards.ts
@@ -1,9 +1,16 @@
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
+import { env } from "@/env";
import { connectToDatabase } from "@/lib/mongoose";
import { User } from "@/models/User";
+/**
+ * DEV ONLY: when true, admin/edit access is open to everyone — including users
+ * who are not signed in. Never enabled in production.
+ */
+export const DEV_OPEN_ACCESS = env.NODE_ENV !== "production";
+
/**
* Server-side authentication guard that requires a valid authenticated user.
* Redirects to /unauthorized if:
@@ -15,6 +22,11 @@ import { User } from "@/models/User";
* @throws Redirects to /unauthorized if authentication fails
*/
export async function requireAuthenticatedUser() {
+ // DEV ONLY: open access — skip the session/allowlist checks entirely.
+ if (DEV_OPEN_ACCESS) {
+ return { session: null, dbUser: null };
+ }
+
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
diff --git a/src/lib/auth.ts b/src/lib/auth.ts
index 936a21e..eb2a2d1 100644
--- a/src/lib/auth.ts
+++ b/src/lib/auth.ts
@@ -40,10 +40,20 @@ export const authOptions: NextAuthOptions = {
const now = new Date();
const existing = await User.findOne({ emailLower: email });
if (!existing) {
+ // DEV ONLY: auto-create + allow any signed-in account so every user
+ // has admin access locally. Never runs in production.
if (env.NODE_ENV !== "production") {
console.warn(
- `[auth] User ${email} not found. No auto-creation. Denying sign-in.`,
+ `[auth] DEV: auto-creating + allowing ${email} (admin access on for all users).`,
);
+ await User.create({
+ email: user?.email,
+ emailLower: email,
+ name: user?.name ?? null,
+ allowed: true,
+ lastLoginAt: now,
+ });
+ return true;
}
return false;
}
@@ -51,6 +61,8 @@ export const authOptions: NextAuthOptions = {
(existing as any).image = (user as any)?.image ?? existing.image;
existing.lastLoginAt = now;
await existing.save();
+ // DEV ONLY: allow regardless of the allowlist flag.
+ if (env.NODE_ENV !== "production") return true;
return !!existing.allowed;
} catch (err) {
if (env.NODE_ENV !== "production") {
diff --git a/src/prompt/summary-and-vote-prompt.ts b/src/prompt/summary-and-vote-prompt.ts
index ce92140..7a3ad9a 100644
--- a/src/prompt/summary-and-vote-prompt.ts
+++ b/src/prompt/summary-and-vote-prompt.ts
@@ -78,6 +78,7 @@ You are analyzing Canadian legislation. You must assess whether the bill aligns
- tenet_evaluations.alignment: aligns|conflicts|neutral
- final_judgment: yes|no|abstain
- is_social_issue: yes|no
+ - Never mention the tenents in the summary, questions, or rationale.
Output format (return valid JSON only):
diff --git a/src/services/billApi.ts b/src/services/billApi.ts
index aa3eaaf..d5763fa 100644
--- a/src/services/billApi.ts
+++ b/src/services/billApi.ts
@@ -61,6 +61,7 @@ export async function getBillFromCivicsProjectApi(
billId: string,
): Promise {
const URL = `${env.CIVICS_PROJECT_BASE_URL}/canada/bills/${CANADIAN_PARLIAMENT_NUMBER}/${billId}`;
+ console.log({ URL });
const response = await fetch(URL, {
// Cache individual bills.
...(process.env.NODE_ENV === "production"
@@ -72,7 +73,17 @@ export async function getBillFromCivicsProjectApi(
},
});
if (!response.ok) {
- throw new Error("Failed to fetch bill details");
+ const body = await response.text().catch(() => "");
+ console.error("Failed to fetch bill details from Civics Project API", {
+ billId,
+ url: URL,
+ status: response.status,
+ statusText: response.statusText,
+ body: body.slice(0, 1000),
+ });
+ throw new Error(
+ `Failed to fetch bill details for "${billId}": ${response.status} ${response.statusText} (${URL})`,
+ );
}
const json = await response.json();
const data = (json?.data?.bill ?? json?.data ?? json) as