Strata is a free personal workspace for your dashboard, agenda, notes, whiteboards, subscriptions and files, built by Project Graphite.
-
Home: dashboards of widgets (agenda, tasks, pages, weather, news feeds, countdown, focus timer, app status and more), picked by time of day and device, and a wall display.
-
Tasks: task lists with repeating tasks, assignment and reminders, a quick-add box that reads dates, tags and priority, and the Today and To-do pages. Ticking off a task can be undone.
-
Agenda: events with guest RSVPs and date polls, followed outside calendars and a private calendar link.
-
Pages: notes with live co-editing, offline drafts, version history, templates, mentions, comments and database views. Pages and boards can be moved to the trash.
-
Boards: whiteboards drawn with Excalidraw, with templates and dot votes, embeddable in pages and events and editable by guests through a share link.
-
Bookmarks: saved links with a read-later list and a reader view.
-
Journal: a daily journal with a mood, and a one-click weekly review page.
-
Recurring: subscriptions with renewals, price history, reminders, home-currency totals at ECB rates, bank statement suggestions and shared splits; habits with check-ins and streaks.
-
Spending: accounts and cards, budgets, installment plans, insights, net worth with assets and savings goals, bank texts to review, and statement import and CSV export.
-
Files: uploads, previews and downloads, with metadata stripped.
-
Spaces: shared spaces with members, invitations, tags, share links, activity and trash.
-
Trash and undo: anything moved to the trash can be undone from the notice that follows, and restored from the Trash for 30 days.
-
Confirmations: deleting for good, discarding edits and cutting off someone's access ask first. One-time secrets, such as tokens and recovery codes, stay on screen until you confirm you saved them.
-
Optional features, turned on in Settings: Goals, People, Recipes and meals, Tidy and Trips. Tidy suggests stale items to clear, with bulk actions, undo and tagging rules.
-
Inbox: notices in the app and as push notifications to chosen devices.
-
Search and a command palette, an installable app, personal access tokens and webhooks.
-
Accounts:
- registration with email verification and resendable links;
- sign-in with rotating refresh sessions and reuse detection, rate-limited per session, so people sharing a network address don't lock each other out;
- password reset by email.
Registration never reveals whether an email address already has an account. The owner gets a notice instead. Failed sign-ins take the same time whether or not the account exists.
-
Two-step sign-in:
- authenticator-app codes (TOTP), set up from a QR code;
- ten recovery codes, each usable once and stored only as hashes;
- sign-in asks for a code after the password, with five attempts per sign-in;
- each code works only once.
-
Sensitive changes need your password and, with two-step sign-in on, a code. That covers the password, email, two-step settings and account deletion.
-
Devices and sessions:
- every signed-in device is listed, and any or all of them can be signed out;
- a signed-out device stops working straight away;
- a sign-in from a new device sends an email.
-
Security emails: new-device sign-ins, password changes and two-step changes.
-
Passwords: passwords found in data breaches are refused. The check sends only the first five characters of the password's SHA-1 hash to Have I Been Pwned.
-
Encryption: authenticator secrets are stored encrypted with AES-256-GCM, under a key that lives outside the database.
-
Settings: profile and time zone, email change, password, two-step sign-in, devices, data export and account deletion.
-
Security:
- a strict content security policy and isolation headers on every response;
- settings checked at start-up, so a missing secret stops the server instead of failing later;
- a request log with no query strings, bodies or email addresses;
- errors that never expose internals;
- scrypt password hashes that store their own cost settings.
-
Layout: the shared
@project-graphite/uishell, with a sidebar on desktop and a tab bar on phones, and browser tabs named after the page. -
Errors say what went wrong and what to do next: inline on forms, with Try again on anything that failed to load, and in plain words when a followed calendar can't be read.
-
Privacy and terms pages.
- React 19, Vite, Tailwind CSS 4 and
@project-graphite/ui. - NestJS 12, Prisma 7 and PostgreSQL 18.
- Redis 8 for rate limits, widget caching and the health check.
- One container serves the built frontend and the
/api/v1API, and runs migrations when it starts.
docker compose up -d --build| Address | What it is |
|---|---|
| http://localhost:4104 | the app, through Vite |
| http://localhost:4102 | the server directly |
| http://localhost:4125 | Mailpit, which catches every email sent locally |
Vite does not see edits through a Windows bind mount, so restart the container after editing:
docker compose restart app frontendChecks run from app/:
npm ci && npm run lint && npm test && npm run buildGive an account the system manager role from inside the running container. Add --transfer to
hand the role over:
docker compose exec app npm run system-manager:grant --workspace server -- you@example.comIn production, open the app container's Terminal in the
Graphite Console, or docker exec into it on the VPS, and run:
npm run system-manager:grant --workspace server -- you@example.com| Folder | What it is |
|---|---|
app/server |
NestJS API, Prisma schema and hand-written migrations |
app/frontend |
React app |
app/Dockerfile |
development, build and production stages; the image is ghcr.io/project-graphite/strata/app |
Production runs at strata.project-graphite.com from
deploy/strata/values.yaml in platform. A push to main records the
image tag there, which deploys it. Uploaded files live in the files-data volume at /data/files
(FILES_ROOT, default /data/files). The backup service writes a pg_dump and a tar of the files
into the backups volume once a day and keeps BACKUP_KEEP_DAYS days of them.
These values live only in the organisation's secrets repository:
POSTGRES_PASSWORDREDIS_PASSWORDAUTH_ACCESS_TOKEN_SECRET, at least 32 charactersDATA_ENCRYPTION_KEY, 32 random bytes in base64 (openssl rand -base64 32). Never change it without re-encrypting the stored secrets, or every two-step sign-in breaks.EMAIL_HOSTandDEFAULT_FROM_EMAIL
Optional: EMAIL_PORT (default 587), EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, VAPID_PUBLIC_KEY,
VAPID_PRIVATE_KEY, VAPID_SUBJECT and BACKUP_KEEP_DAYS (default 14).
Pull request titles follow type(scope): summary using one of feat fix chore refactor docs test ci perf revert style build.