Arkive

Phase 2 lesson 2 walkthrough: resolveApiCaller

As of
Version1.0.0
Kindguidance
Length2,135 words, about 9 min
Tagsbuildwalkthroughphase-2api-guardauthenticationsupabasetesting

This guide reproduces lesson 2 of Phase 2 step by step: task 2.1, which gives API routes a way to know who is calling. It assumes lesson 1 is merged (lesson 1 walkthrough) and that packages/core/src/api/ doesn't exist yet.

The result shipped as sidekick#13. The design is recorded in contracts (version 2.3.0).

Every step explains what you are doing and why. Follow the reasoning, not just the commands.


Step 1 — Orient and Branch

What and why: Page requests pass through apps/web/src/proxy.ts, which redirects signed-out users to /login. An API caller (a fetch, the CLI) wants a 401 it can handle, not a redirect to an HTML page, so the proxy lets /api through untouched. Every API route has to establish the caller itself. resolveApiCaller does that, and lesson 4's withApiGuard will call it on every request.

  1. Branch from an up-to-date main:
Shell
git switch main
git pull origin main
git switch -c feature/P2L2-resolve-api-caller
  1. Find the skip in apps/web/src/proxy.ts:
TypeScript
// Do not authenticate API routes here
if (isApiRoute(request)) {
  return supabaseResponse;
}

supabase.auth.getUser() runs before this line even for API requests. That isn't wasted work. A Supabase session is a short-lived access token (a JWT, about an hour) plus a single-use refresh token. When the access token has expired, getUser() refreshes the pair, and the proxy client's setAll (packages/core/src/supabase/proxy.ts) writes the new cookies to the request, for the route handler, and to the response, for the browser. So the session is refreshed once, in one place, before any route runs.

The guard still checks the caller itself. It must not depend on the proxy: a change to the matcher could stop the proxy running, and only the guard is guaranteed to run on every API route.


Step 2 — Design the Return Type

What and why: Decide what the function returns before writing any logic. Work backwards from what the guard does with the answer: return 401 when nobody is calling, check scopes for API-key callers, then run every query as the user through withRLS(userId, …).

Two kinds of caller will exist:

  • A session, from the browser's cookie. It is the user, so it carries only userId.
  • An API key, from Phase 9 onwards (Authorization: Bearer …). It carries userId, the keyId (to update last_used_at or log which key was used) and its scopes.

Scopes aren't entitlements. Entitlements (lesson 3) are the features a user has. Scopes narrow what one key may do on that user's behalf, like a GitHub token limited to repo:read. A session has nothing to narrow, so it has no scopes field. An invented [] would block every logged-in user, and ['*'] would be a magic string.

A union tagged by a kind field (a discriminated union) lets the guard tell the two apart: checking kind narrows the type, so scopes only exists inside the key branch.

  1. Create packages/core/src/api/auth.ts with the types:
TypeScript
export interface SessionBasedApiCaller {
  kind: 'session';
  userId: string;
}

export interface KeyBasedApiCaller {
  kind: 'key';
  userId: string;
  keyId: string;
  scopes: readonly string[];
}

export type ApiCaller = SessionBasedApiCaller | KeyBasedApiCaller;

Named interfaces follow the repo's lint rule (object shapes are interfaces). They also let a function take KeyBasedApiCaller alone, so "session callers skip the scope check" is enforced by the compiler. ApiCaller is the one type, because it's a union.

"Nobody is calling" is null, and it goes on the function's return type, not inside ApiCaller. Route handlers receive the caller after the guard has already sent the 401, so inside the type it would force a pointless null check everywhere. On the return type, TypeScript won't let the guard read caller.userId until it has checked for null.

  1. Check it compiles:
Shell
pnpm --filter @sidekick/core typecheck

Step 3 — The Session Path

What and why: Recognise a signed-in browser. The function takes the web-standard Request, not Next's NextRequest: a NextRequest is a Request, so route handlers can pass it, packages/core doesn't need Next for the type, and tests can build one with new Request(…).

Use getUser(), not getSession(). getSession() reads the session from the cookie and never contacts Supabase, and the user can edit a cookie. getUser() sends the token to Supabase Auth, which verifies it.

Any Auth error resolves to null: when in doubt, there's no caller, and the guard turns that into a 401. If Supabase Auth itself is down, getUser() also returns an error, so callers get a 401 rather than a 500. That's acceptable, because it still fails closed.

Missing Supabase env vars make createServerClient() throw. Don't catch it. "Not signed in" is an answer, a misconfigured app is a bug, and only a bug should crash (Error handling).

  1. Add the function below the types:
TypeScript
import { createServerClient } from '../supabase/server';

export async function resolveApiCaller(request: Request): Promise<ApiCaller | null> {
  const client = await createServerClient();
  const {
    data: { user },
    error,
  } = await client.auth.getUser();

  return user && !error
    ? {
        kind: 'session',
        userId: user.id,
      }
    : null;
}

Checking user alone would already be enough. getUser()'s own return type is a discriminated union keyed on error (RequestResultSafeDestructure in @supabase/auth-js): user is null exactly when error is set.

pnpm --filter @sidekick/core lint reports request as unused until step 4. Leave it.


Step 4 — The Bearer Rule

What and why: A request can send Authorization: Bearer <token>. In Phase 9 that token will be an API key, looked up in an api_keys table that doesn't exist yet (task 9.4). There's nothing to check it against today.

Three decisions:

  • Any Authorization header gets null. Accepting an unchecked token would let anyone in. That's failing closed.
  • The header beats a valid cookie. The browser attaches the cookie to every request automatically, but code adds a Bearer header deliberately. Picture an extension holding a notes:read key while you're signed in. If the cookie won, the extension's delete request would run with your full session (privilege escalation), and a revoked key would keep working unnoticed.
  • The check runs before getUser(). That's the only way the header can win, because the cookie is never read, and it skips a network call for a request that will be refused anyway.

The check only tests whether the header is there, and it can only take access away, never grant it, so its content needs no validation yet. Phase 9 will validate the content once it grants access. An empty Authorization: header carries no credential and falls through to the session.

  1. Add the check at the top of resolveApiCaller:
TypeScript
const authHeader = request.headers.get('authorization');

// Resolving auth header first so a limited API key can't borrow the user's session cookie,
// which the browser attaches automatically
if (authHeader) {
  // deny all api key/token based access until auth key table is built out in phase 9 / task 9.4
  return null;
}

headers.get() matches names case-insensitively and returns string | null.


Step 5 — server-only

What and why: Mark the file as server code, so it fails the build if a Client Component ever imports it.

  1. Make this the first line of auth.ts, as in admin.ts and db/unsafe.ts:
TypeScript
import 'server-only';

It doesn't stop a secret leaking today. server.ts reads only NEXT_PUBLIC_ variables, which are public by design, and Next never inlines other variables into a client bundle. What it gives:

  • a clear build error instead of a confusing one, because cookies() from next/headers can't run in a browser;
  • protection in advance for task 9.4, which will look up keys in the database here;
  • a signal to readers, since packages/core is imported from both sides.

packages/core/vitest.config.ts aliases server-only to a stub, because the real package throws outside Next's react-server condition.


Step 6 — Test It

What and why: Run resolveApiCaller without Next or Supabase. There's no request scope in a test, so cookies() would throw, and the tests shouldn't make network calls. vi.mock replaces ../supabase/server for every file in the test run, the test file included.

How vi.mock behaves here:

  • It is hoisted above the imports, so auth.ts gets the fake before it loads. A factory therefore can't read top-level consts directly, because they don't exist yet (vi.hoisted() exists for that).
  • The factory makes createServerClient an empty vi.fn(). Each test sets its value with vi.mocked(createServerClient).mockResolvedValue(…).
  • Vitest 5 clears mock call counts between tests by default, but a value set with mockResolvedValue carries over into the next test, so beforeEach(() => vi.resetAllMocks()) is still needed. Import beforeEach from 'vitest'. An editor's auto-import can pick 'node:test', whose hook never runs under Vitest.
  1. Create packages/core/src/api/auth.test.ts. The fakes use the real response shapes, typed as UserResponse. Only the user is cast, because the code reads nothing but id. With no session, getUser() returns AuthSessionMissingError, not error: null. Requests are real Request objects: a fake headers.get() that ignores the header name couldn't catch code reading the wrong header.
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';

import {
  AuthError,
  AuthSessionMissingError,
  type SupabaseClient,
  type User,
  type UserResponse,
} from '@supabase/supabase-js';

import { createServerClient } from '../supabase/server';
import { resolveApiCaller } from './auth';

const MOCK_AUTH_TOKEN = 'bearer mocked-auth-token';
const MOCK_USER = { id: 'mock-user-id' } as User;
const MOCK_AUTH_USER_RESPONSE: {
  validUser: UserResponse;
  invalidUser: UserResponse;
  error: UserResponse;
} = {
  validUser: { data: { user: MOCK_USER }, error: null },
  invalidUser: { data: { user: null }, error: new AuthSessionMissingError() },
  error: { data: { user: null }, error: new AuthError('boom') },
};

function getSupabaseServerClient(state: 'validUser' | 'invalidUser' | 'error') {
  return {
    auth: {
      getUser: async () => MOCK_AUTH_USER_RESPONSE[state],
    },
  } as unknown as SupabaseClient;
}

function getHttpRequestObject(includeHeaders = false, mockAuthToken = MOCK_AUTH_TOKEN) {
  return new Request('http://localhost/auth', {
    headers: includeHeaders ? { Authorization: mockAuthToken } : undefined,
  });
}

vi.mock('../supabase/server', () => ({
  createServerClient: vi.fn(),
}));
  1. Add six cases inside describe('resolveApiCaller', …), after the beforeEach. Each one asserts the whole result (toEqual, toBeNull) and, where it matters, whether the session was read:
TestRequestFake clientExpect
resolves a signed-in user to a session callerno headervalidUsersession caller; client called once
resolves to null when nobody is signed inno headerinvalidUsernull
resolves to null when Supabase Auth returns an errorno headererrornull
resolves a Bearer header to null without reading the sessionBearernonenull; client never called
lets a Bearer header win over a valid sessionBearervalidUsernull; client never called
falls through to the session when the Authorization header is emptyAuthorization: ''validUsersession caller; client called once

For example:

TypeScript
it('lets a Bearer header win over a valid session', async () => {
  vi.mocked(createServerClient).mockResolvedValue(getSupabaseServerClient('validUser'));
  const resolution = await resolveApiCaller(getHttpRequestObject(true));
  expect(resolution).toBeNull();
  expect(createServerClient).not.toHaveBeenCalled();
});

Keep the token parameter a plain string. new Request turns { Authorization: undefined } into the literal header "undefined", which silently takes the Bearer path.

  1. Run both commands. Vitest strips types without checking them, so a type-broken test still goes green, and only typecheck catches it.
Shell
pnpm --filter @sidekick/core test
pnpm --filter @sidekick/core typecheck

The output must say Tests 6 passed (6).

  1. Break it on purpose. Comment out the return null; in the Bearer branch and run the tests. Two fail, in two different ways:
  • lets a Bearer header win over a valid session fails its assertion, because a session caller came back instead of null.
  • resolves a Bearer header to null without reading the session fails with a TypeError. That test set no client, so after resetAllMocks the mock returns undefined, and the code reads .auth from it.

An assertion failure says what's wrong, while a TypeError only says that something broke. That's why each Bearer test checks both the result and the call count. Put the return null; back.

  1. Core has tests now, so drop --passWithNoTests from its test script in packages/core/package.json. As in lesson 1, a package with tests should fail if Vitest finds none:
JSON
"test": "vitest run src",

Step 7 — Verify Like CI and Ship

What and why: CI starts with no Turbo cache, and the PR title becomes the squash commit on main.

  1. Clear the old build and run everything uncached:
Shell
rm -rf packages/core/dist
pnpm prettier:check
pnpm turbo lint typecheck build test --force
ls packages/core/dist/api

Every task should succeed with 0 cached. dist/api holds auth.js and no auth.test.js.

  1. Commit by path, push, and open the PR with a Conventional Commits title:
Shell
git add packages/core/src/api packages/core/package.json
git commit -m "feat(core): add resolveApiCaller for session callers; bearer fails closed"
git push -u origin feature/P2L2-resolve-api-caller
gh pr create --fill

gh needs gh auth login once per machine. Wait for the checks job, then squash-merge.


What you have now

  • resolveApiCaller(req) in packages/core/src/api/auth.ts, internal to core until the guard (lesson 4) uses it.
  • A session caller for a signed-in browser. null for nobody, for any Auth error and for any Authorization header. Loud failures for a misconfigured app.
  • Six unit tests, including proof that a Bearer header never reads the session.

Next: lesson 3, entitlements.

Arkive

Index

Notes, decisions, and progress on my journey as I build Project Sidekick — built in the open; written as it happens.

Tags (144)

View

224 entries.

As ofTitleKind
2026-10-20Phase 2 lesson 2 walkthrough: resolveApiCallerReadingbuild walkthrough phase-2 api-guard authentication supabase testingguidance
2026-10-20Lesson 2 (task 2.1): resolveApiCallerplan phase-2 task api-guard authentication supabase nextjsplan
2026-10-20Phase 2 build rules and target designplan phase-2 api-guard rls api authentication typescript guidanceplan
2026-10-20Agent guideai-coding agent gateway agent-guidance rls supabase drizzle api react prettierguidance
2026-10-20Phase 2 core infrastructure API guard feature systemplan living-plan phase-2 api-guard rls api authentication feature-systemplan
2026-10-18Lesson 1 (tasks 2.6, 2.7): FeatureManifest and ALL_FEATURESplan phase-2 task feature-system typescript monorepoplan
2026-10-18Lesson 3 (tasks 2.8, 2.9): entitlements table and getEnabledFeaturesplan phase-2 task feature-system database drizzle rls postgresql testingplan
2026-10-18Lesson 4 (tasks 2.2, 2.3): withApiGuard with withRLSplan phase-2 task api-guard rls api security testingplan
2026-10-18Lesson 5 (tasks 2.4, 2.5): request and auth-failure loggingplan phase-2 task api-guard observability eslintplan
2026-10-18Lesson 6 (tasks 2.11, 2.12): /api/health and guard verificationplan phase-2 task api-guard api nextjs testingplan
2026-10-18Lesson 7 (task 2.10): dev entitlement seed scriptplan phase-2 task feature-system database postgresqlplan
2026-10-18Phase 2 lesson 1 walkthrough: feature registrybuild walkthrough phase-2 feature-system typescript monorepo testingguidance
2026-10-18Backlogged unplannedplan living-plan backlog feature-system taxila zinsser alter-ego parrot rls supabaseplan
2026-10-18Dependency flowsystem-design monorepo clispec
2026-10-18Registrysystem-design feature-systemspec
2026-10-17Pre-2 walkthroughbuild walkthrough pre-2 rls supabase drizzle postgresql testing eslintguidance
2026-10-16Best practice rulessystem-design code-quality-check eslintspec
2026-10-16ESLint best practice rulesdecision technical architecture-decision eslint typescript nextjsdecision
2026-10-16Stay on ESLint revisit oxlintdecision technical architecture-decision eslint typescriptdecision
2026-10-16Pre 2 foundation hardening completeplan pre-2 foundation security database testingplan
2026-10-16ESLint plugin boundariessystem-design code-quality-check eslintspec
2026-10-16Living implementation planplan living-plan taxila zinsser alter-ego war-room factory parrot core-driveplan
2026-10-16Portable documentation vaultopportunity documentation agentic-coding portability severity-mediumopportunity
2026-10-16Prettier at repo levelsystem-design code-quality-check prettierspec
2026-10-16Server actionssystem-design nextjs rls api authenticationspec
2026-10-16With API guardsystem-design security api-guard rls api authentication typescriptspec
2026-10-15Pooler client configurationopportunity phase-2 database supabase drizzle severity-mediumopportunity
2026-10-14Vitestdecision technical architecture-decision testing vitest monorepodecision
2026-10-14App runtime role for Drizzledecision technical architecture-decision rls supabase drizzledecision
2026-10-14Profile creation Postgres triggersystem-design security postgresql api authenticationspec
2026-10-14Profiles schemasystem-design security rls authenticationspec
2026-10-14Tag taxonomyai-coding agent-guidance taxonomy discoveryguidance
2026-10-13Anatomy of a Core Drive Entrysystem-design prd feature core-driveprd
2026-10-13Model Routingprd vercel ai embedding routingprd
2026-10-13Phase 0 — Foundation and Toolingplan phase-0 api nextjs typescript eslint turborepo pnpmplan
2026-10-13Private Informationsystem-design prd feature core-drive taxila graphprd
2026-10-13Reflections and Learningssystem-design prd feature core-driveprd
2026-10-13Source Attributionprd feature alter-ego aiprd
2026-10-13Values Onlysystem-design prd feature core-drive war-room factoryprd
2026-10-13What is Core Drive?system-design prd feature core-drive factory ai alter-egoprd
2026-10-12Command Paletteprd ux specificationprd
2026-10-12MVP Design Objectiveprd ux specificationprd
2026-10-12Be the Best Version of Yourselfprd value-proposition specificationprd
2026-10-12Make the Right Behavior Easierprd value-proposition specificationprd
2026-10-11Solve Problems and Build Thingsmotivation creativityjournal
2026-10-11A Personal Discoverymotivation discipline bucket-list ambition entrepreneurship sidekickjournal
2026-10-11Commercialize Sidekickmotivation finance freedomjournal
2026-10-10Realityprinciple reality pragmatism survivalguidance
2026-10-10Seek Closureprinciple productivity happiness purposeguidance
2026-10-08No Do-oversprinciple core-drive execution productivityguidance
2026-10-08Pragmatismprinciple practical pragmaticguidance
2026-10-04Protect Your Mind and Your Timeprinciple productivity automation minimalismguidance
2026-10-03Focus Funnelprinciple core-drive productivityguidance
2026-10-02Fuel Career Growthmotivation career ambitionjournal
2026-10-02Learnmotivation learning ai ragjournal
2026-10-02Coding Agent HeuristicsRetiredWhich AI model or coding agent to use for which kind of session based on the type of task, teaching value, and complexitysidekick project technical ai heuristicnote
2026-09-19A graph pattern not a graph databasesystem-design global-tagging-and-linking postgresql graphspec
2026-09-19Actual stateglossary terminologyglossary
2026-09-19Algorithm of lifeglossary terminology nextjsglossary
2026-09-19Alter egosystem-design prd feature taxila alter-ego factory aiprd
2026-09-19API firstsystem-design api clispec
2026-09-19API route fail openopportunity phase-2 api security eslint severity-lowopportunity
2026-09-19API versioningsystem-design apispec
2026-09-19App runtime for Drizzlesystem-design database drizzle postgresqlspec
2026-09-19Approve buildssystem-design monorepo nextjs pnpmspec
2026-09-19Architectural driverssystem-design offlinespec
2026-09-19Architecture invariantsai-coding architecture invariant agent-guidance api nextjsguidance
2026-09-19Asynchronoussystem-design rag embeddingspec
2026-09-19Atomicsystem-design rag embeddingspec
2026-09-19Authenticationsystem-design security taxila api authentication pwa mobile clispec
2026-09-19Background jobssystem-design vercel background-jobspec
2026-09-19Best practicesai-coding-harness agent-guidance drizzle api react pnpm css offline embedding soft-deleteguidance
2026-09-19Build for today designed for futuresystem-design offlinespec
2026-09-19Bundle everythingsystem-design monorepospec
2026-09-19Capacitorsystem-design native-app nextjs mobile offlinespec
2026-09-19Centralizedsystem-design feature-systemspec
2026-09-19Centralizedsystem-design observability api authenticationspec
2026-09-19Centralized and client agnosticsystem-design security rls api authentication clispec
2026-09-19Centralized copydecision technical architecture-decision authentication typescript clidecision
2026-09-19Centralized copysystem-design contentspec
2026-09-19Checkpoint aplan phase-0 checkpoint nextjs typescript turborepo pnpm cliplan
2026-09-19Checkpoint bplan phase-0 checkpoint eslint prettier turborepo pnpmplan
2026-09-19Checkpoint cplan phase-0 checkpoint nextjs pnpmplan
2026-09-19Checkpoint dplan phase-0 checkpoint api-guard rls supabase drizzle api authenticationplan
2026-09-19CLIsystem-design cli apispec
2026-09-19Commands and environmentai-coding command environment agent-guidance prettier pnpm cliguidance
2026-09-19Context assemblersystem-design ai war-room factory api-guardspec
2026-09-19Coresystem-design feature-systemspec
2026-09-19Core drive vs Taxilasystem-design prd feature taxila core-driveprd
2026-09-19Corepacksystem-design monorepo pnpmspec
2026-09-19CSS modulessystem-design css eslint mantinespec
2026-09-19Database and securityai-coding database security agent-guidance api-guard rls drizzle api react repository-patternguidance
2026-09-19DB access chokepointopportunity phase-2 database rls architecture severity-highopportunity
2026-09-19Design constraintssystem-design global-tagging-and-linking rls offline soft-deletespec
2026-09-19dotenv CLIdecision technical architecture-decision clidecision
2026-09-19dotenv CLIsystem-design config clispec
2026-09-19Driving forces and key featuressystem-design api offlinespec
2026-09-19Edge runtimedecision technical architecture-decision supabase api nextjsdecision
2026-09-19Edge runtimesystem-design security supabasespec
2026-09-19Embedding status fieldsystem-design rag embedding typescriptspec
2026-09-19Enforced conventionssystem-designspec
2026-09-19Env vars in turbo JSONdecision technical architecture-decision turborepo verceldecision
2026-09-19Env vars in turbo JSONsystem-design monorepo turborepo vercelspec
2026-09-19Environment contract driftopportunity phase-2 config security developer-experience severity-mediumopportunity
2026-09-19Error handlingsystem-design observability api-guard rls supabase api nextjs react aispec
2026-09-19ESLint rules to use tsupdecision technical architecture-decision nextjs eslintdecision
2026-09-19Essential and ideal stateglossary terminologyglossary
2026-09-19Evolvabilitysystem-design rls offlinespec
2026-09-19Factorysystem-design prd feature factoryprd
2026-09-19Feature package workai-coding feature monorepo agent-guidance feature-systemguidance
2026-09-19Flat configdecision technical architecture-decision typescript eslintdecision
2026-09-19Flat configsystem-design code-quality-check eslintspec
2026-09-19Force dynamicdecision technical architecture-decision supabase authentication nextjsdecision
2026-09-19Force dynamicsystem-design nextjs supabasespec
2026-09-19Global tags and metadatasystem-design global-tagging-and-linking taxila zinsser alter-ego war-room factory core-drivespec
2026-09-19GraphQL and Relaysystem-design api graphql relayspec
2026-09-19GraphQL Relaydecision technical architecture-decision api-guard rls supabase drizzle api authentication nextjsdecision
2026-09-19Historic stateglossary terminologyglossary
2026-09-19Idempotent APIsystem-design api idempotencyspec
2026-09-19Independent deploymentssystem-design feature-systemspec
2026-09-19Informationglossary terminologyglossary
2026-09-19Installation at workspace levelsystem-design code-quality-check typescript pnpmspec
2026-09-19Instrumentationsystem-design observability vercel embeddingspec
2026-09-19Isolationsystem-design feature-systemspec
2026-09-19Lifecycle and traceabilityprd governance planningguidance
2026-09-19Mantinesystem-design css mantinespec
2026-09-19Many clients and many consumerssystem-design api pwa ai rag clispec
2026-09-19May become part of Taxilasystem-design core-drive taxilaspec
2026-09-19Middlewaresystem-design security api authenticationspec
2026-09-19Migrationsystem-design database drizzle pnpmspec
2026-09-19Model router contractsystem-design ai model-routing provider-agnostic embeddingspec
2026-09-19Module resolution bundlerdecision technical architecture-decision nextjs typescriptdecision
2026-09-19Module resolution bundlersystem-design code-quality-check typescriptspec
2026-09-19Never mutate outside API layersystem-design apispec
2026-09-19No API versioningdecision technical architecture-decision api-guard api nextjs clidecision
2026-09-19No utility stylesdecision technical architecture-decision eslint mantine cssdecision
2026-09-19Non syncable tablessystem-design database offlinespec
2026-09-19Notesai-coding-harness agent-guidance nextjs eslint pnpm cssguidance
2026-09-19Observabilitysystem-design api-guard api authentication vercel observabilityspec
2026-09-19Observablesystem-design rag embedding observabilityspec
2026-09-19Offline readysystem-design api pwa offline soft-delete idempotencyspec
2026-09-19Package boundary enforcementopportunity phase-2 monorepo eslint architecture severity-mediumopportunity
2026-09-19Parrotsystem-design prd feature parrotprd
2026-09-19Phase 0 foundation tooling completeplan living-plan phase-0 nextjs typescript eslint prettier turborepo pnpmplan
2026-09-19Phase 1 Supabase and auth shellplan phase-1 rls supabase drizzle postgresql authentication nextjsguidance
2026-09-19Phase 1 Supabase auth shell completeplan living-plan phase-1 api-guard rls supabase drizzle postgresql apiplan
2026-09-19Phase 1.1 DB level RLS soft delete enforcement completeplan living-plan phase-1.1 rls supabase drizzle postgresql pnpm soft-deleteplan
2026-09-19Phase 1.1 DB RLS enforcementplan phase-1.1 rls database supabase drizzle postgresql api typescriptguidance
2026-09-19Phase 10 observability hardeningplan living-plan phase-10 api-guard rls api authentication nextjs offlineplan
2026-09-19Phase 11 dogfooding friends family access optionalplan living-plan phase-11plan
2026-09-19Phase 12 billing SaaS readiness optional pathplan living-plan phase-12 api offlineplan
2026-09-19Phase 3 graph store metadata serviceplan living-plan phase-3 api-guard rls postgresql api offline graphplan
2026-09-19Phase 4 Taxila v1 knowledge managementplan living-plan phase-4 taxila api-guard rls drizzle api authenticationplan
2026-09-19Phase 5 Zinsser v1 writing editor firstplan living-plan phase-5 taxila zinsser api mantine ai embeddingplan
2026-09-19Phase 6 core drive AI layer alter egoplan living-plan phase-6 taxila zinsser alter-ego war-room factory core-driveplan
2026-09-19Phase 7 war room factory v1plan living-plan phase-7 war-room factory core-drive rls api offlineplan
2026-09-19Phase 8 PWA iOS shellplan living-plan phase-8 taxila alter-ego nextjs vercel pwa mobileplan
2026-09-19Phase 9 API keys CLIplan living-plan phase-9 taxila api-guard rls api authentication cliplan
2026-09-19Post mvp factory extensions bots agentsplan living-plan backlog factory parrot api-guard rls supabase drizzleplan
2026-09-19Prefer JSON configsystem-design monorepospec
2026-09-19Present stateglossary terminologyglossary
2026-09-19Profile trigger and referential integrityopportunity phase-2 database authentication integrity severity-highopportunity
2026-09-19Public API onlysystem-design api rls authentication clispec
2026-09-19PWAsystem-design pwa offlinespec
2026-09-19RAGsystem-design rag ai embeddingspec
2026-09-19Repository clientsystem-design database rls supabase drizzle api repository-patternspec
2026-09-19Request flowsystem-design monorepo api offlinespec
2026-09-19Retryablesystem-design rag embeddingspec
2026-09-19Row level securitysystem-design security rls drizzle offlinespec
2026-09-19Runtime database URL driftopportunity phase-2 security rls config severity-highopportunity
2026-09-19Runtime role reproducibilityopportunity phase-2 database security severity-criticalopportunity
2026-09-19Runtime validationsdecision technical architecture-decision api-guard supabase api typescript clidecision
2026-09-19Runtime validationssystem-design typescriptspec
2026-09-19Security proof and ciopportunity phase-2 testing ci security severity-highopportunity
2026-09-19Shared tsconfigdecision technical architecture-decision nextjs clidecision
2026-09-19Shared tsconfigsystem-design code-quality-check typescriptspec
2026-09-19Signup confirmation flowopportunity authentication ux severity-lowopportunity
2026-09-19Soft delete supportsystem-design database soft-deletespec
2026-09-19Start Todayprinciple core-drive execution consistencyguidance
2026-09-19State representationsystem-design api aispec
2026-09-19Structured response attributionsystem-design ai structured-streaming source-attribution citationspec
2026-09-19Syncable tablessystem-design database offline soft-deletespec
2026-09-19System overview diagramsystem-designspec
2026-09-19Task 1.1plan phase-1 task supabase postgresql api authentication nextjsplan
2026-09-19Task 1.10plan phase-1 task rls supabase drizzle postgresql authentication typescriptplan
2026-09-19Task 1.11plan phase-1 task api-guard rls supabase api authentication nextjsplan
2026-09-19Task 1.12and1.13plan phase-1 task supabase api authentication nextjs react typescriptplan
2026-09-19Task 1.14plan phase-1 task react pnpm mantine cssplan
2026-09-19Task 1.15and1.16plan phase-1 task supabase authentication nextjs react mantineplan
2026-09-19Task 1.17plan phase-1 task supabase authenticationplan
2026-09-19Task 1.18plan phase-1 task api-guard rls supabase drizzle postgresql authenticationplan
2026-09-19Task 1.2plan phase-1 task supabase drizzle postgresql authentication nextjs pnpmplan
2026-09-19Task 1.3plan phase-1 task supabase nextjs typescriptplan
2026-09-19Task 1.4plan phase-1 task supabase authentication nextjs react typescriptplan
2026-09-19Task 1.5plan phase-1 task rls supabase authentication typescriptplan
2026-09-19Task 1.6plan phase-1 task rls supabase drizzle authentication typescript offlineplan
2026-09-19Task 1.7plan phase-1 task drizzle postgresql typescriptplan
2026-09-19Task 1.8plan phase-1 task turborepo pnpmplan
2026-09-19Task 1.9plan phase-1 task rls supabase drizzle postgresql authenticationplan
2026-09-19Taxilasystem-design prd feature taxila ragprd
2026-09-19Technology stacksystem-design supabase drizzle postgresql nextjs typescript turborepo pnpm vercelspec
2026-09-19Tiered context modelsystem-design core-drive domain situation war-room factory ai embeddingspec
2026-09-19Tiptap requirementsystem-design rag embeddingspec
2026-09-19tsupsystem-design code-quality-check eslintspec
2026-09-19Turboreposystem-design monorepo turborepo pnpmspec
2026-09-19TypeScript hoistingdecision technical architecture-decision nextjs typescript pnpmdecision
2026-09-19Use corepackdecision technical architecture-decision pnpm verceldecision
2026-09-19Use navigation hooksystem-design nextjsspec
2026-09-19User profile creation by DB triggerdecision technical architecture-decision supabase api authenticationdecision
2026-09-19Verceldecision technical architecture-decision nextjs turborepo pnpm verceldecision
2026-09-19Vercelsystem-design monorepo turborepo pnpm vercelspec
2026-09-19War roomsystem-design prd feature war-roomprd
2026-09-19Why Prettier at repo level?decision technical architecture-decision prettier turborepo graphdecision
2026-09-19Why Turborepodecision technical architecture-decision turborepo pnpmdecision
2026-09-19Zinssersystem-design prd feature zinsser aiprd
2026-08-24Architectural OverviewSidekick's architectural overview — an API-first platform tuned for solo developerssidekick project technical architecturedocument
2026-07-19Project Sidekick - A Bird’s Eye ViewAn introduction to Project Sidekick. What is it? What problem does it solve? Why am I building it?sidekick project essaydocument
2026-07-10Building in the Margins of RealityProject kick-off post and a confessional essay about my past attempts and their failures. Why start now? What do I hope to achieve?sidekick project essayjournal
2026-05-29Checkpoint A walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Checkpoint B walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Checkpoint C walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Checkpoint D walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Config files explainedbuild walkthrough phase-0 turborepo typescript eslint prettierguidance
2026-05-29Phase 1 walkthroughbuild walkthrough phase-1 supabase drizzle authenticationguidance