Add link previews and icons; make PIG_INVITE_CODE actually work
Social and icons. A 1200x630 card, apple-touch-icon, and maskable PWA icons, generated from an HTML template by a script so the mark, wordmark and tagline cannot drift from the product. The apple-touch-icon referenced in index.html was a 404 until now. Icons are drawn on an opaque plate with inset because iOS rounds corners and Android may apply a circle — an edge-to-edge mark loses its ears to that crop. og:image is absolute, which is the single most common reason a card unfurls blank. PIG_INVITE_CODE was a lie. Signup validates against the invites table, so setting the variable only flipped a label in the UI — an operator would set it, hand the code to a colleague, and watch them be rejected. It is now reconciled into a real invite row at boot: setting it issues, changing it rotates and revokes the predecessor, and removing it revokes. Verified all three, plus that a restart with an unchanged code does not duplicate. Two bugs found while doing that: - `uses_remaining` was jsonb, so the SQL decrement could never have worked. Now integer. The generated migration failed because Postgres has no implicit jsonb->integer cast, so the USING clause is hand-written. - Redemption keyed off `redeemedAt`, which would have made every reusable invite single-use — a confusing way to lock a team out. Availability now comes from `usesRemaining`, and redemption records who used it most recently without consuming it. Sign-in gains a password option alongside the magic link, defaulting to password since that is the daily path. PIG stores neither; both are handled by the identity provider and PIG only ever sees the resulting token. autocomplete is set so password managers and iOS can fill. Verified: full migration chain applies to a fresh Postgres, the CSP hash for the inline theme script is unchanged by the rebuild. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import { createDatabase } from '@pig/db';
|
||||
import { createApp } from './app';
|
||||
import { loadConfig } from './lib/config';
|
||||
import { startPrimeSync } from './services/sync';
|
||||
import { reconcileInviteCode } from './services/bootstrap';
|
||||
import { CapacityService } from './services/capacity';
|
||||
|
||||
const config = loadConfig();
|
||||
@@ -29,6 +30,12 @@ if (existsSync(webDist)) {
|
||||
console.log('[pig] serving front end from', webDist);
|
||||
}
|
||||
|
||||
// Reconcile configuration into the database before accepting traffic, so a
|
||||
// freshly set invite code works on the first request rather than the second.
|
||||
await reconcileInviteCode(config, db).catch((error) =>
|
||||
console.error('[pig] could not reconcile the invite code:', error),
|
||||
);
|
||||
|
||||
const server = serve({ fetch: app.fetch, port: config.PIG_PORT }, (info) => {
|
||||
console.log(`[pig] listening on http://localhost:${info.port}`);
|
||||
console.log(`[pig] environment: ${config.NODE_ENV}`);
|
||||
|
||||
Reference in New Issue
Block a user