feat: native OAuth login page, architecture docs, docs site update

- Add GET/POST /login to hermes for first-party cookie during OAuth popup
  (fixes browser CHIPS cookie partitioning that broke claude.ai connection)
- Add role column to all findCustomer* SQL queries in src/auth.ts
- Add claude.ai tab to docs/getting-started.html with OAuth flow steps
- Add ARCHITECTURE.md with system diagrams, data flow, and key invariants
- Rewrite README.md and DEPLOY.md to reflect actual MicroK8s deployment
- Deploy updated docs site (squaremcp-docs sha256 updated)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Garfield
2026-05-14 13:48:01 -04:00
parent 61dab40585
commit 02398258a5
13 changed files with 697 additions and 298 deletions

View File

@@ -12,6 +12,7 @@ export interface JWTPayload {
sub: string; // customer id
email: string;
plan: string;
role?: string;
}
export async function hashPassword(password: string): Promise<string> {
@@ -37,11 +38,12 @@ interface CustomerRow extends RowDataPacket {
active: boolean;
api_key: string;
password_hash: string | null;
role: string;
}
export async function findCustomerByEmail(email: string): Promise<CustomerRow | null> {
const [rows] = await getPool().query<CustomerRow[]>(
'SELECT id, email, plan, active, api_key, password_hash FROM customers WHERE email = ?',
'SELECT id, email, plan, active, api_key, password_hash, role FROM customers WHERE email = ?',
[email]
);
return rows[0] ?? null;
@@ -49,7 +51,7 @@ export async function findCustomerByEmail(email: string): Promise<CustomerRow |
export async function findCustomerById(id: string): Promise<CustomerRow | null> {
const [rows] = await getPool().query<CustomerRow[]>(
'SELECT id, email, plan, active, api_key, password_hash FROM customers WHERE id = ?',
'SELECT id, email, plan, active, api_key, password_hash, role FROM customers WHERE id = ?',
[id]
);
return rows[0] ?? null;
@@ -77,7 +79,7 @@ export async function setResetToken(email: string, token: string): Promise<boole
export async function findCustomerByResetToken(token: string) {
const [rows] = await getPool().query<CustomerRow[]>(
'SELECT id, email, plan, active, api_key, password_hash FROM customers WHERE reset_token = ? AND reset_expires_at > NOW()',
'SELECT id, email, plan, active, api_key, password_hash, role FROM customers WHERE reset_token = ? AND reset_expires_at > NOW()',
[token]
);
return rows[0] ?? null;