+ >
+ )}
);
diff --git a/adminsite/app/signup/page.tsx b/adminsite/app/signup/page.tsx
deleted file mode 100644
index 7761171..0000000
--- a/adminsite/app/signup/page.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-"use client";
-
-import { useState } from "react";
-import { ApiError, NotConnected, api } from "@/lib/api";
-import { Button } from "@/components/Button";
-import { Field } from "@/components/Field";
-
-export default function SignupPage() {
- const [form, setForm] = useState({ name: "", email: "", password: "", website: "" });
- const [state, setState] = useState<"idle" | "busy" | "sent">("idle");
- const [error, setError] = useState(null);
-
- async function submit(e: React.FormEvent) {
- e.preventDefault();
- setState("busy");
- setError(null);
- try {
- await api.signup(form);
- setState("sent");
- } catch (err) {
- setState("idle");
- setError(
- err instanceof NotConnected
- ? "The licensing service is not reachable from this page."
- : err instanceof ApiError
- ? err.message
- : "Could not create the account. Try again.",
- );
- }
- }
-
- return (
-
- {state === "sent" ? (
-
-
Check your email
-
- We sent a link to {form.email}. Open it to finish setting up your account —
- it expires in 24 hours. Nothing is created until you do.
-
-
- ) : (
- <>
-
Create an account
-
- For self-hosted licences. If you run on our cloud, sign in with the same
- details you use for your Vantage instance.
-
-
- >
- )}
-
- );
-}
diff --git a/adminsite/lib/api.ts b/adminsite/lib/api.ts
index 0a89e31..dff5f18 100644
--- a/adminsite/lib/api.ts
+++ b/adminsite/lib/api.ts
@@ -296,8 +296,6 @@ export const api = {
staffLogin: (email: string, password: string) =>
post("/auth/staff/login", { email, password }),
logout: () => post<{ ok: boolean }>("/auth/logout"),
- signup: (payload: { name: string; email: string; password: string; website?: string }) =>
- post<{ pending: boolean }>("/auth/signup", payload),
verify: (token: string) =>
req<{ verified: boolean; needs_password?: boolean }>(
`/auth/verify?token=${encodeURIComponent(token)}`,
diff --git a/claude.md b/claude.md
index 16a0d79..36a5f20 100644
--- a/claude.md
+++ b/claude.md
@@ -669,6 +669,7 @@ git push origin main # server + web deploy
| `API_URL` | **not** a CI variable | `web` reads it at **runtime**, from the container environment — `next.config.ts` is evaluated when `server.js` boots in standalone mode, and the rewrites it feeds are server-side, never browser-side. Default `http://localhost:8080`; compose sets `http://server:8080`. `NEXT_PUBLIC_API_URL` is still honoured as a fallback for existing deployments. |
| `SITE_API_URL` | Variable | **browser-reachable** sitesvc URL, baked into the `site` image. Required — if empty, both forms report "not connected" and submit nowhere. Must also be in sitesvc's `SITE_ORIGIN`. |
| `SITE_CONTACT_EMAIL` | Variable | optional; address shown when a form is misconfigured |
+| `SITE_URL` | Variable | browser URL of the marketing site, baked into `adminsite` so `/login` can point at `/start`. **Signup has no page in `adminsite` at all** — one signup form, on `site/`. Empty renders no link rather than one that 404s. |
| `ADMIN_API_URL` | Variable | **browser-reachable** admin URL, baked into **both** the `adminsite` and `site` images — `site/start` posts account signups straight to admin. Same footgun as `SITE_API_URL`: wrong here and every request fails at runtime with the not-connected panel. |
| `ADMIN_ENV` | Variable | `production` or `sandbox`; drives the persistent environment badge. Anything but `sandbox` reads as production. |
| `HQ_URL` | Variable | optional; browser URL of the HQ portal, baked into `web` so an `hq`-sourced member links to where they are managed. Empty on self-hosted, which renders a plain label instead. |