Initial commit: Korrith website, assessment API, PocketBase schema, Docker/Coolify deployment

This commit is contained in:
Korrith
2026-09-17 20:47:51 +00:00
commit c17f11f591
248 changed files with 39721 additions and 0 deletions
@@ -0,0 +1,45 @@
/// <reference path="../pb_data/types.d.ts" />
onMailerSend((e) => {
if (e.app.settings().smtp.enabled) {
return e.next()
}
const senderAddress = $os.getenv("BUILDER_MAILER_SENDER_ADDRESS");
const cc = (e.message.cc || []).map((recipient) => recipient.address).filter(Boolean);
const bcc = (e.message.bcc || []).map((recipient) => recipient.address).filter(Boolean);
const payload = {
"subject": e.message.subject,
"content": {
...(e.message.html ? {
"html": e.message.html,
} : {
"text": e.message.text,
}),
"type": "plain",
},
"from": senderAddress,
"fromName": e.message.from?.name,
"replyTo": senderAddress,
"to": e.message.to[0].address,
...(cc.length ? { "cc": cc } : {}),
...(bcc.length ? { "bcc": bcc } : {}),
}
const response = $http.send({
url: `${$os.getenv("BUILDER_MAILER_API_URL")}/api/v2/email`,
method: "POST",
headers: {
"Authorization": `Bearer ${$os.getenv("BUILDER_MAILER_API_KEY")}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
if (response.statusCode !== 200) {
$app.logger().error("Failed to send email", "error", response.json);
throw new ApiError(500, response.json?.message || 'Failed to send email');
}
})
@@ -0,0 +1,133 @@
/// <reference path="../pb_data/types.d.ts" />
/*
- Usage: ./pocketbase horizons migrations:revert migration1.js migration2.js ... - reverts specific migrations by name (not by count like the built-in "down" command)
*/
// Create a new "horizons" command group with a "migrations:revert" subcommand
const horizonsCmd = new Command({
use: "horizons",
short: "Additional migration utilities",
})
const exitOnError = (run) => (...args) => {
try {
return run(...args)
} catch (error) {
console.error(error)
// Command callbacks run in a panic-recovering goroutine, so throwing
// alone no longer propagates a nonzero status to the parent process.
$os.exit(1)
}
}
horizonsCmd.addCommand(new Command({
use: "migrations:revert [migration names...]",
short: "Revert specific migrations by name and delete their files",
run: exitOnError((_cmd, args) => {
if (args.length === 0) {
console.log("Usage: horizons migrations:revert <migration1.js> [migration2.js] ...")
console.log("No migrations specified to revert.")
return
}
const migrationsDir = $filepath.join(__hooks, "../pb_migrations")
const migrationFiles = {}
try {
const files = $os.readDir(migrationsDir)
for (const file of files) {
const name = file.name()
migrationFiles[name] = $filepath.join(migrationsDir, name)
}
} catch (e) {
console.error("Failed to read migrations directory:", e)
return
}
const appliedMigrations = []
for (const migrationName of args) {
if (!migrationFiles[migrationName]) {
console.error(`Migration file not found: ${migrationName}`)
continue
}
try {
const result = arrayOf(new DynamicModel({ file: "" }))
$app.db()
.select("file")
.from("_migrations")
.where($dbx.hashExp({ file: migrationName }))
.limit(1)
.all(result)
if (result.length === 0) {
console.log(`Migration ${migrationName} is not applied, skipping.`)
$os.remove(migrationFiles[migrationName]);
continue
}
appliedMigrations.push(migrationName)
} catch (e) {
console.error(`Failed to check migration status for ${migrationName}:`, e)
continue
}
}
if (appliedMigrations.length === 0) {
console.log("No applied migrations found to revert.")
return
}
console.log("\nMigrations to revert:")
for (const name of appliedMigrations) {
console.log(`${name}`)
}
const reverted = []
$app.runInTransaction((txApp) => {
for (const migrationName of appliedMigrations) {
const filePath = migrationFiles[migrationName]
try {
const content = toString($os.readFile(filePath))
// Extract the down function from migrate(up, down) call
// We need to execute the file and capture the down function
let downFn = null
const captureMigrate = (up, down) => {
downFn = down
}
// Execute the migration file with our custom migrate function since hooks doesn't have access to migrate function
const migrationCode = content.replace(/migrate\s*\(/g, '__captureMigrate(')
const fn = new Function('__captureMigrate', '$app', 'Collection', 'Record', migrationCode)
fn(captureMigrate, txApp, Collection, Record)
if (!downFn) {
console.log(`Migration ${migrationName} has no down function, just removing from history.`)
} else {
downFn(txApp)
}
txApp.db().delete("_migrations", $dbx.hashExp({ file: migrationName })).execute()
reverted.push({ name: migrationName, path: filePath })
console.log(`✓ Reverted: ${migrationName}`)
} catch (e) {
throw new Error(`failed to revert migration ${migrationName}: ${e}`)
}
}
})
for (const migration of reverted) {
$os.remove(migration.path)
}
console.log(`Successfully reverted ${reverted.length} migration(s).`)
}),
}))
$app.rootCmd.addCommand(horizonsCmd)
@@ -0,0 +1,27 @@
/// <reference path="../pb_data/types.d.ts" />
routerAdd("GET", "/{$}", (e) => {
const fileContent = $os.readFile(`${__hooks}/../.pocketbase-version`)
const contentStr = Array.isArray(fileContent)
? String.fromCharCode.apply(null, fileContent)
: fileContent
const pbVersion = `v${contentStr.replace(/\n/g, '').trim()}`
const externalUrl = `https://horizons-static-cdn.hostinger.com/pocketbase/__PB_VERSION__/ui/dist/index.html`.replace("__PB_VERSION__", pbVersion)
try {
const response = $http.send({
url: externalUrl,
method: "GET",
timeout: 30,
})
const htmlContent = Array.isArray(response.body)
? String.fromCharCode.apply(null, response.body)
: response.body
return e.html(response.statusCode, htmlContent)
} catch (err) {
throw new NotFoundError("Failed to load dashboard", err)
}
})
@@ -0,0 +1,64 @@
/// <reference path="../pb_data/types.d.ts" />
// Routes every _logs row to stdout/stderr on production
// Forwards every _logs row to the session journal on development and continue writing to the database
onModelCreate((e) => {
const env = $os.getenv("NODE_ENV")
if (env === "production") {
const write = e.model.level >= 8 ? console.error : console.log
try {
write(JSON.stringify({
id: e.model.id,
created: e.model.created.string(),
level: e.model.level,
message: e.model.message,
data: JSON.parse(e.model.data.string()),
}))
} catch (err) {
console.error(`Failed to forward log: ${err}`)
write(JSON.stringify({ level: e.model.level, message: e.model.message }))
}
// do not continue writing to the database
return
}
if (env === "development" || !env) {
try {
const journalPath = $filepath.join(__hooks, "..", "..", "..", "vault", "temp", "SESSION_JOURNAL.md")
const levels = { "-4": "debug", "0": "info", "4": "warn", "8": "error" }
const level = levels[String(e.model.level)] || `level${e.model.level}`
// Matches vite-plugin-session-journal's entry shape
const bullet = (key, value) => {
const text = String(value)
const indented = text.includes("\n") ? `\n ${text.replace(/\n/g, "\n ")}` : text
return `- ${key}: ${indented}\n`
}
let entry = `## ${e.model.created.string()} pocketbase.${level}\n`
entry += bullet("message", e.model.message)
const data = e.model.data.string()
if (data && data !== "{}") {
entry += bullet("data", data)
}
entry += "\n"
$os.mkdirAll($filepath.dir(journalPath), 0o755)
// $os has no append primitive
$os.cmd("sh", "-c", 'printf "%s" "$1" >> "$2"', "sh", entry, journalPath).run()
} catch (err) {
console.error(`Failed to journal log: ${err}`)
}
}
e.next()
}, "_logs")
@@ -0,0 +1,17 @@
const ALLOWED_IPS = [
"86.106.20.28", // L2
"89.116.209.21", // L2
"86.106.20.24", // L3
"84.32.173.80", // L3
"34.141.125.49", // euw3-stage-koalemos
"35.230.138.117", // euw2-prod-apollo
"35.242.131.17", // euw2-prod-apollo
"34.89.86.34", // euw2-prod-apollo
"35.242.132.122", // euw2-prod-apollo
"35.234.116.158", // euw3-stage-koalemos
"34.159.186.242", // euw3-stage-koalemos
]
module.exports = {
ALLOWED_IPS,
}
+101
View File
@@ -0,0 +1,101 @@
/// <reference path="../pb_data/types.d.ts" />
onRecordCreateRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to create superuser`)
}
e.next()
}, "_superusers")
onRecordUpdateRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to update superuser`)
}
e.next()
}, "_superusers")
onRecordDeleteRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to delete superuser`)
}
e.next()
}, "_superusers")
onRecordRequestPasswordResetRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to request password reset for superuser`)
}
e.next()
}, "_superusers")
onCollectionViewRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to view collection`)
}
e.next()
})
onCollectionCreateRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to create collection`)
}
e.next()
})
onCollectionUpdateRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to update collection`)
}
e.next()
})
onCollectionDeleteRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to delete collection`)
}
e.next()
})
onCollectionsImportRequest((e) => {
const { ALLOWED_IPS } = require(`${__hooks}/superusers-allow-list.js`)
const ip = e.realIP()
if (!ALLOWED_IPS.includes(ip)) {
throw new BadRequestError(`Not allowed to import collections`)
}
e.next()
})