-
Notifications
You must be signed in to change notification settings - Fork 0
02_Architecture
Last updated: 2026-05-07
This is the short developer map of how Princeps is built.
Next.js App Router
React + TypeScript
Tailwind CSS + shadcn/ui + Lucide
PostgreSQL + Prisma + pgvector
Better Auth
next-intl
OpenAI / Ollama / Groq through lib/llm-providers
Stripe for billing
Langfuse for optional production LLM tracing
Google APIs for current integrations
Use package.json for exact versions.
app/ Pages, layouts, API routes, cron routes
components/ Client UI and feature shells
hooks/ Shared client hooks
lib/ Server logic and cross-cutting systems
messages/ de/en user-facing strings
prisma/ Schema, migrations, generated client
scripts/ Local setup, seed, healthcheck
types/ Client-safe shared types
CONTEXT/ Agent implementation context
docs/ Human wiki
Most features follow this shape:
app/(app)/<feature>/page.tsx
-> authenticate
-> load initial data through lib/<feature>/
-> render components/<feature>/<Feature>Shell
client action
-> fetch app/api/<feature>/*
-> route authenticates, validates, tier-gates
-> route delegates to lib/<feature>/
-> lib writes/reads Prisma through @/lib/db
API routes should stay thin. Business logic belongs in lib/<feature>/.
Server-only code includes:
- Prisma and
@/lib/db. - Better Auth server helpers.
- LLM provider calls.
- Stripe.
- pgvector queries.
- Integration clients and tokens.
- Node-only parsing or filesystem APIs.
Server-only modules should use import "server-only". Client components must not import a chain that reaches @/lib/db.
Auth uses Better Auth with email/password sessions stored in Postgres.
Important behavior:
- Session expiry is 3 days.
- Sessions refresh after 1 day.
- Password minimum length is 8.
- Username plugin enforces 3-30 character usernames.
- Email verification is currently disabled.
- Password reset links are logged unless a real email provider is wired.
Rate limiting lives in lib/security.ts. It uses Upstash Redis when UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN exist, otherwise an in-memory fallback.
Every server page and API route authenticates independently. proxy.ts is not the trust boundary.
prisma/schema.prisma is the single model.
Common rules:
- User-owned rows include
userId. - Queries and mutations filter by
userId. - Feature rows map to client-safe records in
types/api.ts. - Knowledge embeddings use pgvector.
-
UsageCounterstores daily and monthly usage. -
Integrationstores external provider tokens by(userId, provider).
The AI layer is intentionally split:
lib/llm-providers/ Provider abstraction
lib/context/ System prompt slots
lib/tools/ LLM-callable tools
lib/chat/ Chat persistence and streaming orchestration
Providers:
- OpenAI: chat, streaming, embeddings.
- Ollama: local chat, streaming, embeddings.
- Groq: chat and streaming only.
CHAT_PROVIDER selects the active provider. Current code uses it for embeddings too, so Knowledge needs OpenAI or Ollama.
Tools are feature-agnostic. The registry declares schemas and minTier; handlers validate arguments, enforce limits, and delegate to feature logic.
Settings are mostly stored in User.preferences; timezone and tier are direct User columns.
Tiers are free, pro, premium, and enterprise. Plan values live in types/billing.ts. Enforcement lives in lib/tiers/enforce.ts.
Stripe owns subscription payment:
- Checkout creates paid subscriptions.
- Customer portal handles management.
- Webhooks sync
User.tier. -
/onboarding/successsyncs immediately after checkout as a fast path.
Notifications are persistent, user-scoped assistant inbox records.
Weather uses Open-Meteo server-side. The app prefers saved city coordinates, falls back to timezone coordinates, and sends no user ID or IP to the weather provider.
Daily greetings may call the LLM and consume token quota. Overdue-task nudges are deterministic and do not call the LLM.
Integrations are not login accounts. They are external data connectors stored in Integration rows.
Current providers:
-
google_calendar: Calendar events to Meetings plus best-effort write-back. -
google_drive: Drive file listing and Knowledge import.
Provider logic belongs in lib/integrations/<provider>/; OAuth routes live under app/api/integrations/<provider>/.
Langfuse tracing wraps chat, streaming chat, and single embeddings in production only.
It is a no-op unless:
NODE_ENV=production
LANGFUSE_PUBLIC_KEY is set
LANGFUSE_SECRET_KEY is set
embedBatch is not traced.
Princeps Wiki: USER_GUIDE.md | ARCHITECTURE.md | FEATURES_REFERENCE.md | DEVELOPER_PLAYBOOK.md
For implementation-level agent context, read CONTEXT/. For exact behavior, verify the current code.
<@coldbydefault>
© 2026 PRINCEPS All rights reserved.
Made by AnotherProject™ - ColdByDefault