feat: HTTPS-TLS-Sync nach Deploy, Projekte ohne Subdomain, portalPassword-Feld

- previewDeploy.syncPreviewTls(): schreibt Traefik-Router (Host-Regeln) fuer alle
  Preview-Subdomains nach preview-hosts.yml, damit Let's Encrypt Zertifikate
  ausstellt. Laeuft nach jedem Deploy und beim Serverstart (ersetzt das nie
  aufgerufene bash-Script sync-preview-tls.sh).
- createProjectFromTemplate: Subdomain optional. Ohne Subdomain wird nur das
  Gitea-Repo angelegt (projectType 'repo', Status 'created'), kein Deploy.
- customerAdmin: Portal-Passwort liegt jetzt im Feld customers.portalPassword
  statt als __portalPassword__-Prefix in den Notizen; Legacy-Notizen werden
  beim naechsten Update bereinigt. CRM-Stufe (lead/customer) wird beim Setzen
  des Portal-Passworts nicht mehr auf 'active' ueberschrieben.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 16:34:23 +00:00
parent cf4b3ce4d1
commit cc57cf887a
6 changed files with 124 additions and 30 deletions

View File

@@ -229,14 +229,19 @@ export async function createProjectFromTemplate({
owner,
}) {
const targetOwner = owner || config.gitea.defaultOwner
const safeRepoName = slugify(repoName) || slugify(subdomain)
const safeSubdomain = slugify(subdomain) || safeRepoName
const safeRepoName = slugify(repoName) || slugify(displayName) || slugify(subdomain)
// Subdomain ist optional: ohne Subdomain wird nur das Repo angelegt (normales
// Projekt ohne Website-Preview), mit Subdomain zusaetzlich deployed.
const safeSubdomain = slugify(subdomain)
const hasWebsite = Boolean(safeSubdomain)
if (!safeRepoName || !safeSubdomain) {
throw new Error('repoName und subdomain sind erforderlich')
if (!safeRepoName) {
throw new Error('repoName oder displayName ist erforderlich')
}
await ensureSubdomainAvailable(safeSubdomain)
if (hasWebsite) {
await ensureSubdomainAvailable(safeSubdomain)
}
const repo = await generateRepoFromTemplate({
owner: targetOwner,
@@ -247,25 +252,27 @@ export async function createProjectFromTemplate({
const [repoOwner, repoSlug] = repoFullName.split('/')
const branch = await waitForRepoBranch(repoOwner, repoSlug, 'main')
const previewConfig = {
enabled: true,
enabled: hasWebsite,
type: 'static',
branch,
displayName: displayName || safeRepoName,
subdomain: safeSubdomain,
...(hasWebsite ? { subdomain: safeSubdomain } : {}),
templateName: config.gitea.templateRepo,
}
await updatePreviewConfigFile(repoFullName, previewConfig, branch)
let deployResult = { deployed: false }
try {
deployResult = await runDeploy(repoFullName, branch, previewConfig)
} catch (deployErr) {
console.error('[giteaAdmin] deploy failed:', deployErr.message)
deployResult = { deployed: false, error: deployErr.message }
let deployResult = { deployed: false, skipped: !hasWebsite }
if (hasWebsite) {
try {
deployResult = await runDeploy(repoFullName, branch, previewConfig)
} catch (deployErr) {
console.error('[giteaAdmin] deploy failed:', deployErr.message)
deployResult = { deployed: false, error: deployErr.message }
}
}
const previewUrl = buildPreviewUrl(safeSubdomain)
const previewUrl = hasWebsite ? buildPreviewUrl(safeSubdomain) : ''
const project = await upsertWebsiteProjectByRepo(repoFullName, {
customerId,
ticketId,
@@ -276,8 +283,11 @@ export async function createProjectFromTemplate({
repoFullName,
subdomain: safeSubdomain,
previewUrl,
status: deployResult.deployed ? 'deployed' : 'pending',
provisioningStatus: deployResult.deployed ? 'ready' : 'deploy_failed',
projectType: hasWebsite ? 'website' : 'repo',
status: hasWebsite ? (deployResult.deployed ? 'deployed' : 'pending') : 'created',
provisioningStatus: hasWebsite
? (deployResult.deployed ? 'ready' : 'deploy_failed')
: 'ready',
})
return {
@@ -285,6 +295,7 @@ export async function createProjectFromTemplate({
repoFullName,
previewUrl,
subdomain: safeSubdomain,
projectType: hasWebsite ? 'website' : 'repo',
deploy: deployResult,
}
}