Prepare ERP source for Gitea deployment

This commit is contained in:
A R R R Associates
2026-06-20 15:01:44 +05:30
commit 5c75eb6bd9
450 changed files with 67698 additions and 0 deletions
@@ -0,0 +1,167 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">Consultant Profile Domains</h1>
<p class="mt-1 text-sm text-slate-500">Create domains for consultant public profile, login and lead capture pages. Examples: abc.accountants, consultant.filingabc.com, or yourname.arrr.accountant.</p>
</div>
<div class="flex flex-wrap gap-2">
<a href="/domains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">All Domains</a>
<a href="/domains/tenant-subdomains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Tenant Subdomains</a>
<a href="/domains/firm-domain" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Firm Domain</a>
</div>
</div>
{% if errors %}
<div class="rounded-2xl border border-red-200 bg-red-50 p-4 text-sm text-red-700">
<ul class="list-disc pl-5">
{% for err in errors %}<li>{{ err }}</li>{% endfor %}
</ul>
</div>
{% endif %}
{% if message %}
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">{{ message }}</div>
{% endif %}
<div class="grid grid-cols-1 gap-6 xl:grid-cols-3">
<div class="xl:col-span-2 rounded-2xl border bg-white p-5 shadow-soft">
<h2 class="text-lg font-semibold text-slate-900">Create Consultant Domain</h2>
<p class="mt-1 text-sm text-slate-500">Use platform subdomains for quick setup. Use custom domains only after the consultant points DNS to your ERP server.</p>
<form method="post" action="/domains/consultant-domains/create" class="mt-5 space-y-4">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label class="block text-sm font-medium text-slate-700">Consultant</label>
<select name="consultant_id" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm" required>
<option value="">Select consultant</option>
{% for c in consultants %}
<option value="{{ c.id }}">{{ c.firm_name or c.contact_person }}{% if c.email %} — {{ c.email }}{% endif %}</option>
{% endfor %}
</select>
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Domain type</label>
<select name="domain_type" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm">
<option value="consultant_marketplace_subdomain">Consultant platform subdomain</option>
<option value="consultant_firm_domain">Consultant under firm domain</option>
<option value="consultant_custom_domain">Consultant custom domain</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label class="block text-sm font-medium text-slate-700">Marketplace base domain</label>
<input name="base_domain" value="{{ base_domain or 'filingabc.com' }}" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm" placeholder="filingabc.com" />
<p class="mt-1 text-xs text-slate-500">Used for consultant.filingabc.com.</p>
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Firm consultant base domain</label>
<input name="firm_base_domain" value="{{ firm_base_domain or 'arrr.accountant' }}" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm" placeholder="arrr.accountant" />
<p class="mt-1 text-xs text-slate-500">Used for yourname.arrr.accountant.</p>
</div>
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Custom / override domain, optional</label>
<input name="domain_name" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm" placeholder="abc.accountants or yourname.arrr.accountant" />
<p class="mt-1 text-xs text-slate-500">Leave blank to auto-generate based on the selected consultant and base domain. Enter a value for custom domains.</p>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label class="block text-sm font-medium text-slate-700">Parent audit firm, optional</label>
<select name="parent_tenant_id" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm">
<option value="">Use consultant's linked firm / not applicable</option>
{% for t in tenants %}
<option value="{{ t.id }}">{{ t.display_name or t.name }}</option>
{% endfor %}
</select>
</div>
<div class="rounded-2xl border bg-slate-50 p-4 text-sm text-slate-600">
<div class="font-medium text-slate-900">Activation rule</div>
<p class="mt-1">Platform subdomains can be active immediately if wildcard DNS/SSL is managed by you. Custom domains should normally remain pending until DNS verification is done.</p>
</div>
</div>
<label class="flex items-start gap-3 rounded-2xl border bg-slate-50 p-4 text-sm text-slate-700">
<input type="checkbox" name="mark_verified_active" value="1" class="mt-1 rounded border-slate-300" />
<span>
<span class="font-medium text-slate-900">Mark verified and active now</span><br />
Use only when DNS is already pointing to the ERP server and SSL/proxy is ready.
</span>
</label>
<div class="flex justify-end">
<button class="rounded-xl bg-slate-900 px-5 py-2 text-sm font-semibold text-white shadow-sm">Create Consultant Domain</button>
</div>
</form>
</div>
<div class="space-y-4">
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h3 class="font-semibold text-slate-900">Recommended DNS</h3>
<div class="mt-3 space-y-2 text-sm text-slate-600">
<div><span class="font-medium text-slate-900">Platform:</span> *.filingabc.com → ERP server IP/proxy</div>
<div><span class="font-medium text-slate-900">Firm brand:</span> *.arrr.accountant → ERP server IP/proxy</div>
<div><span class="font-medium text-slate-900">Custom:</span> abc.accountants → ERP server IP/proxy</div>
<div><span class="font-medium text-slate-900">SSL:</span> Coolify / proxy / Cloudflare will be configured later in 7T.9.</div>
</div>
</div>
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h3 class="font-semibold text-slate-900">Suggested domains</h3>
<p class="mt-2 text-sm text-slate-600">The suggestions below are generated from consultant firm name or contact person.</p>
</div>
</div>
</div>
<div class="overflow-hidden rounded-2xl border bg-white shadow-soft">
<div class="border-b bg-slate-50 p-4">
<h2 class="font-semibold text-slate-900">Consultant Domain Suggestions</h2>
</div>
{% if candidates %}
<table class="w-full text-sm">
<thead class="bg-slate-50 text-slate-600">
<tr>
<th class="p-3 text-left">Consultant</th>
<th class="p-3 text-left">Platform Domain</th>
<th class="p-3 text-left">Firm Domain</th>
<th class="p-3 text-left">Status</th>
</tr>
</thead>
<tbody>
{% for item in candidates %}
<tr class="border-t align-top">
<td class="p-3">
<div class="font-semibold text-slate-900">{{ item.consultant.firm_name or item.consultant.contact_person }}</div>
<div class="text-xs text-slate-500">{{ item.consultant.email or 'No email configured' }}</div>
</td>
<td class="p-3">
<div class="font-medium text-slate-800">{{ item.platform_domain }}</div>
{% if item.platform_mapping %}<a href="/domains/{{ item.platform_mapping.id }}" class="text-xs text-slate-900 underline">Open mapping</a>{% endif %}
</td>
<td class="p-3">
<div class="font-medium text-slate-800">{{ item.firm_domain }}</div>
{% if item.firm_mapping %}<a href="/domains/{{ item.firm_mapping.id }}" class="text-xs text-slate-900 underline">Open mapping</a>{% endif %}
</td>
<td class="p-3">
{% if item.platform_mapping or item.firm_mapping %}
<span class="rounded-full bg-emerald-50 px-2.5 py-1 text-xs font-medium text-emerald-700">Mapped</span>
{% else %}
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-medium text-slate-700">Not mapped</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="p-8 text-center text-sm text-slate-500">No consultants found.</div>
{% endif %}
</div>
</div>
{% endblock %}
@@ -0,0 +1,71 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">{{ mapping.domain_name }}</h1>
<p class="mt-1 text-sm text-slate-500">Domain mapping details and DNS verification token.</p>
</div>
<div class="flex gap-2">
<a href="/domains/{{ mapping.id }}/ssl" class="rounded-xl border px-4 py-2 text-sm text-slate-700">SSL</a>
<a href="/domains/{{ mapping.id }}/edit" class="rounded-xl border px-4 py-2 text-sm text-slate-700">Edit</a>
<a href="/domains" class="rounded-xl bg-slate-900 px-4 py-2 text-sm text-white">Back to Domains</a>
</div>
</div>
<div class="grid grid-cols-1 gap-5 lg:grid-cols-3">
<div class="rounded-2xl border bg-white p-5 shadow-soft lg:col-span-2">
<h2 class="text-lg font-semibold text-slate-900">Mapping</h2>
<dl class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2 text-sm">
<div><dt class="text-slate-500">Type</dt><dd class="font-medium text-slate-900">{{ mapping.domain_type.replace('_', ' ')|title }}</dd></div>
<div><dt class="text-slate-500">Status</dt><dd class="font-medium text-slate-900">{{ mapping.status.replace('_', ' ')|title }}</dd></div>
<div><dt class="text-slate-500">Audit Firm</dt><dd>{{ mapping.tenant.display_name or mapping.tenant.name if mapping.tenant else '-' }}</dd></div>
<div><dt class="text-slate-500">Branch</dt><dd>{{ mapping.branch.name if mapping.branch else '-' }}</dd></div>
<div><dt class="text-slate-500">Consultant</dt><dd>{{ mapping.consultant.contact_person if mapping.consultant else '-' }}</dd></div>
<div><dt class="text-slate-500">Parent Firm</dt><dd>{{ mapping.parent_tenant.display_name or mapping.parent_tenant.name if mapping.parent_tenant else '-' }}</dd></div>
<div><dt class="text-slate-500">Primary</dt><dd>{{ 'Yes' if mapping.is_primary else 'No' }}</dd></div>
<div><dt class="text-slate-500">SSL Mode</dt><dd>{{ mapping.ssl_mode }}</dd></div>
<div><dt class="text-slate-500">SSL Status</dt><dd>{{ (mapping.ssl_status or "not_checked").replace("_", " ")|title }}</dd></div>
</dl>
{% if mapping.notes %}<div class="mt-5 rounded-xl bg-slate-50 p-4 text-sm text-slate-700">{{ mapping.notes }}</div>{% endif %}
</div>
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h2 class="text-lg font-semibold text-slate-900">DNS Verification</h2>
{% if dns_result is defined and dns_result %}
<div class="mt-3 rounded-xl {% if dns_result.ok %}bg-emerald-50 text-emerald-800{% else %}bg-red-50 text-red-800{% endif %} p-3 text-sm">
<div class="font-semibold">{{ 'Verification successful' if dns_result.ok else 'Verification failed' }}</div>
<div class="mt-1">{{ dns_result.message }}</div>
{% if dns_result.found_values %}
<div class="mt-2 text-xs">Found TXT: {{ dns_result.found_values|join(', ') }}</div>
{% endif %}
</div>
{% endif %}
{% if mapping.is_verified %}
<div class="mt-3 rounded-xl bg-emerald-50 p-3 text-sm text-emerald-800">This domain is marked as verified.</div>
{% else %}
<div class="mt-3 rounded-xl bg-amber-50 p-3 text-sm text-amber-800">Add the TXT record below at your DNS provider. Click Verify DNS after adding the TXT record at your DNS provider.</div>
{% endif %}
<div class="mt-4 space-y-3 text-sm">
<div><div class="text-slate-500">TXT Name</div><code class="block rounded-lg bg-slate-100 p-2 text-xs break-all">{{ mapping.dns_txt_name or '-' }}</code></div>
<div><div class="text-slate-500">TXT Value</div><code class="block rounded-lg bg-slate-100 p-2 text-xs break-all">{{ mapping.dns_txt_value or '-' }}</code></div>
</div>
<div class="mt-4 flex flex-col gap-2">
<form method="post" action="/domains/{{ mapping.id }}/verify-dns">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<button class="w-full rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white">Verify DNS TXT Now</button>
</form>
<form method="post" action="/domains/{{ mapping.id }}/mark-verified">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<button class="w-full rounded-xl bg-emerald-700 px-4 py-2 text-sm font-medium text-white">Mark Verified Manually</button>
</form>
<form method="post" action="/domains/{{ mapping.id }}/regenerate-token">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<button class="w-full rounded-xl border px-4 py-2 text-sm text-slate-700">Regenerate Token</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
@@ -0,0 +1,98 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">Audit Firm Custom Domain</h1>
<p class="mt-1 text-sm text-slate-500">Create a verified mapping for your own audit firm domain, for example arrr.associates.</p>
</div>
<div class="flex flex-wrap gap-2">
<a href="/domains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">All Domains</a>
<a href="/domains/tenant-subdomains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Tenant Subdomains</a>
</div>
</div>
{% if errors %}
<div class="rounded-2xl border border-red-200 bg-red-50 p-4 text-sm text-red-700">
<ul class="list-disc pl-5">
{% for err in errors %}<li>{{ err }}</li>{% endfor %}
</ul>
</div>
{% endif %}
{% if message %}
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">{{ message }}</div>
{% endif %}
<div class="grid grid-cols-1 gap-6 xl:grid-cols-3">
<div class="xl:col-span-2 rounded-2xl border bg-white p-5 shadow-soft">
<h2 class="text-lg font-semibold text-slate-900">Create / Link Firm Domain</h2>
<p class="mt-1 text-sm text-slate-500">Use this for your own branded firm domain. For other tenant firms, use auditfirm.filingabc.com subdomains first.</p>
<form method="post" action="/domains/firm-domain/create" class="mt-5 space-y-4">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<div>
<label class="block text-sm font-medium text-slate-700">Firm domain</label>
<input name="domain_name" value="{{ domain_name or 'arrr.associates' }}" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm" placeholder="arrr.associates" />
<p class="mt-1 text-xs text-slate-500">Enter the domain only. Do not include http://, https:// or path.</p>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label class="block text-sm font-medium text-slate-700">Audit firm / tenant</label>
<select name="tenant_id" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm" required>
<option value="">Select audit firm</option>
{% for t in tenants %}
<option value="{{ t.id }}">{{ t.display_name or t.name }}</option>
{% endfor %}
</select>
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Branch, optional</label>
<select name="branch_id" class="mt-1 w-full rounded-xl border px-3 py-2 text-sm">
<option value="">Firm-level domain</option>
{% for b in branches %}
<option value="{{ b.id }}">{{ b.name }}</option>
{% endfor %}
</select>
</div>
</div>
<label class="flex items-start gap-3 rounded-2xl border bg-slate-50 p-4 text-sm text-slate-700">
<input type="checkbox" name="mark_verified_active" value="1" class="mt-1 rounded border-slate-300" />
<span>
<span class="font-medium text-slate-900">Mark verified and active now</span><br />
Use this only if DNS is already pointing to the ERP server and SSL/proxy is ready. Otherwise leave unchecked and verify later from the domain detail page.
</span>
</label>
<div class="flex justify-end">
<button class="rounded-xl bg-slate-900 px-5 py-2 text-sm font-semibold text-white shadow-sm">Create Firm Domain</button>
</div>
</form>
</div>
<div class="space-y-4">
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h3 class="font-semibold text-slate-900">Recommended DNS</h3>
<div class="mt-3 space-y-2 text-sm text-slate-600">
<div><span class="font-medium text-slate-900">A record:</span> arrr.associates → your server IP</div>
<div><span class="font-medium text-slate-900">CNAME:</span> www.arrr.associates → arrr.associates</div>
<div><span class="font-medium text-slate-900">SSL:</span> configure in Coolify / proxy / Cloudflare</div>
</div>
</div>
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h3 class="font-semibold text-slate-900">Verification</h3>
<p class="mt-2 text-sm text-slate-600">If not marked active now, open the created domain record and use the DNS TXT token shown there.</p>
{% if existing %}
<div class="mt-4 rounded-xl border bg-slate-50 p-3 text-sm">
<div class="font-semibold text-slate-900">Existing mapping found</div>
<div class="mt-1 text-slate-600">{{ existing.domain_name }} — {{ existing.status.replace('_', ' ')|title }}</div>
<a href="/domains/{{ existing.id }}" class="mt-2 inline-block text-slate-900 underline">Open mapping</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
@@ -0,0 +1,104 @@
{% extends "ui/templates/base/layout.html" %}
{% set f = form if form else {} %}
{% block content %}
<div class="space-y-6">
<div>
<h1 class="text-2xl font-semibold text-slate-900">{{ title }}</h1>
<p class="mt-1 text-sm text-slate-500">Create or update a domain mapping. Runtime resolver will use this table in Phase 7T.2.</p>
</div>
{% if errors %}
<div class="rounded-2xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-800">
<div class="font-semibold">Please fix the following:</div>
<ul class="mt-2 list-disc pl-5">{% for e in errors %}<li>{{ e }}</li>{% endfor %}</ul>
</div>
{% endif %}
<form method="post" class="max-w-5xl rounded-2xl border bg-white p-5 shadow-soft">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<label class="grid gap-1 md:col-span-2">
<span class="text-sm text-slate-600">Domain Name</span>
<input class="rounded-xl border px-3 py-2" name="domain_name" required placeholder="filingabc.com" value="{{ f.domain_name if f.domain_name is defined else (mapping.domain_name if mapping else '') }}" />
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">Domain Type</span>
{% set selected_type = f.domain_type if f.domain_type is defined else (mapping.domain_type if mapping else 'marketplace') %}
<select class="rounded-xl border px-3 py-2" name="domain_type" required>
{% for code, label in domain_types %}<option value="{{ code }}" {% if selected_type == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">Status</span>
{% set selected_status = f.status if f.status is defined else (mapping.status if mapping else 'draft') %}
<select class="rounded-xl border px-3 py-2" name="status">
{% for code, label in statuses %}<option value="{{ code }}" {% if selected_status == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">Audit Firm</span>
{% set selected_tenant = f.tenant_id if f.tenant_id is defined else (mapping.tenant_id if mapping else '') %}
<select class="rounded-xl border px-3 py-2" name="tenant_id">
<option value="">Not applicable</option>
{% for t in tenants %}<option value="{{ t.id }}" {% if selected_tenant == t.id %}selected{% endif %}>{{ t.display_name or t.name }} ({{ t.code }})</option>{% endfor %}
</select>
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">Branch</span>
{% set selected_branch = f.branch_id if f.branch_id is defined else (mapping.branch_id if mapping else '') %}
<select class="rounded-xl border px-3 py-2" name="branch_id">
<option value="">Not applicable</option>
{% for b in branches %}<option value="{{ b.id }}" {% if selected_branch == b.id %}selected{% endif %}>{{ b.name }} (Firm {{ b.tenant_id }})</option>{% endfor %}
</select>
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">Consultant</span>
{% set selected_consultant = f.consultant_id if f.consultant_id is defined else (mapping.consultant_id if mapping else '') %}
<select class="rounded-xl border px-3 py-2" name="consultant_id">
<option value="">Not applicable</option>
{% for c in consultants %}<option value="{{ c.id }}" {% if selected_consultant == c.id %}selected{% endif %}>{{ c.contact_person }}{% if c.firm_name %} - {{ c.firm_name }}{% endif %}</option>{% endfor %}
</select>
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">Parent Firm for Consultant Domain</span>
{% set selected_parent = f.parent_tenant_id if f.parent_tenant_id is defined else (mapping.parent_tenant_id if mapping else '') %}
<select class="rounded-xl border px-3 py-2" name="parent_tenant_id">
<option value="">Not applicable</option>
{% for t in tenants %}<option value="{{ t.id }}" {% if selected_parent == t.id %}selected{% endif %}>{{ t.display_name or t.name }} ({{ t.code }})</option>{% endfor %}
</select>
</label>
<label class="grid gap-1">
<span class="text-sm text-slate-600">SSL Mode</span>
{% set selected_ssl = f.ssl_mode if f.ssl_mode is defined else (mapping.ssl_mode if mapping else 'manual') %}
<select class="rounded-xl border px-3 py-2" name="ssl_mode">
{% for code, label in ssl_modes %}<option value="{{ code }}" {% if selected_ssl == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
</label>
<div class="flex items-center gap-6 rounded-xl border bg-slate-50 px-4 py-3">
{% set primary_checked = f.is_primary if f.is_primary is defined else (mapping.is_primary if mapping else False) %}
{% set verified_checked = f.is_verified if f.is_verified is defined else (mapping.is_verified if mapping else False) %}
<label class="flex items-center gap-2 text-sm"><input type="checkbox" name="is_primary" {% if primary_checked %}checked{% endif %}> Primary</label>
<label class="flex items-center gap-2 text-sm"><input type="checkbox" name="is_verified" {% if verified_checked %}checked{% endif %}> Verified manually</label>
</div>
<label class="grid gap-1 md:col-span-2">
<span class="text-sm text-slate-600">Notes</span>
<textarea class="rounded-xl border px-3 py-2" name="notes" rows="4">{{ f.notes if f.notes is defined else (mapping.notes if mapping else '') }}</textarea>
</label>
</div>
<div class="mt-5 flex gap-3">
<button class="rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white">Save Domain</button>
<a href="/domains" class="rounded-xl border px-4 py-2 text-sm text-slate-700">Cancel</a>
</div>
</form>
</div>
{% endblock %}
@@ -0,0 +1,82 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">Domain Mapping</h1>
<p class="mt-1 text-sm text-slate-500">Map marketplace, audit firm, branch and consultant domains. Tenant subdomains like auditfirm.filingabc.com, firm domains like arrr.associates, and consultant profile domains like abc.accountants or yourname.arrr.accountant can be created from here.</p>
</div>
<div class="flex flex-wrap gap-2">
<a href="/domains/ssl" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">SSL Automation</a>
<a href="/domains/verification" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Verify Domains</a>
<a href="/domains/firm-domain" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Firm Domain</a>
<a href="/domains/consultant-domains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Consultant Domains</a>
<a href="/domains/tenant-subdomains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Tenant Subdomains</a>
<a href="/domains/new" class="rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white shadow-sm">Add Domain</a>
</div>
</div>
<form method="get" class="rounded-2xl border bg-white p-4 shadow-soft">
<div class="grid grid-cols-1 gap-3 md:grid-cols-4">
<input class="rounded-xl border px-3 py-2 text-sm" name="q" value="{{ filters.q }}" placeholder="Search domain" />
<select class="rounded-xl border px-3 py-2 text-sm" name="domain_type">
<option value="">All domain types</option>
{% for code, label in domain_types %}<option value="{{ code }}" {% if filters.domain_type == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
<select class="rounded-xl border px-3 py-2 text-sm" name="status">
<option value="">All statuses</option>
{% for code, label in statuses %}<option value="{{ code }}" {% if filters.status == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
</select>
<button class="rounded-xl bg-slate-800 px-4 py-2 text-sm font-medium text-white">Filter</button>
</div>
</form>
<div class="overflow-hidden rounded-2xl border bg-white shadow-soft">
{% if mappings %}
<table class="w-full text-sm">
<thead class="bg-slate-50 text-slate-600">
<tr>
<th class="p-3 text-left">Domain</th>
<th class="p-3 text-left">Type</th>
<th class="p-3 text-left">Mapped To</th>
<th class="p-3 text-left">Status</th>
<th class="p-3 text-left">Verification</th>
<th class="p-3 text-left">Action</th>
</tr>
</thead>
<tbody>
{% for m in mappings %}
<tr class="border-t align-top">
<td class="p-3">
<div class="font-semibold text-slate-900">{{ m.domain_name }}</div>
<div class="text-xs text-slate-500">SSL: {{ m.ssl_mode }} / {{ (m.ssl_status or "not_checked").replace("_", " ")|title }}</div>
</td>
<td class="p-3">{{ m.domain_type.replace('_', ' ')|title }}</td>
<td class="p-3 text-slate-700">
{% if m.tenant %}<div>Firm: {{ m.tenant.display_name or m.tenant.name }}</div>{% endif %}
{% if m.branch %}<div>Branch: {{ m.branch.name }}</div>{% endif %}
{% if m.consultant %}<div>Consultant: {{ m.consultant.contact_person }}</div>{% endif %}
{% if not m.tenant and not m.branch and not m.consultant %}<span class="text-slate-400">Marketplace / platform</span>{% endif %}
</td>
<td class="p-3">
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-medium text-slate-700">{{ m.status.replace('_', ' ')|title }}</span>
{% if m.is_primary %}<span class="ml-1 rounded-full bg-indigo-50 px-2.5 py-1 text-xs font-medium text-indigo-700">Primary</span>{% endif %}
</td>
<td class="p-3">
{% if m.is_verified %}
<span class="rounded-full bg-emerald-50 px-2.5 py-1 text-xs font-medium text-emerald-700">Verified</span>
{% else %}
<span class="rounded-full bg-amber-50 px-2.5 py-1 text-xs font-medium text-amber-700">Pending</span>
{% endif %}
</td>
<td class="p-3"><div class="flex flex-col gap-1"><a class="text-slate-900 underline" href="/domains/{{ m.id }}">Open</a><a class="text-slate-600 underline" href="/domains/{{ m.id }}/ssl">SSL</a></div></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="p-8 text-center text-sm text-slate-500">No domain mappings found.</div>
{% endif %}
</div>
</div>
{% endblock %}
@@ -0,0 +1,82 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">SSL Automation</h1>
<p class="mt-1 text-sm text-slate-500">Track SSL readiness for marketplace, audit firm and consultant domains. Certificate issuance is handled by your deployment proxy such as Coolify, Caddy, Traefik, Cloudflare or Nginx + Certbot.</p>
</div>
<div class="flex flex-wrap gap-2">
<form method="post" action="/domains/ssl/check-all">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<button class="rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white shadow-sm">Check Active SSL</button>
</form>
<a href="/domains/verification" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">DNS Verification</a>
<a href="/domains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700 shadow-sm">Domains</a>
</div>
</div>
{% if ssl_results is defined and ssl_results %}
<div class="rounded-2xl border bg-white p-4 shadow-soft">
<h2 class="text-sm font-semibold text-slate-900">Latest SSL check</h2>
<div class="mt-3 grid gap-2">
{% for mapping, result in ssl_results %}
<div class="rounded-xl {% if result.ok %}bg-emerald-50 text-emerald-800{% else %}bg-red-50 text-red-800{% endif %} p-3 text-sm">
<span class="font-semibold">{{ mapping.domain_name }}:</span> {{ result.message }}
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<div class="text-sm text-slate-500">Verified active domains</div>
<div class="mt-2 text-3xl font-semibold text-slate-900">{{ domains|selectattr('is_verified')|selectattr('status', 'equalto', 'active')|list|length }}</div>
</div>
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<div class="text-sm text-slate-500">SSL active</div>
<div class="mt-2 text-3xl font-semibold text-emerald-700">{{ domains|selectattr('ssl_status', 'equalto', 'active')|list|length }}</div>
</div>
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<div class="text-sm text-slate-500">Needs attention</div>
<div class="mt-2 text-3xl font-semibold text-amber-700">{{ domains|rejectattr('ssl_status', 'equalto', 'active')|list|length }}</div>
</div>
</div>
<div class="overflow-hidden rounded-2xl border bg-white shadow-soft">
<table class="w-full text-sm">
<thead class="bg-slate-50 text-slate-600">
<tr>
<th class="p-3 text-left">Domain</th>
<th class="p-3 text-left">Type</th>
<th class="p-3 text-left">DNS</th>
<th class="p-3 text-left">SSL Mode</th>
<th class="p-3 text-left">SSL Status</th>
<th class="p-3 text-left">Expiry</th>
<th class="p-3 text-left">Action</th>
</tr>
</thead>
<tbody>
{% for m in domains %}
<tr class="border-t align-top">
<td class="p-3 font-semibold text-slate-900">{{ m.domain_name }}</td>
<td class="p-3">{{ m.domain_type.replace('_', ' ')|title }}</td>
<td class="p-3">
{% if m.is_verified and m.status == 'active' %}<span class="rounded-full bg-emerald-50 px-2.5 py-1 text-xs font-medium text-emerald-700">Verified</span>{% else %}<span class="rounded-full bg-amber-50 px-2.5 py-1 text-xs font-medium text-amber-700">Pending</span>{% endif %}
</td>
<td class="p-3">{{ m.ssl_mode or 'manual' }}</td>
<td class="p-3">
{% set ssl_status = m.ssl_status or 'not_checked' %}
<span class="rounded-full {% if ssl_status == 'active' %}bg-emerald-50 text-emerald-700{% elif ssl_status == 'failed' %}bg-red-50 text-red-700{% else %}bg-slate-100 text-slate-700{% endif %} px-2.5 py-1 text-xs font-medium">{{ ssl_status.replace('_', ' ')|title }}</span>
{% if m.ssl_last_error %}<div class="mt-1 max-w-sm truncate text-xs text-red-600">{{ m.ssl_last_error }}</div>{% endif %}
</td>
<td class="p-3 text-slate-600">{{ m.ssl_not_after_utc.strftime('%d-%m-%Y') if m.ssl_not_after_utc else '-' }}</td>
<td class="p-3"><a href="/domains/{{ m.id }}/ssl" class="text-slate-900 underline">Open SSL</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
@@ -0,0 +1,75 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">SSL Setup: {{ mapping.domain_name }}</h1>
<p class="mt-1 text-sm text-slate-500">Use this page to track DNS, proxy and certificate readiness.</p>
</div>
<div class="flex gap-2">
<a href="/domains/{{ mapping.id }}" class="rounded-xl border px-4 py-2 text-sm text-slate-700">Domain Detail</a>
<a href="/domains/ssl" class="rounded-xl bg-slate-900 px-4 py-2 text-sm text-white">Back to SSL</a>
</div>
</div>
{% if ssl_result is defined and ssl_result %}
<div class="rounded-2xl {% if ssl_result.ok %}bg-emerald-50 text-emerald-800{% else %}bg-red-50 text-red-800{% endif %} p-4 text-sm">
<div class="font-semibold">{{ ssl_result.status.replace('_', ' ')|title }}</div>
<div class="mt-1">{{ ssl_result.message }}</div>
</div>
{% endif %}
<div class="grid grid-cols-1 gap-5 lg:grid-cols-3">
<div class="rounded-2xl border bg-white p-5 shadow-soft lg:col-span-2">
<h2 class="text-lg font-semibold text-slate-900">Readiness checklist</h2>
<div class="mt-4 space-y-3 text-sm">
<div class="flex items-start gap-3"><span class="mt-0.5 rounded-full px-2 py-0.5 text-xs {% if mapping.is_verified and mapping.status == 'active' %}bg-emerald-50 text-emerald-700{% else %}bg-amber-50 text-amber-700{% endif %}">{{ 'Done' if mapping.is_verified and mapping.status == 'active' else 'Pending' }}</span><div><div class="font-medium text-slate-900">DNS TXT verification</div><div class="text-slate-500">The domain should be verified and active in ERP.</div></div></div>
<div class="flex items-start gap-3"><span class="mt-0.5 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-700">Manual</span><div><div class="font-medium text-slate-900">A/CNAME record</div><div class="text-slate-500">Point {{ mapping.domain_name }} to your Coolify/proxy server before certificate issue.</div></div></div>
<div class="flex items-start gap-3"><span class="mt-0.5 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-700">Proxy</span><div><div class="font-medium text-slate-900">Add domain in deployment proxy</div><div class="text-slate-500">Coolify/Caddy/Traefik/Nginx must route this domain to the FastAPI app.</div></div></div>
<div class="flex items-start gap-3"><span class="mt-0.5 rounded-full px-2 py-0.5 text-xs {% if mapping.ssl_status == 'active' %}bg-emerald-50 text-emerald-700{% else %}bg-amber-50 text-amber-700{% endif %}">{{ (mapping.ssl_status or 'not_checked').replace('_', ' ')|title }}</span><div><div class="font-medium text-slate-900">Certificate check</div><div class="text-slate-500">ERP checks public HTTPS on port 443 and records certificate expiry.</div></div></div>
</div>
<div class="mt-5 flex flex-wrap gap-2">
<form method="post" action="/domains/{{ mapping.id }}/ssl/check">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<button class="rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white">Check SSL Now</button>
</form>
<form method="post" action="/domains/{{ mapping.id }}/ssl/mark-managed" class="flex gap-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<select name="provider" class="rounded-xl border px-3 py-2 text-sm">
<option value="coolify" {% if mapping.ssl_mode == 'coolify' %}selected{% endif %}>Coolify</option>
<option value="caddy" {% if mapping.ssl_mode == 'caddy' %}selected{% endif %}>Caddy</option>
<option value="traefik" {% if mapping.ssl_mode == 'traefik' %}selected{% endif %}>Traefik</option>
<option value="cloudflare" {% if mapping.ssl_mode == 'cloudflare' %}selected{% endif %}>Cloudflare</option>
<option value="manual" {% if mapping.ssl_mode == 'manual' %}selected{% endif %}>Manual</option>
</select>
<button class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700">Mark Managed</button>
</form>
</div>
</div>
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h2 class="text-lg font-semibold text-slate-900">Certificate status</h2>
<dl class="mt-4 space-y-3 text-sm">
<div><dt class="text-slate-500">SSL Status</dt><dd class="font-medium text-slate-900">{{ (mapping.ssl_status or 'not_checked').replace('_', ' ')|title }}</dd></div>
<div><dt class="text-slate-500">SSL Mode</dt><dd>{{ mapping.ssl_mode or 'manual' }}</dd></div>
<div><dt class="text-slate-500">Last Checked</dt><dd>{{ mapping.ssl_last_checked_at_utc.strftime('%d-%m-%Y %H:%M') if mapping.ssl_last_checked_at_utc else '-' }}</dd></div>
<div><dt class="text-slate-500">Valid Until</dt><dd>{{ mapping.ssl_not_after_utc.strftime('%d-%m-%Y') if mapping.ssl_not_after_utc else '-' }}</dd></div>
<div><dt class="text-slate-500">Issuer</dt><dd class="break-words">{{ mapping.ssl_issuer or '-' }}</dd></div>
<div><dt class="text-slate-500">Subject</dt><dd class="break-words">{{ mapping.ssl_subject or '-' }}</dd></div>
</dl>
{% if mapping.ssl_last_error %}<div class="mt-4 rounded-xl bg-red-50 p-3 text-sm text-red-800">{{ mapping.ssl_last_error }}</div>{% endif %}
</div>
</div>
<div class="space-y-4">
<h2 class="text-lg font-semibold text-slate-900">Proxy snippets / setup notes</h2>
{% for snippet in snippets %}
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h3 class="font-semibold text-slate-900">{{ snippet.title }}</h3>
<pre class="mt-3 overflow-auto rounded-xl bg-slate-900 p-4 text-xs text-slate-100"><code>{{ snippet.body }}</code></pre>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
@@ -0,0 +1,90 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">Tenant Subdomains</h1>
<p class="mt-1 text-sm text-slate-500">Create audit firm platform subdomains like <strong>auditfirm.filingabc.com</strong>. This uses your existing domain_mappings table.</p>
</div>
<a href="/domains" class="rounded-xl border px-4 py-2 text-sm text-slate-700">Back to Domains</a>
</div>
{% if errors %}
<div class="rounded-2xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-800">
<div class="font-semibold">Please fix the following:</div>
<ul class="mt-2 list-disc pl-5">{% for e in errors %}<li>{{ e }}</li>{% endfor %}</ul>
</div>
{% endif %}
{% if message %}<div class="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">{{ message }}</div>{% endif %}
<form method="get" class="rounded-2xl border bg-white p-4 shadow-soft">
<div class="grid grid-cols-1 gap-3 md:grid-cols-4">
<label class="grid gap-1 md:col-span-2">
<span class="text-xs font-medium uppercase tracking-wide text-slate-500">Platform base domain</span>
<input class="rounded-xl border px-3 py-2 text-sm" name="base_domain" value="{{ base_domain }}" placeholder="filingabc.com" />
</label>
<div class="flex items-end"><button class="rounded-xl bg-slate-800 px-4 py-2 text-sm font-medium text-white">Refresh Suggestions</button></div>
</div>
<p class="mt-3 text-xs text-slate-500">For local testing you can use <code>filingabc.local</code>. For production use <code>filingabc.com</code> and configure wildcard DNS/SSL for <code>*.filingabc.com</code>.</p>
</form>
<div class="rounded-2xl border bg-white p-4 shadow-soft">
<h2 class="text-lg font-semibold text-slate-900">Audit firm subdomain candidates</h2>
<div class="mt-4 overflow-hidden rounded-xl border">
<table class="w-full text-sm">
<thead class="bg-slate-50 text-slate-600">
<tr>
<th class="p-3 text-left">Audit Firm</th>
<th class="p-3 text-left">Suggested Subdomain</th>
<th class="p-3 text-left">Current Status</th>
<th class="p-3 text-left">Action</th>
</tr>
</thead>
<tbody>
{% for item in candidates %}
{% set tenant = item.tenant %}
{% set mapping = item.mapping %}
<tr class="border-t align-top">
<td class="p-3">
<div class="font-semibold text-slate-900">{{ tenant.display_name or tenant.name }}</div>
<div class="text-xs text-slate-500">Code: {{ tenant.code }} · ID: {{ tenant.id }}</div>
</td>
<td class="p-3">
<code class="rounded-lg bg-slate-100 px-2 py-1 text-xs">{{ item.domain_name }}</code>
</td>
<td class="p-3">
{% if mapping %}
<div><span class="rounded-full bg-emerald-50 px-2.5 py-1 text-xs font-medium text-emerald-700">Created</span></div>
<div class="mt-2 text-xs text-slate-500">{{ mapping.status|title }}{% if mapping.is_verified %} · Verified{% else %} · Pending verification{% endif %}</div>
{% else %}
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-medium text-slate-700">Not created</span>
{% endif %}
</td>
<td class="p-3">
{% if mapping %}
<a href="/domains/{{ mapping.id }}" class="rounded-xl border px-3 py-2 text-xs font-medium text-slate-700">Open Mapping</a>
{% else %}
<form method="post" action="/domains/tenant-subdomains/create" class="space-y-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<input type="hidden" name="tenant_id" value="{{ tenant.id }}" />
<input type="hidden" name="base_domain" value="{{ base_domain }}" />
<label class="flex items-center gap-2 text-xs text-slate-600"><input type="checkbox" name="mark_verified_active" checked /> Mark active/verified</label>
<button class="rounded-xl bg-slate-900 px-3 py-2 text-xs font-medium text-white">Create Subdomain</button>
</form>
{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="4" class="p-8 text-center text-slate-500">No audit firms found.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="rounded-2xl border border-blue-100 bg-blue-50 p-4 text-sm text-blue-900">
<div class="font-semibold">Deployment note</div>
<p class="mt-1">This phase creates and resolves tenant subdomain mappings in the ERP. DNS/SSL is still deployment-level: point <code>*.{{ base_domain }}</code> to your server and configure wildcard SSL in Coolify/Caddy/Traefik/Nginx as applicable.</p>
</div>
</div>
{% endblock %}
@@ -0,0 +1,78 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h1 class="text-2xl font-semibold text-slate-900">Custom Domain Verification</h1>
<p class="mt-1 text-sm text-slate-500">Verify DNS TXT records for custom firm, consultant and marketplace domains before activating runtime routing.</p>
</div>
<div class="flex gap-2">
<a href="/domains" class="rounded-xl border px-4 py-2 text-sm font-medium text-slate-700">Back to Domains</a>
<form method="post" action="/domains/verification/run">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<input type="hidden" name="limit" value="25" />
<button class="rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white">Verify Pending</button>
</form>
</div>
</div>
{% if results %}
<div class="rounded-2xl border bg-white p-5 shadow-soft">
<h2 class="text-lg font-semibold text-slate-900">Verification Result</h2>
<div class="mt-4 space-y-3">
{% for mapping, result in results %}
<div class="rounded-xl border p-4 {% if result.ok %}border-emerald-200 bg-emerald-50{% else %}border-red-200 bg-red-50{% endif %}">
<div class="flex flex-col gap-1 md:flex-row md:items-center md:justify-between">
<div class="font-semibold text-slate-900">{{ mapping.domain_name }}</div>
<span class="text-xs font-semibold {% if result.ok %}text-emerald-700{% else %}text-red-700{% endif %}">{{ 'Verified' if result.ok else 'Pending' }}</span>
</div>
<div class="mt-1 text-sm text-slate-700">{{ result.message }}</div>
{% if result.found_values %}<div class="mt-2 text-xs text-slate-600">Found: {{ result.found_values|join(', ') }}</div>{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="rounded-2xl border bg-white shadow-soft overflow-hidden">
<div class="border-b bg-slate-50 px-5 py-4">
<h2 class="text-lg font-semibold text-slate-900">Domains Awaiting DNS Verification</h2>
<p class="mt-1 text-sm text-slate-500">Add the TXT record at your DNS provider, wait for DNS propagation, then verify.</p>
</div>
{% if pending %}
<div class="divide-y">
{% for m in pending %}
<div class="grid grid-cols-1 gap-4 p-5 lg:grid-cols-12 lg:items-center">
<div class="lg:col-span-3">
<div class="font-semibold text-slate-900">{{ m.domain_name }}</div>
<div class="text-xs text-slate-500">{{ m.domain_type.replace('_', ' ')|title }}</div>
</div>
<div class="lg:col-span-6 text-sm">
<div class="text-slate-500">TXT Name</div>
<code class="mt-1 block rounded-lg bg-slate-100 p-2 text-xs break-all">{{ m.dns_txt_name or '-' }}</code>
<div class="mt-2 text-slate-500">TXT Value</div>
<code class="mt-1 block rounded-lg bg-slate-100 p-2 text-xs break-all">{{ m.dns_txt_value or '-' }}</code>
</div>
<div class="lg:col-span-3 flex flex-col gap-2">
<form method="post" action="/domains/{{ m.id }}/verify-dns">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<button class="w-full rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white">Verify DNS</button>
</form>
<a href="/domains/{{ m.id }}" class="w-full rounded-xl border px-4 py-2 text-center text-sm font-medium text-slate-700">Open Details</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="p-8 text-center text-sm text-slate-500">No pending domain verification records.</div>
{% endif %}
</div>
<div class="rounded-2xl border bg-white p-5 text-sm text-slate-600 shadow-soft">
<h3 class="font-semibold text-slate-900">DNS record format</h3>
<p class="mt-2">For a domain such as <strong>arrr.associates</strong>, add a TXT record at:</p>
<code class="mt-2 block rounded-lg bg-slate-100 p-2 text-xs">_audit-firm-verify.arrr.associates</code>
<p class="mt-2">The TXT value must exactly match the verification token shown for that domain.</p>
</div>
</div>
{% endblock %}