URL: https://mkdocs.justinsforge.com/memory/general/reference_suite_database_engine/
CANON UPDATE (2026-06-18) , renamed to CreatorTrack. This is the CreatorTrack collection/database engine (product formerly "The Suite"/"Workspace"), built and previewed at
dev.creatortrack.ai. It is the foundation apps plug into: most apps (tasks, habits, CRM, content calendar) are just a collection (schema + view) on this engine, i.e. configuration, not new code. Build order: reusable UI components first, then this Notion-class page framework + database engine as the foundation, then apps on top; iterate back-and-forth until features work. The data layer formerly "lifeos" is now the core database (core). Full canon (with tech-stack overview): creator-suite-vision-strategy.CANON UPDATE (2026-06-18) , Property Type Registry. A property type's knowledge used to be smeared across six parallel structures (
PropTypeunion,COMPUTED_TYPES,ADDABLE_TYPES,TYPE_LABEL,PROP_GLYPH,TYPE_HINT) plus inline switches in Cell/PropertyMenu/FilterSort. It is now consolidated into one canonical registrylib/prop-types.ts:PROP_TYPES: Record<PropType, PropTypeSpec>where a single object fully describes each type (label/glyph/hint, addable/computed, zodconfigSchema/valueSchema,parse/serialize,isEmpty,compare,filterOps,formatText,calcKinds). The free-texttype+ jsonbconfig/valueare interpreted, validated, sorted, filtered and rendered THROUGH this registry. Adding a property type = adding onePROP_TYPESentry (+ a Python migration only if it needs net-new storage) + one entry in the UI dispatch maps (CELL_BY_TYPEin Cell.tsx,CONFIG_EDITORSin PropertyMenu.tsx). The old constants now re-export registry-derived fromcollection.ts. Boundary validation:/api/collection/valueand/propvalidate value/config against the spec's zod schemas before any jsonb write (malformed → 400). Filters are per-type operators (is/contains/before/after/is_empty/checked/…) from each spec'sfilterOps; the AND/OR group builder that composes them is a Tier 2 db-views task. Currency is NOT a separate type: it is the numbernumber_formatvalue"dollar"(USD via Intl), per the locked decision , no stray"currency"literal exists.
CreatorTrack , Collection / Database Engine¶
Built 2026-06-17 in /home/justinwieb/creatortrack (Next.js 16 App Router, React 19, TS,
Drizzle as a typed client over lifeos Postgres; Python migrations own DDL). This is
foundation item #26: the apps-as-building-blocks core. Most apps (tasks, habits, CRM,
projects, content-calendar) are just a collection with a schema + a view, so the engine is
ONE strong collection surface and those apps become CONFIGS, not code. Ported faithfully
from the canonical Flask source scripts/forge_workspace_ui_database.py.
Data model (already in lifeos, unchanged)¶
app.nodes (a database/collection node + its database_row children), plus
app.collection_props (schema), app.collection_values (cells, jsonb, PK rowId+propId),
app.collection_views (saved views, jsonb config), app.collection_relations (link rows).
Title lives on nodes.title, not in collection_values.
Write path (never raw SQL from client)¶
client → /api/collection/* route handler → lib/mutations.ts → asUser() (RLS) →
Postgres. Same pattern as nodes/blocks. Idempotent: setCellValue upserts on
(rowId, propId) and deletes on empty; setRelation ON CONFLICT DO NOTHING;
ensureCollection seeds Name + a table view only if missing. Verified end-to-end
2026-06-17 (prop add → row add → value set → DB confirm → delete, all 200).
Files delivered¶
lib/prop-types.ts, the Property Type Registry (single source of truth). DefinesPropTypeSpec,PROP_TYPES, theFilterOpvocabulary +matchesFilterevaluator, the per-type config zod schemas + inferred types (PropConfigByType), and the registry-derivedTYPE_LABEL/PROP_GLYPH/TYPE_HINT/ADDABLE_TYPES/COMPUTED_TYPES. Boundary helpersvalidateConfig/validateValue. Pure module; cycle with collection.ts is safe (neither reads the other's bindings at top-level eval, only inside functions).lib/collection.ts, pure engine: PropType/ViewType, option color palette (optionColorhashes a string to one of 8 Notion colors),applyView(hidden/filter/sort, filter now per-type operators viamatchesFilter),evalFormula(guarded Function stub, denylist),rollup,calcColumn(Calculate footer, isEmpty via the registry),formatNumber. The six scattered type constants now re-export registry-derived fromprop-types.ts.lib/data.ts,collectionData(props/views/rows/cells + resolved relation chips + computed rollups & formulas),listDatabases,databaseRows,databaseProps.lib/mutations.ts, addProp/updateProp/deleteProp/reorderProps/duplicateProp, setCellValue, setRelation, createRow/deleteRow, addView/updateView/deleteView, ensureCollection.app/api/collection/*, prop, prop/[id], prop/[id]/duplicate, prop/reorder, value, relation, row, row/[id], view, view/[id], databases, [id]/rows, [id]/props.components/workspace/database/, context.tsx (client store + actions, optimistic + router.refresh reconcile), Cell.tsx (per-type editors), PropertyMenu.tsx (add + column menu + per-type config), FilterSort.tsx, TableView.tsx, Views.tsx (board/gallery/list/ calendar), DatabaseClient.tsx (view tabs + toolbar).components/workspace/DatabasePage.tsx, server loader, flattens Maps to a snapshot.- Tokens in
app/theme.css(8-color option palette--opt-*, db metrics) and CSS inapp/(suite)/workspace.css(.db*).
Property types (14)¶
title, text, number (plain/comma/dollar/percent format), select, multiselect, status,
date, checkbox, url, email, phone, relation (target_db + chips), rollup (count/sum/avg/
min/max over a relation), formula (prop("Name"), arithmetic, round/concat/now/
dateBetween/contains). select/multiselect/status options are stored as plain strings;
chips get a stable hashed color. relation/rollup/formula are computed read-only.
Views (5 native)¶
table (complete: inline edit per type, column resize via header right-edge drag saved to
view.config.widths, column reorder via header drag saved to collection_props positions,
add/hide/duplicate/delete + change-type via column menu, row open /n/[id] + delete, New
page row, Calculate footer), board (group by select/status), gallery (cards), list
(compact), calendar (month grid by a date prop). Filters + sorts are per-view, saved to
collection_views.config; quick search is ephemeral client-side title filter.
Deliberately deferred (with why)¶
- Formula engine is a stub (guarded
new Function+ token denylist), not the full Flask AST whitelist. Owner-only, server-side; safe enough, swap to a real parser later. - Rollups computed server-side; after a relation/rollup change the client calls
router.refresh()to recompute (formulas recompute locally for live typing). - No drag-reorder of ROWS, no group-by on non-select props, no conditional formatting, no per-option manual color override, no timeline/chart/form view layouts (Flask listed them as non-native fallbacks; we render the 5 native and fall back to table).
- Calculate-footer selection is per-session (not persisted to the view config).
Boundaries honored¶
Did not touch finance (Flask app on 127.0.0.1:8096, still 200), clips/media, or the UI
kit components (consumed only). schema.ts ids marked .generatedByDefaultAsIdentity()
to mirror the live sequence so drizzle inserts typecheck (TS-only, no DDL pushed). tsc
clean except the stale Next validator.ts. /kit, /n/136, /, /finances all 200.
[Claude Code]