This is a harness for developing Datagrok lightweight applications, along with apps. The idea is to make developing apps by AI a quick, straightforward, and reproducible process. All apps share the same logical structure, same UI, same component library, design philosophy, testing concepts, same database approaches, and they share a core database schema with users, groups, security, etc.
The app factory is designed for development velocity.
- Read /docs/CODING.md and /docs/DATABASE.md and /docs/DESIGN.md (they are short)
- Read the app-specific docs in the app you're working on: ./docs/DOMAIN.md, ./docs/ARCHITECTURE.md, ./docs/STATUS.md
- Check ./docs/STATUS.md for what's already built
packages/
app-core/ # Non-UI client infrastructure: auth context, API hooks, mock adapters, permissions
app-kit/ # Client UI components, theme (re-exports app-core for convenience)
core-schema/ # Drizzle tables + types for core Datagrok entities, auditColumns() helper
server-kit/ # Server harness: createApp(), createDb(), standard middleware & routes
test-utils/ # Shared test helpers: createTestHeaders(), renderWithProviders(), DB fixtures
apps/
send/ # SEND nonclinical study app
grit/ # GRIT issue tracker app
app-host/ # Unified SPA hosting all apps (icon strip + namespaced API routing)
tools/
create-app/ # Scaffolding tool for new apps
- Database: All apps share one PostgreSQL instance (
datagrok_dev). Core tables are auto-created bypackages/core-schema/sql/mounted into Docker's init directory. App tables live in app-specific schemas (e.g.send.*). - DATABASE_URL:
postgresql://datagrok:datagrok_local@localhost:5433/datagrok_dev— defined in root.env.example, used everywhere. - Server setup: Use
createApp()from@datagrok/server-kit— provides CORS, logging, request-id, auth middleware, error handler, and/api/health+/api/auth/meroutes out of the box. - DB connection: Use
createDb({ schema })from@datagrok/server-kit— readsDATABASE_URLfrom env. - Audit columns: Use
auditColumns()from@datagrok/core-schemaon entity tables (top-level things users create/own) — returnsid,entity_id(FK →entities.idfor the privilege system),created_at,updated_at,created_by(FK →users.id). Detail/child tables that cascade-delete with a parent only needid. - Auth:
X-User-Idheader validated as UUID by server-kit middleware, available asc.var.userIdin Hono handlers. - Well-known UUIDs: Import
SYSTEM_USER_ID,ADMIN_USER_IDfrom@datagrok/core-schema— never define local copies.
Each app exports a client definition (ClientAppDefinition) and a server definition (ServerAppDefinition). The app-host loops over arrays of these to mount all apps automatically.
- Client:
apps/<id>/client/src/app-definition.ts→ exports{ id, name, icon, routes } - Server:
apps/<id>/server/app-definition.ts→ exports{ id, name, routes }(Hono instance composing all route files) - Package exports: Each app's
package.jsonexports./client/app-definitionand./server/app-definition - Routing convention: The
iddrives all paths —/api/${id}for server,/${id}/*for client - Adding a new app to app-host: 2 imports + 2 array entries (one client, one server)
- Use
<Shell>+<View>from@datagrok/app-kitfor app layout - Use
<DataGrid>from@datagrok/app-kitfor all tabular data (powered by AG Grid Community) - Use
@datagrok/app-kitcomponents, never raw HTML or direct Shadcn imports - Use
createApp()from@datagrok/server-kitfor server setup, never manual Hono boilerplate - Use
createDb()from@datagrok/server-kitfor DB connections - Use
auditColumns()from@datagrok/core-schemaon entity tables (not on detail/child tables) - Define types in
/shared/schema.tsusing Drizzle, derive Zod and TS types from it - Run
npm test,npm run typecheck, andnpm run lintbefore considering a task done - Keep shared/ as the single source of truth for types
- Use relative URLs in app page links (e.g.
study/123,..) so apps work in both standalone and app-host modes
- Use
anytype - Add dependencies without checking if app-kit, server-kit, or an existing package already covers the need
- Modify shared/ types without considering impact on other code that imports them
- Skip Zod validation on API endpoints
- Hardcode colors, spacing, or other design tokens — use app-kit theme
- Use
pgEnum()— usevarchar+ Zod validation instead (pgEnum leaks into public schema) - Define local
SYSTEM_USER_ID/ADMIN_USER_IDconstants — import from@datagrok/core-schema - Hardcode database connection strings — use
DATABASE_URLenv var viacreateDb() - Deprecate code — just delete it. No
@deprecated, no backwards-compat shims. We iterate quickly with no external consumers.