feat: initial scaffold - backend, frontend, Prisma schema, Docker

- Prisma schema: User, Session, RepoConfig, Preview, Job, WebhookToken, NoConfigComment, AdminSettings
- Backend: auth (login/logout/me/first-user setup), webhook handler with HMAC verification, EC2 service, SSH service, deploy pipeline, job queue worker, cron workers
- Frontend: Login with first-user detection, Dashboard, PreviewDetail with live log streaming, Settings, Repos config, Admin panel, SetupWizard, Privacy page
- Docker Compose and Dockerfile for self-hosted deployment
- Uses bcryptjs for Node 24 compatibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 00:18:08 +02:00
parent ca2efdadea
commit 40d484bede
108 changed files with 13393 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var auth_exports = {};
__export(auth_exports, {
COOKIE_NAME_EXPORT: () => COOKIE_NAME_EXPORT,
authEnforcementMiddleware: () => authEnforcementMiddleware,
authResolutionMiddleware: () => authResolutionMiddleware
});
module.exports = __toCommonJS(auth_exports);
var import_rjweb_server = require("rjweb-server");
var import_db = require("../db");
var import_logger = require("../logger");
var import_errors = require("../errors");
const log = (0, import_logger.createLogger)("AUTH");
const COOKIE_NAME = "pp_session";
const authResolutionMiddleware = new import_rjweb_server.Middleware(
"Auth Resolution Middleware",
"1.0.0"
).load(() => {
log.info("Auth resolution middleware loaded");
}).httpRequest(async (_config, _server, context, ctr) => {
const cookieToken = ctr.cookies.get(COOKIE_NAME);
const tokenProvided = Boolean(cookieToken);
const data = context.data(authResolutionMiddleware);
if (!cookieToken) {
data.auth = { success: false, message: "No session", tokenProvided: false };
return;
}
const session = await import_db.prisma.session.findFirst({
where: { hash: cookieToken },
include: { user: true }
});
if (!session) {
data.auth = { success: false, message: "Invalid session", tokenProvided };
return;
}
data.auth = { success: true, user: session.user, sessionId: session.id };
}).httpRequestContext(
(_config, Original) => class extends Original {
getAuth() {
const data = this.context.data(authResolutionMiddleware);
if (!data.auth) {
return { success: false, message: "Auth not resolved", tokenProvided: false };
}
return data.auth;
}
}
).export();
const authEnforcementMiddleware = new import_rjweb_server.Middleware(
"Auth Enforcement Middleware",
"1.0.0"
).httpRequest(async (_config, _server, context, ctr, end) => {
const data = context.data(authResolutionMiddleware);
const auth = data.auth;
if (!auth || auth.success || !auth.tokenProvided) {
return;
}
return end(
ctr.status(import_errors.ERROR_MESSAGES.UNAUTHORIZED.code).print({
status: "FAILED",
message: auth.message
})
);
}).export();
const COOKIE_NAME_EXPORT = COOKIE_NAME;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
COOKIE_NAME_EXPORT,
authEnforcementMiddleware,
authResolutionMiddleware
});
//# sourceMappingURL=auth.js.map