memory coding
Project Context Memory
project-context conventions architecture onboarding
Targets
---
id: "a7c3e1f4-9b2d-4e8a-b6f0-3d5c7a9e1b4f"
name: "Project Context Memory"
type: memory
category: coding
version: "1.0.0"
author: "markeddown"
license: MIT
min_context_tokens: 4096
target_frameworks:
- markeddown
- cursor
- claude
- generic
tags:
- project-context
- conventions
- architecture
- onboarding
---
# Project Context Memory
Persistent codebase context that gives an AI agent an accurate mental model of this project from the first message. Keep this file updated as the stack, conventions, and active work evolve. The goal is zero "how is this project structured?" questions at the start of a session.
## Tech Stack
- **Language:** TypeScript 5.6, strict mode enabled. No `any` — use `unknown` and narrow.
- **Runtime:** Node 20 LTS. Bun is not used; some CI scripts assume Node APIs.
- **Framework:** Next.js 14 App Router. Pages in `app/`, API routes in `app/api/`. Server components by default; `"use client"` only when interactivity requires it.
- **Database:** PostgreSQL 16 on Neon (serverless). Queries go through Drizzle ORM — no raw SQL in route handlers. Migrations managed with `drizzle-kit push`.
- **Cache:** Redis via Upstash (REST-based client, no persistent connection). Used for rate limiting and session tokens. Not used as a primary data store.
- **Hosting:** Vercel. Edge middleware for auth checks. Serverless functions for API routes. ISR for marketing pages, SSR for dashboard.
- **Package manager:** pnpm 9. Lockfile committed. `pnpm-workspace.yaml` exists but this is a single-package repo (workspace was set up for future extraction).
## Architecture Decisions
| Decision | Choice | Rationale |
|---|---|---|
| State management | Zustand (3 stores: auth, ui, workspace) | Minimal boilerplate, works with RSC without provider wrappers |
| Auth | NextAuth v5 (beta) with GitHub + Google providers | Built-in adapter support for Drizzle; handles session, CSRF, token rotation out of the box |
| Styling | Tailwind 3.4 + `cn()` utility from shadcn/ui | Colocated styles, no runtime CSS, consistent with component library |
| Component library | shadcn/ui (copy-paste, not npm dependency) | Full control over component source, no version lock-in |
| API layer | Server actions for mutations, route handlers for public API | tRPC was evaluated but added complexity without enough benefit for a single-dev project |
| Testing | Vitest for unit/integration, Playwright for e2e | Fast unit tests (~200ms cold start), reliable browser tests for critical flows |
| Error tracking | Sentry (free tier) | Source maps uploaded on deploy, alert rules on new issues and 10x spikes |
| Email | Resend (transactional only) | Simple API, good deliverability, generous free tier |
## Naming Conventions
- **Files:** kebab-case for all source files (`user-profile.tsx`, `auth-utils.ts`). One export per file for components; utilities may export multiple.
- **Components:** PascalCase exports matching filename (`UserProfile` in `user-profile.tsx`). Never default exports — always named.
- **Database tables:** snake_case plural (`user_sessions`, `api_keys`). Junction tables join both names (`user_workspace_roles`).
- **Database columns:** snake_case. Timestamps always `created_at` / `updated_at`. Foreign keys always `{referenced_table_singular}_id`.
- **Environment variables:** `SCREAMING_SNAKE`. Client-exposed vars prefixed `NEXT_PUBLIC_`. Secret vars never prefixed. Group by service: `DB_`, `REDIS_`, `STRIPE_`, `RESEND_`, `SENTRY_`.
- **Branches:** `feat/short-description`, `fix/short-description`, `chore/short-description`. No ticket numbers in branch names (they go in commit messages).
- **Commits:** Conventional commits, lowercase, imperative mood. `feat: add workspace invite flow`. Include ticket reference in body if applicable.
## Directory Structure
```
src/
app/ # Next.js App Router — routes, layouts, loading/error boundaries
(marketing)/ # Route group: landing, pricing, docs (ISR)
(dashboard)/ # Route group: authenticated app pages (SSR)
api/ # Route handlers (public API + webhooks)
components/
ui/ # shadcn/ui primitives (button, dialog, input, etc.)
forms/ # Form components with react-hook-form + zod
layout/ # Shell, sidebar, header, footer
domain/ # Feature-specific components (workspace-switcher, billing-card)
lib/
db/ # Drizzle schema, migrations, query helpers
auth/ # NextAuth config, session utilities
billing/ # Stripe helpers, plan definitions, webhook handlers
email/ # Resend templates and send functions
utils/ # Pure utility functions (formatting, validation, cn())
types/ # Shared TypeScript types and Zod schemas
hooks/ # Custom React hooks
```
## Code Patterns to Follow
- **Async:** `async/await` everywhere. No `.then()` chains. No floating promises — always `await` or explicitly discard with `void fn()`.
- **Error handling:** Let unexpected errors bubble to the nearest error boundary. Only catch errors you can meaningfully handle. Never `catch (e) {}` silently.
- **Early returns:** Validate and bail at the top of functions. Main logic should never be more than 2 levels of indentation deep.
- **Database:** All queries go through Drizzle. Use `db.transaction()` for multi-step writes. Never construct SQL strings manually.
- **Validation:** Zod schemas at the boundary (API routes, form submissions, webhook payloads). Interior code trusts the validated types.
- **Env vars:** Never commit `.env`. `.env.example` has every key with a placeholder value and a comment explaining what it does. CI validates that all required vars are set before deploy.
- **Imports:** Absolute imports via `@/` alias (mapped to `src/`). No relative imports that go up more than one level (`../` is fine, `../../` means the code is in the wrong place).
- **Tests:** Colocated next to source (`foo.ts` / `foo.test.ts`). Unit tests mock nothing except external HTTP calls. Integration tests use a real test database (Neon branch).
## Known Constraints
- **Vercel function size:** 50 MB max. The Drizzle + Stripe + Sentry bundle is ~18 MB — leaves headroom, but watch for heavy image processing or PDF libs.
- **Neon cold starts:** First query after idle can take 200–500ms. Not an issue for authenticated routes (session check warms the connection) but noticeable on public API endpoints. Mitigate with Neon's `@neondatabase/serverless` driver which uses HTTP, not TCP.
- **NextAuth v5 is in beta.** Breaking changes are possible on minor updates. Pin the exact version in `package.json` and test auth flows after any update.
- **Rate limits:** Stripe webhooks retry with exponential backoff for up to 72 hours. Resend free tier is 100 emails/day. Upstash free tier is 10K commands/day.
- **Legacy routes:** `/api/v1/` endpoints are frozen and serve only the mobile app. All new API work targets `/api/v2/`. Do not modify v1 without explicit approval.
## Current Focus
- Shipping the workspace invite flow: users can invite teammates via email, invitees join the workspace on signup or login.
- Migrating billing from per-user to per-workspace pricing. Stripe subscription is being moved from `users` table to `workspaces` table.
- Feature flag `ENABLE_WORKSPACE_BILLING` gates the new billing flow. Remove the flag and the old per-user code path once 100% of users are migrated.
Download
Compatibility
gpt-4o-mini 100% sanity-v1
claude-haiku-4-5 80% sanity-v1