Skip to content
Project-GraphitePublic

About

A personal workspace: dashboard, agenda, notes, whiteboards, subscriptions and files.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

199 Commits

Folders and files

Repository files navigation

Strata

Strata is a free personal workspace for your dashboard, agenda, notes, whiteboards, subscriptions and files, built by Project Graphite.

Features

  • 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/ui shell, 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.

Stack

  • 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/v1 API, and runs migrations when it starts.

Running it

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 frontend

Checks run from app/:

npm ci && npm run lint && npm test && npm run build

Give 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.com

In 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

Layout

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

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_PASSWORD
  • REDIS_PASSWORD
  • AUTH_ACCESS_TOKEN_SECRET, at least 32 characters
  • DATA_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_HOST and DEFAULT_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).

Conventions

Pull request titles follow type(scope): summary using one of feat fix chore refactor docs test ci perf revert style build.

About

A personal workspace: dashboard, agenda, notes, whiteboards, subscriptions and files.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages