Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

587 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Manut

Employee operations platform — one universal codebase, edge-first delivery.

PR Checks TypeScript Cloudflare Workers License

Manut is a clean-room employee operations platform. A single Expo Router route tree ships the same screens, domain services, authentication decisions, and route policies to web today and iOS/Android later — no second frontend rewrite. The public boundary is a Cloudflare Worker that serves the SPA, enforces security headers, and fails closed on any missing capability.

Highlights

  • Universal frontend — one Expo codebase for web, iOS, and Android; platform differences live in small .web.ts / .native.ts adapters.
  • Fail-closed edge — missing auth, API origin, Hyperdrive, Queue, Workflow, Container, or storage capability returns an explicit 503; no silent fallbacks, no direct secret URLs.
  • Server-side authorization — API permission and ownership checks stay authoritative even when a route is guarded in the client; sidebar visibility is never authorization.
  • Idempotent async jobs — Cloudflare Queues with a Durable Object ledger (once-only claims), permanent-failure dead-lettering, and bounded retries.
  • Realtime at the edge — Durable Object hibernating WebSockets own reconnectable room state.
  • Strangler Postgres SoR — Prisma 7 over Cloudflare Hyperdrive with one immutable migration baseline (until master-plan Phase 8+ D1-per-tenant gates); every new migration must pass deploy, direct replay, and double db push convergence on PostgreSQL 16. See docs/EXPO_CLOUDFLARE_MASTER_PLAN.md and docs/ADR-010-postgres-strangler-vs-d1-target.md.
  • Self-provisioning deploys — queues and R2 buckets named in wrangler.jsonc are created idempotently at deploy time; resource names have a single source of truth.

Architecture

flowchart LR
  Client["Expo universal app<br/>web · iOS · Android"] --> Edge["Cloudflare Worker<br/>security headers · rate limits"]
  Edge --> Assets["Static Assets<br/>Expo web export"]
  Edge --> DO["Durable Objects<br/>realtime rooms · queue ledger"]
  Edge --> Q["Queues + DLQ<br/>idempotent jobs"]
  Edge --> R2[("R2 uploads")]
  Edge --> API["Business API"]
  API --> PG[("PostgreSQL<br/>Prisma 7 · Hyperdrive")]
Loading
Layer Responsibility Direction
apps/app Expo Router universal web/native shell Primary frontend
packages/app-core Platform-neutral auth, API, and RBAC contracts Shared by web, Android, and iOS
packages/ui Universal React Native tokens and components Shared by web, Android, and iOS
apps/edge Cloudflare Worker, static assets, security headers, API gateway Public request boundary
apps/api Strict TypeScript business API Runs behind the gateway; Node-only work moves to a Cloudflare Container
apps/web Next.js route-parity reference Retired route-by-route after Expo acceptance
packages/database Prisma schema and immutable migration baseline Postgres through Cloudflare Hyperdrive

Cloudflare R2 is the file-storage target, Durable Objects own reconnectable state, and Queues/Workflows own asynchronous jobs. D1 may hold edge-local coordination data only — PostgreSQL remains the authoritative business database.

Getting started

corepack enable
pnpm install --frozen-lockfile
cp .env.example .env
pnpm db:generate
pnpm dev

Focused commands:

pnpm dev:app          # Expo universal app
pnpm dev:api          # business API
pnpm dev:edge         # Cloudflare gateway
pnpm --filter @manut/app export:web
pnpm --filter @manut/app export:ios
pnpm --filter @manut/app export:android

Quality gates

Every pull request must pass the aggregated Validate check: generated database types, strict API and root TypeScript, zero-warning lint, unit tests, Expo web and native exports, Worker tests and build, web bundle limits, PostgreSQL 16 migration safety, credential/Gitleaks scans, and serialized authenticated Playwright E2E against the dedicated project. any, ts-ignore, blanket non-null assertions, and conditional E2E skips are rejected.

Deployment

Each branch has one deploy owner. GitHub deploys fail closed without their Environment secrets:

Branch Deploy owner Target
main Cloudflare Workers Builds service manut (production)
preview GitHub Actions Worker manut-preview
staging GitHub Actions Worker manut-staging

Cloudflare Workers Builds is the sole production deploy path and runs pnpm run build:cloudflare from the dashboard. After validating a replacement build token with a full deploy to the isolated manut-preview Worker, disable native non-production Workers Builds so GitHub Actions remains the only preview/staging owner. Before every wrangler invocation, apps/edge/scripts/ensure-cloudflare-resources.mjs idempotently creates the queues and R2 buckets named in wrangler.jsonc. No deploy path mutates DNS or invents Hyperdrive ids, and this ownership split does not authorize DNS changes. hyperdrive: [] stays empty until ops binds a real config. Cloudflare Pages auto-deploy remains off. See CI/CD Cloudflare and production deploy readiness.

Security model

  • Web sessions use secure HTTP-only cookies; native uses PKCE bearer sessions in SecureStore — both resolve the same server-side user, roles, and permissions.
  • Authenticated state clears only on 401/403; warm state survives network and rate-limit failures.
  • Uploads go through R2 with server-owned keys; receipt provenance is restricted to trusted storage origins.
  • Credential scanning gates every artifact before deploy.

See the credential boundary and authentication and RBAC.

Documentation

Topic Doc
Canonical handoff docs/CURSOR_HANDOFF.md
Cloudflare bindings docs/CLOUDFLARE_BINDINGS.md
CI/CD on Cloudflare docs/CICD_CLOUDFLARE.md
Production readiness docs/PRODUCTION_DEPLOY.md
Auth and RBAC docs/AUTH_RBAC.md
Repository migration docs/REPOSITORY_MIGRATION.md
Dependency upgrade scope docs/DEPENDENCY_UPGRADE_SCOPE.md

License

Proprietary. All rights reserved. This repository is source-visible for collaboration and review; no license is granted for reuse or redistribution.

About

Clean-room employee operations platform — one Expo Router codebase for web, iOS, and Android, served from a fail-closed Cloudflare Workers edge with Postgres (Prisma + Hyperdrive), R2, Queues, and Durable Objects.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages