Skip to content

Latest commit

 

History

History
311 lines (213 loc) · 12.6 KB

File metadata and controls

311 lines (213 loc) · 12.6 KB

Setup Guide — Techy

Prerequisites

  • Node.js 20+
  • A GitHub account (for OAuth)
  • A Neon account (free tier: https://neon.tech)

1. Clone and Install

git clone <repo-url>
cd Techy
npm install

The repo includes:

  • Tailwind CSS v4 via @tailwindcss/vite
  • Melt UI for headless Svelte 5 UI primitives
  • GSAP for optional motion and animation work

No extra Tailwind init command is required. The Tailwind entrypoint lives at src/app.css.


2. GitHub OAuth App

Create an OAuth App at https://github.com/settings/developers → "OAuth Apps" → "New OAuth App"

Field Value
Application name Techy (or anything)
Homepage URL http://localhost:5173 (dev) or your prod URL
Authorization callback URL http://localhost:5173/auth/callback/github

Copy the Client ID and generate a Client Secret.

For production, create a second OAuth App with the production domain, or update the callback URL.


3. Neon Database

  1. Sign in at https://console.neon.tech
  2. Create a new project (PostgreSQL 16)
  3. From the dashboard, copy the pooled connection string (not the direct one)

4. Environment Variables

cp .env.example .env

Edit .env:

# Generate with: openssl rand -hex 32
AUTH_SECRET=<your-secret>

GITHUB_CLIENT_ID=<from-step-2>
GITHUB_CLIENT_SECRET=<from-step-2>

# Your GitHub username — only this account can log in
ALLOWED_GITHUB_USERNAME=<your-github-username>

# Optional debug bypass for local and agent-driven Playwright testing
# Set this to true only when you want the bypass available
DEBUG_AUTH_BYPASS_ENABLED=true

# Use the same strong secret locally and in Vercel if you want the agent to access both
DEBUG_AUTH_BYPASS_SECRET=<long-random-secret>

# Optional display name shown in the app when using the bypass
DEBUG_AUTH_BYPASS_NAME=Agent

# Neon pooled connection string from step 3
DATABASE_URL=postgresql://...?sslmode=require

# Required for assistant/provider work once the assistant-first phase lands
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
OPENROUTER_API_KEY=

# Optional kill switch for unofficial LeetCode daily-practice fetching.
# Manual JSON practice import should still work when this is false.
LEETCODE_DAILY_FETCH_ENABLED=false

# Optional speech-to-text fallback provider for voice input
# Leave unset to use browser speech recognition only
SPEECH_TRANSCRIPTION_PROVIDER=
SPEECH_TRANSCRIPTION_API_KEY=

5. Database Migrations

# Generate migration SQL from schema
npm run db:generate

# Apply migrations to Neon
npm run db:migrate

Migrations are output to drizzle/. Commit them.


6. Run Development Server

npm run dev

Visit http://localhost:5173. You'll be redirected to the standalone /signin page. After sign-in, you'll enter the protected app shell.


7. Type Check

npm run check

8. Run Unit Tests

npm run test

Use npm run test:watch while iterating locally.


9. Normalize Legacy Note Categories

Use the repo-local backfill script only when you intentionally want to clean up older note rows that were saved before the canonical category taxonomy landed:

npm run normalize:note-categories -- --apply

The command is a dry run unless --apply is provided. It rewrites only safe legacy category labels, keeps tags and bodies unchanged, and prints ambiguous or unknown categories for manual review.


Frontend Styling Notes

  • Tailwind is configured through the Vite plugin in vite.config.ts
  • Global Tailwind import and shared theme tokens live in src/app.css
  • Root layout imports src/app.css from src/routes/+layout.svelte
  • Melt UI is available for new interactive UI work; it does not provide Techy's final visual styling on its own
  • GSAP is installed and currently wired into restrained chat and nav motion; keep any new usage scoped to meaningful state transitions

PWA Setup Notes

The app is wired as an installable online-first PWA via @vite-pwa/sveltekit. The PWA layer is active in production builds (npm run build) and not active in dev.

What is included:

  • @vite-pwa/sveltekit configured in vite.config.ts — generates the service worker and manifest at build time
  • @vite-pwa/assets-generator used to generate icons from static/pwa-icon-source.svg
  • Generated icon assets in static/: pwa-64x64.png, pwa-192x192.png, pwa-512x512.png, maskable-icon-512x512.png, apple-touch-icon-180x180.png, favicon.ico
  • manifest.webmanifest output with name "Techy", display: standalone, start_url: /, theme_color: #09090b, background_color: #09090b

Service-worker scope:

  • Static app-shell and build assets (client/**) are precached
  • Authenticated routes (/api/, /auth/, /debug/, /signin) are excluded from navigation fallback
  • No runtime caching — all authenticated data requests (notes, chat, AI) go to the network
  • The auth flow and session boundary are unchanged after install

Icons can be regenerated at any time from the source SVG:

npx @vite-pwa/assets-generator --preset minimal-2023 static/pwa-icon-source.svg

Deployment (Vercel)

  1. Push the repo to GitHub

  2. Go to vercel.comAdd New Project → import the repo

  3. In Project Settings → Environment Variables, add every variable from .env:

    Variable Notes
    AUTH_SECRET Generate with openssl rand -hex 32
    GITHUB_CLIENT_ID From your production GitHub OAuth App
    GITHUB_CLIENT_SECRET From your production GitHub OAuth App
    ALLOWED_GITHUB_USERNAME Your GitHub login (case-sensitive)
    DEBUG_AUTH_BYPASS_ENABLED Optional. Set to true only when you want the debug bypass available
    DEBUG_AUTH_BYPASS_SECRET Optional. Strong shared secret for local and deployed debug login
    DEBUG_AUTH_BYPASS_NAME Optional. Display name for the debug session, e.g. Agent
    DATABASE_URL Neon pooled connection string (see below)
    ANTHROPIC_API_KEY Required for Anthropic models on /chat
    OPENAI_API_KEY Required for OpenAI models on /chat
    OPENROUTER_API_KEY Required for OpenRouter models on /chat and /practice tutoring
    LEETCODE_DAILY_FETCH_ENABLED Optional. Enables unofficial /practice daily fetch when set to true; keep manual JSON import available either way
    SPEECH_TRANSCRIPTION_PROVIDER Optional. Enables server speech-to-text fallback when implemented
    SPEECH_TRANSCRIPTION_API_KEY Optional. Provider key for server speech-to-text fallback
    AUTH_TRUST_HOST Set to true — required on Vercel so Auth.js trusts the host header
  4. Create a second GitHub OAuth App (or update the existing one) with:

    • Callback URL: https://<your-vercel-domain>/auth/callback/github
  5. Click Deployadapter-auto detects Vercel automatically

Important: Use the Neon pooled connection string for DATABASE_URL in production. The direct connection string does not work reliably in serverless environments.

Build note: The build requires DATABASE_URL to be set in the Vercel environment variables — the DB client is initialised at module load time. Vercel injects env vars into the build, so this works automatically once the variable is configured.

Env-loading note: App server modules use SvelteKit's private env access, while standalone tooling such as drizzle.config.ts still reads from plain Node environment variables. Keep running Drizzle commands from the repo root so .env is loaded as expected.

Practice Integration Notes

The /practice direction includes an unofficial LeetCode daily challenge fetch path plus a manual JSON import fallback. Treat the automated fetch as fragile: it may break if LeetCode changes its internal API or content shape, and it should remain disabled unless intentionally enabled for personal use.

Practice tutoring uses OpenRouter and requires OPENROUTER_API_KEY. Tutor turns are transient and are not persisted in chat history or a practice transcript table.

Debug Bypass

For agent-driven Playwright testing, Techy can mint a signed debug session without going through GitHub OAuth.

  1. Set DEBUG_AUTH_BYPASS_ENABLED=true
  2. Set a long random DEBUG_AUTH_BYPASS_SECRET
  3. Use the same secret in your local .env and Vercel if you want the agent to work against both environments
  4. Hit /debug/auth/login with the secret and an optional redirectTo

Example:

curl -i "http://localhost:5173/debug/auth/login?secret=<DEBUG_AUTH_BYPASS_SECRET>&redirectTo=/notes"

This bypass is app-level, not GitHub-level. It does not use your personal GitHub password, OAuth token, or browser session.


Database Studio (optional)

npm run db:studio

Opens Drizzle Studio at http://local.drizzle.studio — a GUI for browsing and editing the database.

Neon Compute Usage Troubleshooting

If Neon reports unexpectedly high monthly compute usage while Techy is idle, first confirm whether the compute is repeatedly waking rather than assuming data storage is growing. The Techy database is small enough that this warning is usually about compute time, not table size.

Useful checks:

neonctl projects list --output json
neonctl branches list --project-id <project-id> --output json
neonctl operations list --project-id <project-id> --output json
vercel logs --project techy --environment production --no-branch --since <iso-start> --until <iso-end> --json

In June 2026, the techy Neon endpoint was found with suspend_timeout_seconds: 0, and Neon rejected changing it to 300 on the active account with modifying the suspend interval is not permitted on this account. Manual suspend worked, but the endpoint restarted again without matching local processes, TCP database connections, Vercel cron jobs, or Vercel request logs at the restart timestamp.

The fix was to rotate the neondb_owner role password, then suspend the endpoint and wait without polling Neon. After rotation, the endpoint stayed idle, confirming that an old or unknown DATABASE_URL client had been waking the compute. Vercel production DATABASE_URL and local .env were then updated to the new Neon URL, followed by a production redeploy so the deployed app used the new secret.

Safe recovery sequence:

  1. Close Neon console tabs and stop local dev servers.
  2. Suspend the endpoint, wait 3-5 minutes without polling, then check operations once.
  3. If a new start_compute appears without matching Vercel logs, reset the Neon role password.
  4. Suspend again and repeat the no-poll wait.
  5. If the endpoint stays idle, update DATABASE_URL only in the intended consumers: local .env, Vercel production env, and any other known deploy targets.
  6. Redeploy Vercel after updating production env vars.
  7. Remove any temporary files that held the rotated connection string.

Do not print or commit the new database URL. Prefer passing it through stdin or a 0600 temp file when updating deployment env vars.


Common Issues

Issue Fix
DATABASE_URL environment variable is not set .env file missing or not loaded
AccessDenied on GitHub sign-in ALLOWED_GITHUB_USERNAME doesn't match your GitHub login (case-sensitive)
Debug bypass returns 404 DEBUG_AUTH_BYPASS_ENABLED is not set to true
Debug bypass returns 403 DEBUG_AUTH_BYPASS_SECRET is missing or does not match
AUTH_SECRET errors Run openssl rand -hex 32 and set the output as AUTH_SECRET
CSRF / bad request errors on Vercel sign-in AUTH_TRUST_HOST env var not set to true in Vercel settings
D3 graph blank in production Check browser console — likely a CSP issue with inline SVG
Wikilinks show as broken (red) The linked note's title must match exactly — check capitalisation. See docs/NOTES.md.
Neon compute usage spikes while app is idle Check for repeated start_compute operations and compare with Vercel logs. If manual suspend does not hold, rotate the Neon role password and update only known DATABASE_URL consumers.

Further Reading