refactor: large refactor around monorepo

Just a commit point while I'm testing stuff. Already decided at this
point to simplify and revert away from PayloadCMS.
This commit is contained in:
2026-01-04 13:18:34 -06:00
parent 31b1804fc9
commit af81d8e048
110 changed files with 8392 additions and 12918 deletions
+148
View File
@@ -0,0 +1,148 @@
# Default environment variables
default_database_url := "postgresql://xevion:xevion@xevion-db:5432/xevion"
default_payload_secret := "development-secret-change-in-production"
network_name := "xevion-net"
# Build the Docker image
docker-build:
docker build -t xevion.dev .
# Run the Docker container (uses .env if available, otherwise defaults)
docker-run:
#!/bin/sh
docker network create {{network_name}} 2>/dev/null || true
if [ -f .env ]; then
echo "Loading environment from .env file..."
docker run -p 3000:3000 \
--network {{network_name}} \
-e DATABASE_URL="{{default_database_url}}" \
--env-file .env \
xevion.dev | hl -P
else
echo "No .env file found, using defaults..."
docker run -p 3000:3000 \
--network {{network_name}} \
-e DATABASE_URL="{{default_database_url}}" \
-e PAYLOAD_SECRET="{{default_payload_secret}}" \
xevion.dev | hl -P
fi
# Start the PostgreSQL database container
docker-db:
#!/bin/sh
docker network create {{network_name}} 2>/dev/null || true
docker run --name xevion-db \
--network {{network_name}} \
-p 5432:5432 \
-e POSTGRES_USER=xevion \
-e POSTGRES_PASSWORD=xevion \
-e POSTGRES_DB=xevion \
-d postgres
# Stop and remove the database container
docker-db-stop:
docker stop xevion-db && docker rm xevion-db
# Test Docker image with health checks
[script("bun")]
docker-test:
const $ = async (cmd: string[]) => Bun.spawn(cmd).exited;
const $out = (cmd: string[]) => Bun.spawnSync(cmd).stdout.toString();
// Ensure network exists (suppress error if already exists)
Bun.spawnSync(["docker", "network", "create", "{{network_name}}"], { stderr: "ignore" });
// Find available port
const used = new Set(
$out(["ss", "-tuln"]).split("\n").slice(1)
.map(l => l.match(/:(\d+)/)?.[1]).filter(Boolean)
);
const ranges = [[49152, 65535], [10000, 32767], [5000, 9999]];
const available = ranges
.flatMap(([s, e]) => Array.from({ length: e - s + 1 }, (_, i) => s + i))
.filter(p => !used.has(String(p)));
const port = available[~~(Math.random() * available.length)];
console.log(`Using port ${port}`);
// Start container
const container = `xevion-test-${port}`;
const dbUrl = "{{default_database_url}}";
const secret = "{{default_payload_secret}}";
await $([
"docker", "run", "-d", "--name", container,
"--network", "{{network_name}}",
"-p", `${port}:3000`,
"-e", `DATABASE_URL=${dbUrl}`,
"-e", `PAYLOAD_SECRET=${secret}`,
"xevion.dev"
]);
const cleanup = async () => {
console.log("\nCleaning up...");
await $(["docker", "rm", "-f", container]);
};
process.on("SIGINT", async () => { await cleanup(); process.exit(1); });
process.on("SIGTERM", async () => { await cleanup(); process.exit(1); });
const base = `http://localhost:${port}`;
// Poll until success or timeout
const poll = async (
fn: () => Promise<boolean>,
{ timeout = 5000, interval = 1000 } = {}
): Promise<boolean> => {
const start = Date.now();
while (Date.now() - start < timeout) {
if (await fn()) return true;
await Bun.sleep(interval);
}
return false;
};
// Test a route with retries
const test = async (path: string, expect: { status?: number; contains?: string } = {}) => {
const { status = 200, contains } = expect;
let last = { status: 0, reason: "no response" };
const check = async () => {
try {
const res = await fetch(`${base}${path}`);
const text = await res.text();
if (res.status === status && (!contains || text.includes(contains))) return true;
last = { status: res.status, reason: contains && !text.includes(contains)
? `missing "${contains}"` : `status ${res.status}` };
return false;
} catch (e: any) { last = { status: 0, reason: e.code || e.message }; return false; }
};
const ok = await poll(check);
console.log(ok ? `${path}` : `${path} (${last.reason})`);
return ok;
};
// Wait for index
console.log("Waiting for server...");
const ready = await poll(async () => {
try { return (await fetch(base)).ok; } catch { return false; }
}, { timeout: 3000, interval: 100 });
if (!ready) {
console.error("Server failed to start");
await cleanup();
process.exit(1);
}
console.log("Server ready\n");
// Run tests sequentially
const tests = [
() => test("/projects"),
() => test("/blog"),
() => test("/admin", { contains: "Payload" }),
() => test("/admin/api/stats"),
];
const results: boolean[] = [];
for (const t of tests) results.push(await t());
await cleanup();
process.exit(results.every(Boolean) ? 0 : 1);