Arkive

Gatekeeper Lesson 3 Walkthrough: Entitlements

As of
Version1.1.1
Kindguidance
Length2,069 words, about 9 min
Tagsbuildwalkthroughphase-2feature-systemdatabasedrizzlerlspostgresqltesting

This guide reproduces lesson 3 of Phase 2 step by step: tasks 2.8 and 2.9, which record which features each user has and let the guard read them. It assumes lesson 2 is merged (lesson 2 walkthrough) and that the latest migration is 0005.

The result shipped as sidekick#15. The design is recorded in contracts (version 2.4.0).

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


Step 1 — Design the Table

What and why: An entitlement says "user X has feature Y". A present row means enabled; disabling deletes the row. Design the columns from three questions: what identifies an entitlement, can a user have the same feature twice, and what happens when the user is deleted?

  1. Branch from an up-to-date main:
Shell
git switch main
git pull origin main
git switch -c feature/P2L3-entitlements
  1. Settle the columns:
ColumnTypeWhy
user_iduuidReferences profiles.id, which is the auth user's id. Named user_id because the value is userId everywhere else.
feature_keytextA FeatureManifest.key. Not a Postgres enum: an enum needs a migration for every new feature, and features live in code.
created_attimestamptzAnswers "when did this user get this feature?" during support. Not an audit log.
  • No duplicates: a composite primary key on (user_id, feature_key). It forbids the same feature twice and gives the index getEnabledFeatures uses, because its leading column is user_id. A surrogate id would only pay off if something referenced a single row, and nothing does.
  • User deleted: ON DELETE CASCADE to profiles. Deleting from auth.users cascades to profiles, then here. Referencing profiles keeps our tables pointing at our tables (auth.users belongs to Supabase, which is why 0004 needed a REFERENCES grant), and no entitlement can exist without a profile. An entitlement is account state, not a transaction record, so nothing requires keeping it once the user erases their account.
  • No deleted_at: soft delete is for syncable entities that clients create offline. Entitlements aren't one, and a soft-deleted row would make re-enabling an un-delete.
  1. Create packages/core/src/db/schema/user-feature-entitlements.ts:
TypeScript
import { pgTable, primaryKey, text, timestamp, uuid } from 'drizzle-orm/pg-core';

import { profiles } from './profiles';

export const userFeatureEntitlements = pgTable(
  'user_feature_entitlements',
  {
    userId: uuid('user_id')
      .notNull()
      .references(() => profiles.id, { onDelete: 'cascade' }),
    featureKey: text('feature_key').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (self) => {
    return [
      primaryKey({
        columns: [self.userId, self.featureKey],
      }),
    ];
  },
);

The string passed to uuid() is the SQL column name; the object key is only the TypeScript name. A column-level .primaryKey() makes that one column the primary key, so two of them would declare two primary keys, which Postgres rejects. The composite key goes in pgTable's third argument, which returns an array of constraints (returning the bare primaryKey(...) gives a confusing overload error).

  1. Export it from packages/core/src/db/schema/index.ts. Drizzle Kit reads only that file, so an unexported table produces no migration:
TypeScript
export * from './user-feature-entitlements';

Step 2 — Generate the Migration

What and why: Drizzle Kit compares the schema with the last snapshot in migrations/meta/ and writes only the difference. It doesn't connect to the database, but the config still needs .env.local to load.

  1. Generate it with a readable name:
Shell
pnpm --filter @sidekick/core db:generate --name user_feature_entitlements
  1. Read 0006_user_feature_entitlements.sql. The composite key is a named constraint inside CREATE TABLE, and the foreign key comes after it as a separate ALTER TABLE, because Drizzle always adds foreign keys last so tables can be created in any order. --> statement-breakpoint is where Drizzle splits the file into separate statements.

  2. Notice what's missing: access control. 0001's ALTER DEFAULT PRIVILEGES grants app_runtime SELECT, INSERT, UPDATE and DELETE the moment the table exists, with no RLS on it.

The journal and snapshot. _journal.json lists migrations in order. drizzle-kit migrate records each one it applies in drizzle.__drizzle_migrations and on the next run applies only newer entries. An edited migration therefore never re-runs where it was applied, while a fresh database gets the edited version, so the two drift. That's why applied migrations are never edited. 0006_snapshot.json is the whole schema after this migration, the baseline for the next generate.


Step 3 — Lock It Down

What and why: Who may write this table? Not app_runtime: every user request runs as that role, so one careless route would let a user grant themselves a feature. Only the privileged postgres role (DATABASE_DIRECT_URL) writes rows, and it needs nothing granted: it owns the table, and it has BYPASSRLS, which beats even FORCE. Nobody updates rows: granting is an insert and revoking is a delete.

  1. Create an empty custom migration:
Shell
pnpm --filter @sidekick/core db:generate --custom --name user_feature_entitlements_rls
  1. Write 0007_user_feature_entitlements_rls.sql:
SQL
-- Ensure RLS is on (idempotent — safe to run even if already enabled)
ALTER TABLE public.user_feature_entitlements ENABLE ROW LEVEL SECURITY;

-- FORCE means the policy applies even to the table owner role.
ALTER TABLE public.user_feature_entitlements FORCE ROW LEVEL SECURITY;

-- Revoke mutations by app_runtime role on this table
-- By default, all tables on `public` schema get CRUD permissions
-- Blocking mutations here since users must never grant themselves features
REVOKE UPDATE, INSERT, DELETE ON public.user_feature_entitlements FROM app_runtime;

-- Drop the policy if already exists before creating to allow migration re-runs
DROP POLICY IF EXISTS "users_read_own_entitlements" ON public.user_feature_entitlements;

-- A user can only read their own entitlements.
CREATE POLICY "users_read_own_entitlements"
  ON public.user_feature_entitlements
  FOR SELECT
  USING  (user_id::text = current_setting('app.current_user_id', true));

Don't copy 0002's FOR ALL … WITH CHECK policy. FOR ALL with WITH CHECK lets a user insert rows carrying their own user_id, which, combined with the default INSERT grant, is exactly a user granting themselves a feature. FOR SELECT takes only USING; WITH CHECK has nothing to check on a read, and Postgres rejects it.

REVOKE mirrors the GRANT in 0001: same three parts, with GRANT … TO swapped for REVOKE … FROM.


Step 4 — Read It

What and why: The guard (lesson 4) opens withRLS(caller.userId, …) and needs the caller's feature keys inside that transaction.

Why it takes tx, not userId:

  • withRLS sets app.current_user_id with set_config(…, true), which lasts only until the transaction ends, so a pooled connection never carries one user's id into the next request.
  • The user is already inside tx, and the policy filters on it, so the query needs no where. A userId parameter would be redundant, or could disagree with the transaction and quietly return nothing.
  • Without tx, the function would need its own connection: one with no user sees zero rows, and a second withRLS costs a second pooled connection per request.
  • It returns keys, not manifests, so packages/core never imports the registry.
  1. Create packages/core/src/features/entitlements.ts:
TypeScript
import 'server-only';

import type { RlsTx } from '../db';
import { userFeatureEntitlements } from '../db/schema';

const selectFeatureKeys = async (tx: RlsTx) =>
  tx.select({ featureKey: userFeatureEntitlements.featureKey }).from(userFeatureEntitlements);

const toFeatureKeyArray = (entitlements: Awaited<ReturnType<typeof selectFeatureKeys>>) =>
  entitlements.map(({ featureKey }) => featureKey);

/**
 * Retrieves the enabled feature keys of the user whose id withRLS set on tx.
 * RLS filters the rows, so the query needs no user filter of its own.
 * @param tx Transaction opened by withRLS for the caller
 * @returns Keys of enabled features
 */
export async function getEnabledFeatures(tx: RlsTx): Promise<string[]> {
  return toFeatureKeyArray(await selectFeatureKeys(tx));
}

The database call and the pure transform are separate functions, and getEnabledFeatures composes them. Selecting only featureKey lets Drizzle infer the row type. There's no ORDER BY, so callers must not rely on order.


Step 5 — Prove It

What and why: Unit tests can't prove RLS or grants; only a real Postgres can. tests/with-test-db.sh builds a throwaway PostgreSQL 17 from the Supabase stand-ins and every migration, runs the command and deletes the cluster. Install the tools once with brew install postgresql@17.

  1. The seed needs the privileged role, and the script didn't export one. DATABASE_URL is app_runtime and TEST_AUTH_DATABASE_URL is supabase_auth_admin; neither can write this table. Add to tests/with-test-db.sh:
Shell
# postgres: the privileged migration/seed role, the only one that writes entitlements
export TEST_ADMIN_DATABASE_URL="$(url postgres)"
  1. Create packages/core/tests/integration/entitlements.test.ts, not under src/: pnpm test runs everything under src/ without a database. The file:
  • opens authDb, adminDb and runtimeDb with postgres(url, { max: 1 });
  • inserts three users into auth.users (the 0005 trigger creates their profiles, which the foreign key needs), then seeds entitlements through adminDb with postgres.js's multi-row helper, adminDb(rows, 'user_id', 'feature_key'). Building (${a}, ${b}) strings inside the tagged template sends them as one text parameter, not SQL;
  • has six tests:
TestHow
returns only userA's / userB's feature keys (it.each)withRLS(userId, getEnabledFeatures), sorted before comparing
returns zero rows without a user contextruntimeDb\SELECT 1 FROM user_feature_entitlements``
cannot insert, even for the caller's own userwithRLS insert → rejects with "permission denied for table …"
cannot delete, even the caller's own rowswithRLS delete → rejects with "permission denied for table …"
cascades through profiles to their entitlementsdelete from auth.users via authDb, then count via adminDb (bypasses RLS)

Match the error message, not just the rejection. Both the REVOKE and RLS fail with SQLSTATE 42501, but "permission denied" comes only from the REVOKE. Drizzle wraps the driver error, so the message sits on cause:

TypeScript
const permissionDenied = {
  cause: expect.objectContaining({
    message: 'permission denied for table user_feature_entitlements',
  }),
};

await expect(insert).rejects.toMatchObject(permissionDenied);
  1. Run it:
Shell
pnpm --filter @sidekick/core test:integration

Expect 9 passed: 6 here and 3 in rls.test.ts.

  1. Break each wall, one at a time. Guess which test fails before running, and put each one back before the next. Editing a migration is safe here because the script rebuilds the database every run.
BreakWhat fails
Policy USING (true)Both own-rows reads (each user sees everything) and the context-free query, which only returned zero rows because NULL never matched.
REVOKE commented outInsert now fails with "new row violates row-level security policy" (RLS denies by default). Delete doesn't fail at all: RLS filters it to zero rows.
ON DELETE restrict in 0006The cascade test fails on the DELETE FROM auth.users line with a foreign key violation. The whole statement rolls back, user and profile included.

The second row is the reason both walls exist: without the REVOKE, a forbidden delete silently does nothing.


Step 6 — Apply to Dev

What and why: Put the table on the dev Supabase project, which is a real database, so commit first.

  1. From the repo root:
Shell
pnpm db:migrate
  1. Check it in the Supabase dashboard: the table shows RLS enabled and no rows, and users_read_own_entitlements is listed for SELECT.

  2. In the SQL Editor, list who holds which privileges:

SQL
select grantee, privilege_type
from information_schema.role_table_grants
where table_name = 'user_feature_entitlements'
order by grantee, privilege_type;

app_runtime holds only SELECT, and postgres and service_role hold everything. anon and authenticated don't appear, if you followed the post notes in Phase 1.1 and Pre-2. Sidekick's dev project showed both with full privileges here, TRUNCATE included, which is how the gap was found (see the post note below).


Step 7 — Verify Like CI and Ship

  1. Run everything uncached:
Shell
pnpm prettier:check
pnpm turbo lint typecheck build test --force
pnpm --filter @sidekick/core test:integration

If web#build fails with Cannot find module …/next/dist/bin/next, node_modules is stale after a dependency update. Run pnpm install and try again.

  1. Commit, push and open the PR:
Shell
git add packages/core
git commit -m "feat(core): add user_feature_entitlements table and getEnabledFeatures"
git push -u origin feature/P2L3-entitlements
gh pr create --fill

Wait for the checks job (it runs test:integration on PostgreSQL 17), then squash-merge.


What you have now

  • user_feature_entitlements with a composite primary key, a cascading foreign key to profiles, forced RLS with a read-only own-rows policy, and no write privileges for app_runtime.
  • getEnabledFeatures(tx) in packages/core/src/features/entitlements.ts, internal to core until the guard uses it.
  • Six integration tests, each proven to fail when the wall it guards is removed.

Next: lesson 4, withApiGuard.


Post note — Found at the End of This Lesson (added 2026-10-23)

Three follow-ups came out of this lesson. If you're following along, they're already folded into earlier walkthroughs as post notes, so you do them before wrapping up those phases:

  • Data API roles. Step 6's grants query showed anon and authenticated with every privilege on profiles and user_feature_entitlements. Fixed in sidekick#17: see the post notes in Phase 1.1 (the migration and turning off the Data API) and Pre-2 (the stub roles, TEST_ADMIN_DATABASE_URL and the proof test). If you did those, step 5's with-test-db.sh change is already in place.
  • undefined, not null. resolveApiCaller now returns undefined for no caller (sidekick#16); see the lesson 2 walkthrough.
  • pnpm's dead "pnpm" field. Removed in sidekick#14; see the post note in Phase 0 checkpoint B.
Arkive

Index

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

Tags (137)

View

233 entries.

As ofTitleKind
2026-11-01Decisions Logdecisionlog
2026-11-01Synergy Checkpoint 3a: Prove the Store, Plan 3bplan phase-3 checkpoint guidanceplan
2026-11-01Synergy Lesson 1: Layer Folders and Lintplan phase-3 task monorepo eslintplan
2026-11-01Synergy Lesson 10: Save Call, Anchorsplan phase-3 task synergy apiplan
2026-11-01Synergy Lesson 11: Delete and Restoreplan phase-3 task synergy databaseplan
2026-11-01Synergy Lesson 12: Tagsplan phase-3 task synergy apiplan
2026-11-01Synergy Lesson 13: Race Testsplan phase-3 task synergy testing postgresqlplan
2026-11-01Synergy Lesson 2: Per-Package Migrationsplan phase-3 task database drizzle testingplan
2026-11-01Synergy Lesson 3: Entity Index and Version Logplan phase-3 task synergy database rls postgresqlplan
2026-11-01Synergy Lesson 4: Sandbox Providers and the First Routesplan phase-3 task synergy feature-system apiplan
2026-11-01Synergy Lesson 5: Outbox, Status and Versionsplan phase-3 task synergy database postgresqlplan
2026-11-01Synergy Lesson 6: Links, Relation Types and Cyclesplan phase-3 task synergy graph postgresql apiplan
2026-11-01Synergy Lesson 7: Staleness Dots and the Roll-Upplan phase-3 task synergy apiplan
2026-11-01Synergy Lesson 8: Lists and Supersedeplan phase-3 task synergy graph postgresqlplan
2026-11-01Synergy Lesson 9: Save Call, Mentionsplan phase-3 task synergy apiplan
2026-11-01Violations and Exceptionssystem-design synergyspec
2026-11-01Content Sequencesystem-design synergyspec
2026-11-01Tombstone Visibilitysystem-design synergy rlsspec
2026-11-01Anchors in Contentsystem-design synergy anchorsspec
2026-11-01Capture External Contentsystem-design synergy taxilaspec
2026-11-01Lexicon Highlightingsystem-design synergy taxilaspec
2026-11-01Mentions and Link Lifetimesystem-design synergyspec
2026-11-01Synergy Store Choicessystem-design synergy postgresqlspec
2026-11-01Synergy: System Designsystem-design synergyspec
2026-11-01Testing Layerssystem-design testing vitest playwrightspec
2026-11-01Synergy - Feature Specificationsprd spec synergyprd
2026-11-01Relationshipsprd feature synergyprd
2026-11-01Scope and Phasesprd feature synergyprd
2026-11-01Best Practice Rulessystem-design code-quality-check eslintspec
2026-11-01Stay on ESLint, Revisit Oxlintsystem-design eslint typescriptspec
2026-11-01Agent Guideai-coding agent gateway agent-guidance rls supabase drizzle api react prettierguidance
2026-11-01API Versioningsystem-design apispec
2026-11-01App Runtime for Drizzlesystem-design database drizzle postgresqlspec
2026-11-01Best Practicesai-coding-harness agent-guidance drizzle api react pnpm css offline embedding soft-deleteguidance
2026-11-01Centralized Copysystem-design contentspec
2026-11-01Corepacksystem-design monorepo pnpmspec
2026-11-01CSS Modulessystem-design css eslint mantinespec
2026-11-01Dependency Flowsystem-design monorepo clispec
2026-11-01dotenv CLIsystem-design config clispec
2026-11-01Edge Runtimesystem-design security supabasespec
2026-11-01Env Vars in Turbo JSONsystem-design monorepo turborepo vercelspec
2026-11-01ESLint Plugin Boundariessystem-design code-quality-check eslintspec
2026-11-01Flat Configsystem-design code-quality-check eslintspec
2026-11-01Force Dynamicsystem-design nextjs supabasespec
2026-11-01GraphQL and Relaysystem-design api graphql relayspec
2026-11-01Installation at Workspace Levelsystem-design code-quality-check typescript pnpmspec
2026-11-01Module Resolution: Bundlersystem-design code-quality-check typescriptspec
2026-11-01Prettier at Repo Levelsystem-design code-quality-check prettierspec
2026-11-01Profile Creation Postgres Triggersystem-design security postgresql api authenticationspec
2026-11-01Public API Onlysystem-design api rls authentication clispec
2026-11-01Runtime Validationssystem-design typescriptspec
2026-11-01Shared tsconfigsystem-design code-quality-check typescriptspec
2026-11-01Synergyplan living-plan phase-3 synergy rls postgresql api graphplan
2026-11-01tsupsystem-design code-quality-check eslintspec
2026-11-01Turboreposystem-design monorepo turborepo pnpmspec
2026-11-01Vercelsystem-design monorepo turborepo pnpm vercelspec
2026-10-31Entities and the Entity Indexprd feature synergyprd
2026-10-31Foundationsprd feature synergyprd
2026-10-31Keeping Links Trueprd feature synergyprd
2026-10-31Sneak Peek Linkprd feature synergyprd
2026-10-30Search and Backlinksprd feature synergyprd
2026-10-30Tagsprd feature synergyprd
2026-10-29Cost to Add Laterprinciple product engineeringguidance
2026-10-27Individual Firstprinciple productguidance
2026-10-27One Interfaceprinciple api cliguidance
2026-10-27Overview of Synergyprd feature synergyprd
2026-10-24Gatekeeper Lesson 7 Walkthrough: The Ops Package and Entitlements Grantbuild walkthrough phase-2 feature-system database postgresql cliguidance
2026-10-24Gatekeeper Lesson 8: Close-Outplan phase-2 task guidanceplan
2026-10-24Gatekeeper Walkthroughbuild walkthrough phase-2 api-guard feature-system rls authenticationguidance
2026-10-24Gatekeeper Lesson 3 Walkthrough: EntitlementsReadingbuild walkthrough phase-2 feature-system database drizzle rls postgresql testingguidance
2026-10-24Gatekeeper Lesson 4 Walkthrough: withApiGuardbuild walkthrough phase-2 api-guard rls api authentication testingguidance
2026-10-24Gatekeeper Lesson 5 Walkthrough: Request and Auth-Failure Loggingbuild walkthrough phase-2 api-guard observability eslint testingguidance
2026-10-24Gatekeeper Lesson 6 Walkthrough: /api/health and Guard Verificationbuild walkthrough phase-2 api-guard api nextjs testingguidance
2026-10-24Gatekeeper Lesson 2 Walkthrough: resolveApiCallerbuild walkthrough phase-2 api-guard authentication supabase testingguidance
2026-10-24Gatekeeper Build Rules and Target Designplan phase-2 api-guard rls api authentication typescript guidanceplan
2026-10-24Gatekeeper Lesson 1 Walkthrough: Feature Registrybuild walkthrough phase-2 feature-system typescript monorepo testingguidance
2026-10-24Gatekeeper Lesson 7 (Task 2.10): Dev Entitlement Seed Scriptplan phase-2 task feature-system database postgresqlplan
2026-10-24Front Door: Hardening Walkthroughbuild walkthrough pre-2 rls supabase drizzle postgresql testing eslintguidance
2026-10-24Backlogged / Unplannedplan living-plan backlog feature-system taxila zinsser alter-ego parrot rls supabaseplan
2026-10-24Commands and Environmentai-coding command environment agent-guidance prettier pnpm cliguidance
2026-10-24Gatekeeperplan living-plan phase-2 api-guard rls api authentication feature-systemplan
2026-10-24Living Implementation Planplan living-plan taxila zinsser alter-ego war-room factory parrot core-driveplan
2026-10-24Terminalplan living-plan phase-9 taxila api-guard rls api authentication cliplan
2026-10-24With API Guardsystem-design security api-guard rls api authentication typescriptspec
2026-10-23Gatekeeper Lesson 3 (Tasks 2.8, 2.9): Entitlements Table and getEnabledFeaturesplan phase-2 task feature-system database drizzle rls postgresql testingplan
2026-10-23Gatekeeper Lesson 4 (Tasks 2.2, 2.3): withApiGuard With withRLSplan phase-2 task api-guard rls api security testingplan
2026-10-23Gatekeeper Lesson 5 (Tasks 2.4, 2.5): Request and Auth-Failure Loggingplan phase-2 task api-guard observability eslintplan
2026-10-23Gatekeeper Lesson 6 (Tasks 2.11, 2.12): /api/health and Guard Verificationplan phase-2 task api-guard api nextjs testingplan
2026-10-23Centralizedsystem-design observability api authenticationspec
2026-10-23Database and Securityai-coding database security agent-guidance api-guard rls drizzle api react repository-patternguidance
2026-10-23Error Handlingsystem-design observability api-guard rls supabase api nextjs react aispec
2026-10-23Front Door: Row-Level Security Walkthroughplan phase-1.1 rls database supabase drizzle postgresql api typescriptguidance
2026-10-23Groundwork Checkpoint B Walkthroughbuild walkthrough phase-0 checkpointguidance
2026-10-20Gatekeeper Lesson 2 (Task 2.1): resolveApiCallerplan phase-2 task api-guard authentication supabase nextjsplan
2026-10-18Gatekeeper Lesson 1 (Tasks 2.6, 2.7): FeatureManifest and ALL_FEATURESplan phase-2 task feature-system typescript monorepoplan
2026-10-18Registrysystem-design feature-systemspec
2026-10-17Core Drive to Be Practical and Grounded in Realitysystem-design feature core-drive prdprd
2026-10-17MVP Scopeprd mvp specification core-drive taxila war-room factory alter-ego zinsser parrot api cli native-appprd
2026-10-17An AI Writing Coach and an Appsystem-design prd feature zinsser aiprd
2026-10-17Overview of Taxilasystem-design prd feature taxila ragprd
2026-10-16Front Door: Hardeningplan pre-2 foundation security database testingplan
2026-10-16Server Actionssystem-design nextjs rls 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-13Core Drive Stores Personal and Sensitive Informationsystem-design prd feature core-drive taxila graphprd
2026-10-13Core Drive Stores Values Onlysystem-design prd feature core-drive war-room factoryprd
2026-10-13Core Drive to Foster Reflections and Learningssystem-design prd feature core-driveprd
2026-10-13Groundwork: Checkpointsplan phase-0 api nextjs typescript eslint turborepo pnpmplan
2026-10-13Model Routingprd vercel ai embedding routingprd
2026-10-13Overview of Core Drivesystem-design prd feature core-drive factory ai alter-egoprd
2026-10-13Source Attributionprd feature alter-ego aiprd
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-09-19Actual Stateglossary terminologyglossary
2026-09-19Algorithm of Lifeglossary terminology nextjsglossary
2026-09-19Alter Egoplan living-plan phase-6 taxila zinsser alter-ego war-room factory core-driveplan
2026-09-19Alter Egosystem-design prd feature taxila alter-ego factory aiprd
2026-09-19API Firstsystem-design api clispec
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-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-19Centralized and Client-Agnosticsystem-design security rls api authentication clispec
2026-09-19CLIsystem-design cli apispec
2026-09-19Context Assemblersystem-design ai war-room factory api-guardspec
2026-09-19Coresystem-design feature-systemspec
2026-09-19Core Drive and Taxilasystem-design prd feature taxila core-driveprd
2026-09-19Driving Forces and Key Featuressystem-design api offlinespec
2026-09-19Embedding Status Fieldsystem-design rag embedding typescriptspec
2026-09-19Enforced Conventionssystem-designspec
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-19Front Doorplan living-plan phase-1 api-guard rls supabase drizzle postgresql apiplan
2026-09-19Front Door Task 1.1plan phase-1 task supabase postgresql api authentication nextjsplan
2026-09-19Front Door Task 1.10plan phase-1 task rls supabase drizzle postgresql authentication typescriptplan
2026-09-19Front Door Task 1.11plan phase-1 task api-guard rls supabase api authentication nextjsplan
2026-09-19Front Door Task 1.14plan phase-1 task react pnpm mantine cssplan
2026-09-19Front Door Task 1.17plan phase-1 task supabase authenticationplan
2026-09-19Front Door Task 1.18plan phase-1 task api-guard rls supabase drizzle postgresql authenticationplan
2026-09-19Front Door Task 1.2plan phase-1 task supabase drizzle postgresql authentication nextjs pnpmplan
2026-09-19Front Door Task 1.3plan phase-1 task supabase nextjs typescriptplan
2026-09-19Front Door Task 1.4plan phase-1 task supabase authentication nextjs react typescriptplan
2026-09-19Front Door Task 1.5plan phase-1 task rls supabase authentication typescriptplan
2026-09-19Front Door Task 1.6plan phase-1 task rls supabase drizzle authentication typescript offlineplan
2026-09-19Front Door Task 1.7plan phase-1 task drizzle postgresql typescriptplan
2026-09-19Front Door Task 1.8plan phase-1 task turborepo pnpmplan
2026-09-19Front Door Task 1.9plan phase-1 task rls supabase drizzle postgresql authenticationplan
2026-09-19Front Door Tasks 1.12 and 1.13plan phase-1 task supabase api authentication nextjs react typescriptplan
2026-09-19Front Door Tasks 1.15 and 1.16plan phase-1 task supabase authentication nextjs react mantineplan
2026-09-19Front Door: Original Planplan phase-1 rls supabase drizzle postgresql authentication nextjsguidance
2026-09-19Front Door: Row-Level Securityplan living-plan phase-1.1 rls supabase drizzle postgresql pnpm soft-deleteplan
2026-09-19Groundworkplan living-plan phase-0 nextjs typescript eslint prettier turborepo pnpmplan
2026-09-19Groundwork Checkpoint Aplan phase-0 checkpoint nextjs typescript turborepo pnpm cliplan
2026-09-19Groundwork Checkpoint Bplan phase-0 checkpoint eslint prettier turborepo pnpmplan
2026-09-19Groundwork Checkpoint Cplan phase-0 checkpoint nextjs pnpmplan
2026-09-19Groundwork Checkpoint Dplan phase-0 checkpoint api-guard rls supabase drizzle api authenticationplan
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-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-19Never Mutate Outside API Layersystem-design apispec
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-19Open Houseplan living-plan phase-11plan
2026-09-19Parrotsystem-design prd feature parrotprd
2026-09-19Pocketplan living-plan phase-8 taxila alter-ego nextjs vercel pwa mobileplan
2026-09-19Prefer JSON Configsystem-design monorepospec
2026-09-19Present Stateglossary terminologyglossary
2026-09-19Productivity Modulesystem-design prd feature war-roomprd
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-19Soft-Delete Supportsystem-design database soft-deletespec
2026-09-19Start Todayprinciple core-drive execution consistencyguidance
2026-09-19State Representationsystem-design api aispec
2026-09-19Storefrontplan living-plan phase-12 api offlineplan
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-19Taxilaplan living-plan phase-4 taxila api-guard rls drizzle api authenticationplan
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-19Use Navigation Hooksystem-design nextjsspec
2026-09-19War Roomplan living-plan phase-7 war-room factory core-drive rls api offlineplan
2026-09-19Watchtowerplan living-plan phase-10 api-guard rls api authentication nextjs offlineplan
2026-09-19Zinsserplan living-plan phase-5 taxila zinsser api mantine ai embeddingplan
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-29Config Files Explainedbuild walkthrough phase-0 turborepo typescript eslint prettierguidance
2026-05-29Front Door: Original Walkthroughbuild walkthrough phase-1 supabase drizzle authenticationguidance
2026-05-29Groundwork Checkpoint A Walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Groundwork Checkpoint C Walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Groundwork Checkpoint D Walkthroughbuild walkthrough phase-0 checkpointguidance