Snapshot: full project state
This commit is contained in:
55
templates/application.html
Normal file
55
templates/application.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="app-head">
|
||||
<div>
|
||||
<h1>{{ a['institution'] }}</h1>
|
||||
<div class="muted">{{ a['account_type'] | replace('_', ' ') | title }} · started {{ a['created_at'] }}</div>
|
||||
</div>
|
||||
<form method="post" action="{{ url_for('set_status', app_id=a['id']) }}" class="inline">
|
||||
<select name="status" onchange="this.form.submit()">
|
||||
{% for s in ['researching', 'in_progress', 'submitted', 'approved', 'denied'] %}
|
||||
<option value="{{ s }}" {% if a['status'] == s %}selected{% endif %}>{{ s }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h2>Requirements</h2>
|
||||
<ul class="checklist">
|
||||
{% for item in items %}
|
||||
<li>
|
||||
<form method="post" action="{{ url_for('toggle_item', app_id=a['id'], item_id=item['id']) }}">
|
||||
<button type="submit" class="checkbox {{ 'checked' if item['done'] else '' }}">
|
||||
{{ '✓' if item['done'] else '' }}
|
||||
</button>
|
||||
<span class="{{ 'done' if item['done'] else '' }}">{{ item['label'] }}</span>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h2>Your info (for pre-filling this application)</h2>
|
||||
{% if profile %}
|
||||
<div class="profile-panel">
|
||||
{% for key, label in [('full_name','Name'),('date_of_birth','DOB'),('ssn','SSN/TIN'),('address_line1','Address'),('city','City'),('state','State'),('zip','ZIP'),('phone','Phone'),('email','Email')] %}
|
||||
{% if profile.get(key) %}
|
||||
<div><span class="plabel">{{ label }}</span><span class="pvalue">{{ profile[key] }}</span></div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="muted">Edit in <a href="{{ url_for('profile') }}">Profile</a>.</p>
|
||||
{% else %}
|
||||
<p class="muted">No profile yet. <a href="{{ url_for('profile') }}">Add your info</a> to pre-fill.</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>Notes</h2>
|
||||
<form method="post" action="{{ url_for('set_notes', app_id=a['id']) }}" class="form">
|
||||
<textarea name="notes" rows="3">{{ a['notes'] }}</textarea>
|
||||
<button type="submit" class="btn">Save notes</button>
|
||||
</form>
|
||||
|
||||
<form method="post" action="{{ url_for('delete_application', app_id=a['id']) }}"
|
||||
onsubmit="return confirm('Delete this application?');">
|
||||
<button type="submit" class="btn danger">Delete application</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
41
templates/base.html
Normal file
41
templates/base.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title>Castor — Account Onboarding</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="brand">
|
||||
<span class="logo">✦</span>
|
||||
<span>Castor</span>
|
||||
<span class="tag">account onboarding assistant</span>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="{{ url_for('index') }}">Applications</a>
|
||||
<a href="{{ url_for('new_application') }}">+ New</a>
|
||||
<a href="{{ url_for('profile') }}">Profile</a>
|
||||
<a href="{{ url_for('vault') }}">Vault</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for cat, msg in messages %}
|
||||
<div class="flash {{ cat }}">{{ msg }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>For opening <strong>your own</strong> accounts in <strong>your own name</strong>. No identity fabrication, no bulk signups, no KYC evasion.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
57
templates/index.html
Normal file
57
templates/index.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title>Castor — Signup Dashboard</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="brand"><span class="logo">✦</span><span>Castor</span><span class="tag">signup dashboard</span></div>
|
||||
<nav>
|
||||
<a href="{{ url_for('index') }}">Providers</a>
|
||||
<a href="{{ url_for('profile_route') }}">Your Info ({{ filled }}/{{ total }})</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for cat, msg in messages %}<div class="flash {{ cat }}">{{ msg }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="hero">
|
||||
<h1>Open accounts without retyping your info</h1>
|
||||
<p class="muted">Check the providers you want, hit launch — each signup page opens with your details already filled. You finish the CAPTCHA / verification and submit.</p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{{ url_for('launch') }}">
|
||||
{% for cat in categories %}
|
||||
<h2 class="cat">{{ cat | replace('_', ' ') | title }}</h2>
|
||||
<div class="cards">
|
||||
{% for p in providers if p['category'] == cat %}
|
||||
<label class="provider">
|
||||
<input type="checkbox" name="providers" value="{{ p['id'] }}">
|
||||
<span class="pname">{{ p['name'] }}</span>
|
||||
<span class="pnote">{{ p['note'] }}</span>
|
||||
<a class="plink" href="{{ p['url'] }}" target="_blank" rel="noopener" onclick="event.stopPropagation()">open ↗</a>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="launchbar">
|
||||
<button type="submit" class="btn primary big">Launch & autofill selected</button>
|
||||
<span class="muted">opens each in a new browser tab with your info filled</span>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Fills <strong>your own</strong> info into forms <strong>you</strong> submit. No identity fabrication, no bulk signups, no KYC evasion.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
36
templates/new.html
Normal file
36
templates/new.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>New Application</h1>
|
||||
<p class="muted">Pick the account type. Castor loads the real KYC requirements that institutions ask for.</p>
|
||||
|
||||
<form method="post" class="form">
|
||||
<label>Account type
|
||||
<select name="account_type" id="account_type">
|
||||
{% for key, info in reqs.items() %}
|
||||
<option value="{{ key }}">{{ info['label'] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div id="preview" class="preview"></div>
|
||||
|
||||
<label>Institution
|
||||
<input type="text" name="institution" placeholder="e.g. Chase, Vanguard, Coinbase, PayPal" required>
|
||||
</label>
|
||||
|
||||
<button type="submit" class="btn primary">Start application</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const reqs = {{ reqs | tojson }};
|
||||
const sel = document.getElementById('account_type');
|
||||
const preview = document.getElementById('preview');
|
||||
function render() {
|
||||
const info = reqs[sel.value];
|
||||
preview.innerHTML = '<strong>Requirements:</strong><ul>' +
|
||||
info.requirements.map(r => '<li>' + r + '</li>').join('') + '</ul>';
|
||||
}
|
||||
sel.addEventListener('change', render);
|
||||
render();
|
||||
</script>
|
||||
{% endblock %}
|
||||
42
templates/profile.html
Normal file
42
templates/profile.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title>Castor — Your Info</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="brand"><span class="logo">✦</span><span>Castor</span><span class="tag">signup dashboard</span></div>
|
||||
<nav>
|
||||
<a href="{{ url_for('index') }}">Providers</a>
|
||||
<a href="{{ url_for('profile_route') }}">Your Info</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for cat, msg in messages %}<div class="flash {{ cat }}">{{ msg }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<h1>Your Info</h1>
|
||||
<p class="muted">Stored locally, used only to auto-fill <strong>your own</strong> signup forms.</p>
|
||||
<form method="post" class="form">
|
||||
{% for key, label in fields %}
|
||||
<label>{{ label }}
|
||||
<input type="text" name="{{ key }}" value="{{ profile.get(key, '') }}" autocomplete="off">
|
||||
</label>
|
||||
{% endfor %}
|
||||
<button type="submit" class="btn primary">Save</button>
|
||||
</form>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Fills <strong>your own</strong> info into forms <strong>you</strong> submit. No identity fabrication, no bulk signups, no KYC evasion.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
37
templates/vault.html
Normal file
37
templates/vault.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Vault</h1>
|
||||
<p class="muted">Your identity documents, encrypted at rest with a key generated on this machine.</p>
|
||||
|
||||
<form method="post" action="{{ url_for('vault_upload') }}" enctype="multipart/form-data" class="form">
|
||||
<label>Upload document (20 MB max)
|
||||
<input type="file" name="file" required>
|
||||
</label>
|
||||
<button type="submit" class="btn primary">Encrypt & store</button>
|
||||
</form>
|
||||
|
||||
{% if docs %}
|
||||
<table class="table">
|
||||
<thead><tr><th>File</th><th>Type</th><th>SHA-256</th><th>Uploaded</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{% for d in docs %}
|
||||
<tr>
|
||||
<td>{{ d['filename'] }}</td>
|
||||
<td>{{ d['mime'] }}</td>
|
||||
<td class="mono">{{ d['sha256'][:16] }}…</td>
|
||||
<td>{{ d['uploaded_at'] }}</td>
|
||||
<td class="row-actions">
|
||||
<a class="btn small" href="{{ url_for('vault_download', doc_id=d['id']) }}">Download</a>
|
||||
<form method="post" action="{{ url_for('vault_delete', doc_id=d['id']) }}" class="inline"
|
||||
onsubmit="return confirm('Delete this document?');">
|
||||
<button type="submit" class="btn small danger">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="muted">No documents stored yet.</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user