How the fork is published
The three-tier model that lets this repo be an open fork without leaking the proprietary deployment code — and the rules that route every file.
Per-file classification
Every file diverged from upstream baseline b780a4b ("Initial commit")
is listed here with its tier and the rationale for the assignment.
Tiers are defined in README.md:
- A — Upstream PR (zero Azure dependency, becomes upstream code)
- B — Published to AGPL fork (application code, Azure adapters inclusive, but no deployment automation)
- C — Private (deployment IP, marketplace packaging, internal-only scripts and runbooks)
Summary counts
Counting only files actually changed by this fork (not unchanged upstream files):
| Tier | Files | Notes |
|---|---|---|
| A | 5 (refactors only) | Storage interface, auth interface; the change to auth.ts middleware to dispatch on AUTH_PROVIDER. |
| B | ~115 | All the Azure-functional code, all the local-stack docker config, the install configurator route + manifest, the schema migrations, the runtime-config endpoint + ConfigContext from issues 030–032. |
| C | ~40 | Bicep modules, deploy/check/install PowerShell, GitHub-OIDC bootstrap, ACR mirror script, deploy parameter files, internal runbooks, fork-internal issue docs. |
Recent deletions (no longer in any tier — gone from the working tree as of issues 030–032):
frontend/src/lib/auth-provider.ts— replaced byConfigContext.frontend/.env.production— replaced byDockerfilebuild-arg and runtime/config.
Full classification table
The table below lists every diverged file (A = added, M = modified, R = renamed) along with its tier and one-sentence rationale. Files omitted from this table are unchanged from upstream and require no action.
Backend application code
| File | Δ | Tier | Why |
|---|---|---|---|
| backend/src/index.ts | M | B | Adds new routers + static-frontend serving; nothing Azure-specific. The static-frontend block can ship to upstream too if we want — it's just an Express trick that any deployment can use. |
| backend/src/middleware/auth.ts | M | A | Provider dispatch on AUTH_PROVIDER; supabase remains the default. Pure provider boundary, no Azure imports. |
| backend/src/middleware/tenantAccess.ts | A | B | Entra-only tenant lifecycle middleware. Reads principal.tenantId and the tenants table; only runs when AUTH_PROVIDER=entra. |
| backend/src/middleware/requireRole.ts | A | B | Tiny role-guard helper; only used by Entra paths today but provider-neutral in shape. Ship to B; consider a follow-up A PR once role mapping is generalized. |
| backend/src/lib/storage.ts | M | A + B (split) | The StorageProvider interface, R2Provider class, factory and singleton wiring → Tier A. The AzureBlobProvider class and the factory's Azure branch → Tier B. The split is documented in docs/issues/azure-migration/006.1-storage-provider-interface.md. |
| backend/src/lib/supabase.ts | M | B | Adds the entra mode fetch wrapper that strips the /rest/v1 prefix and Authorization header so internal PostgREST works without JWTs. Provider boundary; the supabase function name is now historical. |
| backend/src/lib/userSettings.ts | M | B | Adds Azure OpenAI per-user settings + global-key fallback chain + upsertUserProfile. The shape is provider-neutral but the Azure OpenAI block is the immediate motivator. |
| backend/src/lib/access.ts | M | B | Defensive logging + JSON containment fix for shared_with. Mostly bug-fix-shaped; would be a clean upstream PR but we are not investing in upstreaming it because it doesn't unblock our merge story. |
| backend/src/lib/downloadTokens.ts | M | B | Production-mode hard requirement on DOWNLOAD_SIGNING_SECRET. Generic improvement; could PR upstream if upstream wants it. Not blocking. |
| backend/src/lib/auth/types.ts | A | A | Provider-neutral AuthPrincipal and AuthValidationResult. |
| backend/src/lib/auth/providers/supabase.ts | A | A | Supabase validation extracted from the middleware; behaviour-equivalent. |
| backend/src/lib/auth/providers/entra.ts | A | B | Entra JWT validator with JWKS, issuer/audience/tenant/expiry checks, group extraction. |
| backend/src/lib/auth/providers/local.ts | A | B | Local HS256 JWT validator for the docker-compose dev stack. |
| backend/src/lib/auth/roles.ts | A | B | Maps Entra group OIDs → app roles via ENTRA_ADMIN_GROUP_IDS / ENTRA_MEMBER_GROUP_IDS. |
| backend/src/lib/llm/index.ts | M | B | Adds OpenAI + Azure OpenAI dispatch alongside Claude/Gemini. |
| backend/src/lib/llm/types.ts | M | B | Adds azureOpenai provider type + AzureOpenaiSettings shape. |
| backend/src/lib/llm/models.ts | M | B | Adds OpenAI tier IDs + aoai:<deployment> prefix routing. |
| backend/src/lib/llm/openai.ts | A | B | OpenAI streaming + completion adapter. Could PR upstream as a generic OpenAI adapter (not Azure-specific) — flagged in 02-upstream-prs.md as a possible future PR. |
| backend/src/lib/llm/azureOpenai.ts | A | B | Azure OpenAI adapter (endpoint + apiVersion + deployment). |
| backend/src/lib/llm/azureOpenaiDeployments.ts | A | B | Lists deployments configured against the user's AOAI resource for the model picker. |
| backend/src/lib/config.ts | A | B | Key Vault-backed config reader with env-var override + TTL cache. Azure-specific (uses @azure/keyvault-secrets); the env-override design lets it stay quiet during local dev. |
| backend/src/lib/install/installAuth.ts | A | B | Bootstrap-token + Entra OIDC auth for the /install configurator. |
| backend/src/lib/install/manifest.ts | A | B | Declarative manifest of every config item (anthropic-api-key, kv-mike secret names, etc.). Mike-specific but ships in the published fork — anyone with this code can rebuild it. |
| backend/src/lib/install/types.ts | A | B | Manifest model types. |
| backend/src/routes/auth.ts | A | B | Local-login endpoint + MatterAI-style Entra OpenID provider selection + callback. Issue 030 added GET /auth/logout so the browser bundle no longer constructs the Microsoft logout URL itself. |
| backend/src/routes/install.ts | A | B | The /install configurator's HTML routes + write handlers. Operator scripts the route serves are kept private (Tier C). |
| backend/src/routes/diagnostics.ts | A | B | /admin/diagnostics health-check page. Operator-grade tool, useful in any deployment. |
| backend/src/routes/llm.ts | A | B | /llm/azure-openai/deployments route used by the model picker. |
| backend/src/routes/config.ts | A | B | New (issue 030) — GET /config returns { authProvider, entra: { tenantId, clientId } } from server env / Key Vault. Replaces build-time NEXT_PUBLIC_* baking; the bundle is now tenant-portable. |
| backend/src/routes/chat.ts | M | B | title_model → fast_model rename + cosmetic-failure fallback. Worth upstreaming as a follow-up bug-fix PR. |
| backend/src/routes/projects.ts | M | B | JSONB shared_with containment fix (PostgREST shape) + replaces db.auth.admin.listUsers (Supabase-only) with a user_profiles lookup. |
| backend/src/routes/tabular.ts | M | B | Same shared_with JSONB fix as projects.ts. |
| backend/src/routes/user.ts | M | B | Full /user/profile REST surface (replaces the old single-row upsert) + global-key flags + AOAI settings columns. |
| backend/src/routes/workflows.ts | M | B | Minor adjustments tied to the user-profile shape change. |
| backend/src/routes/documents.ts | M | B | Minor adjustments. |
| backend/src/scripts/runMigrations.ts | A | B | node-pg-migrate runner used by the Container App migrate job. |
Backend infrastructure-of-runtime files
| File | Δ | Tier | Why |
|---|---|---|---|
| backend/.env.example | M | B (sanitized) | Lists AUTH_PROVIDER, all three of supabase/local/entra blocks, Azure storage and AOAI vars, R2 fallback. Sanitize: strip references to internal tenant before publishing — see 05-config-extraction.md. |
| backend/.dockerignore | A | B | Standard; nothing Azure-specific. |
| backend/package.json | M | B | Adds @azure/identity, @azure/keyvault-secrets, @azure/storage-blob, openai, node-pg-migrate, pg, cookie-parser. All published. |
| backend/migrations/0000_initial.sql | R | B | Renamed from 000_one_shot_schema.sql to fit node-pg-migrate's 4-digit numeric ordering, with Supabase-specific items removed (RLS, auth.users FK, handle_new_user trigger). Application-layer change, ships in B. |
| backend/migrations/0001_tenant_policy.sql | A | B | tenants + tenant_group_policies tables for Entra-mode tenant lifecycle. |
| backend/migrations/0002_user_profile_email.sql | A | B | Adds email column to user_profiles. |
| backend/migrations/0003_user_profile_provider_keys.sql | A | B | Adds OpenAI + AOAI per-user key columns. |
| backend/migrations/0004_user_profile_fast_model.sql | A | B | Adds fast_model column. |
| backend/migrations/0005_postgres_roles.sql | A | B | Recreates the PostgREST role topology (web_anon, authenticated, service_role) on Azure Postgres where Supabase's bootstrap doesn't run. |
Frontend application code
| File | Δ | Tier | Why |
|---|---|---|---|
| frontend/src/contexts/AuthContext.tsx | M | B | Provider boundary supports supabase + local + entra. The boundary shape is upstream-PR-eligible; the entra/local branches are fork policy. After issue 030 the provider mode comes from useConfig() (runtime), not module-level env vars; sign-out redirects through GET /auth/logout. |
| frontend/src/contexts/ConfigContext.tsx | A | B | New (issue 030) — ConfigProvider, useConfig(), getCachedAuthProvider(). Fetches /config on mount and caches the resolved provider in localStorage so module-level helpers can answer "what mode are we in?" without a React context. |
| frontend/src/contexts/UserProfileContext.tsx | M | B | Adds AOAI settings + global-key flags + the AOAI deployment cache. |
frontend/src/lib/auth-provider.ts |
deleted | — | Existed pre-030; deleted by issue 030. Module-level isLocalAuth / isEntraAuth / entraConfig reads replaced by useConfig(). |
| frontend/src/lib/auth-token.ts | A | B | Central browser token retrieval helper + bounceIfUnauthorized. Post-030 uses getCachedAuthProvider() and the lazy supabase factory. |
| frontend/src/lib/supabase.ts | M | B | Lazy getSupabaseClient() factory (issue 031). Throws a clear error in non-supabase deployments rather than constructing against placeholder env vars. |
frontend/src/lib/supabase-server.ts, frontend/src/lib/auth.ts |
M | B | Same lazy-factory treatment (issue 031); handle missing supabase env vars gracefully (return null / skip) instead of asserting on placeholder values. |
| frontend/src/components/providers.tsx | M | B | Wraps app shell with ConfigProvider outside AuthProvider so auth bootstrap can read from runtime config. |
| frontend/src/app/lib/mikeApi.ts | M | B | Routes auth header through getBrowserAccessToken instead of supabase session. |
| frontend/src/app/lib/modelAvailability.ts | M | B | OpenAI + AOAI availability flags. |
| frontend/src/app/login/page.tsx | M | B | Adds Microsoft sign-in button + local-login form path. |
| frontend/src/app/signup/page.tsx | M | B | Adapted to the new provider boundary. |
| frontend/src/app/page.tsx | M | B | Provider-aware redirect. |
frontend/src/app/(pages)/account/page.tsx |
M | B | Account page surfaces provider state + new profile fields. |
frontend/src/app/(pages)/account/models/page.tsx |
M | B | Models page surfaces AOAI deployment dropdown + per-provider keys. |
frontend/src/app/(pages)/assistant/chat/[id]/AssistantChatClient.tsx |
A | B | Code-split client extracted from page.tsx; preserves SSR shell for static export. |
frontend/src/app/(pages)/assistant/chat/[id]/page.tsx |
M | B | Becomes the SSR shell that delegates to the client component above. |
frontend/src/app/(pages)/projects/[id]/page.tsx |
M | B | Same SSR-shell pattern. |
frontend/src/app/(pages)/projects/[id]/assistant/chat/[chatId]/page.tsx + ProjectAssistantChatClient.tsx |
M + A | B | Same SSR-shell split. |
frontend/src/app/(pages)/projects/[id]/tabular-reviews/[reviewId]/page.tsx |
M | B | Same. |
frontend/src/app/(pages)/tabular-reviews/[id]/page.tsx |
M | B | Same. |
frontend/src/app/(pages)/workflows/[id]/page.tsx + WorkflowDetailClient.tsx |
M + A | B | Same SSR-shell split. |
frontend/src/app/components/assistant/{AssistantMessage,ChatInput,EditCard,ModelToggle}.tsx |
M | B | Provider-aware tweaks — model picker shows AOAI deployments, etc. |
frontend/src/app/components/shared/{DocPanel,DocxView}.tsx |
M | B | Provider-aware doc fetch + 401 bounce. |
frontend/src/app/components/tabular/{TRChatPanel,TabularReviewView}.tsx |
M | B | Same. |
frontend/src/app/hooks/{useDocumentVersions,useFetchDocxBytes,useFetchSingleDoc}.ts |
M | B | Provider-aware fetch + 401 bounce. |
| frontend/.env.local.example | M | B | Sample env vars. Issue 032 trimmed the file to its current minimal shape: only NEXT_PUBLIC_API_BASE_URL plus the optional supabase pair. |
frontend/.env.production |
deleted | — | Existed pre-032 with real tenant GUIDs and FQDN. Issue 032 deleted the file and the .gitignore whitelist; NEXT_PUBLIC_API_BASE_URL is now a Docker --build-arg and customer-specific values come from /config at runtime. |
Dockerfile |
M | B | Issue 032 added ARG NEXT_PUBLIC_API_BASE_URL= on the frontend-builder stage so the deploy pipeline passes the same-origin / split-origin choice as a build arg. |
.gitignore |
M | B | Issue 032 removed the !frontend/.env.production whitelist; the existing .env.* rule keeps every variant out by default. |
| frontend/next.config.ts | M | B | output: 'export' for the static export bundled into the Container App. |
| frontend/package.json | M | B | Removes resend, bumps AWS SDK. |
Infrastructure-as-code (Bicep)
All files in this section are Tier C — private. They encode our deployment topology, naming conventions, and parameterization choices. Publishing them removes the gap between "fork code" and "deployed service," which destroys the marketplace IP.
| File | Δ | Tier | Why |
|---|---|---|---|
| infra/main.bicep | A | C | Composes every module; reveals our deployment shape. |
| infra/main.parameters.dev.json | A | C | Names acrmike.azurecr.io, our region, our SKUs. |
| infra/main.parameters.prod.json | A | C | Same; tighter SKUs. |
| infra/modules/acr.bicep | A | C | |
| infra/modules/containerapp-backend.bicep | A | C | |
| infra/modules/containerapp-job-migrate.bicep | A | C | |
| infra/modules/containerapp-postgrest.bicep | A | C | The internal-PostgREST trust-model rationale lives here; valuable IP. |
| infra/modules/containerapps-env.bicep | A | C | |
| infra/modules/keyvault-secret.bicep | A | C | |
| infra/modules/keyvault.bicep | A | C | |
| infra/modules/managed-identity.bicep | A | C | |
| infra/modules/network.bicep | A | C | |
| infra/modules/postgres.bicep | A | C | |
| infra/modules/storage.bicep | A | C |
Operator and deployment scripts
| File | Δ | Tier | Why |
|---|---|---|---|
deploy.ps1 |
A | C | The deploy pipeline. Pure deployment IP. |
check-azure.ps1 |
A | C | Read-only health check tied to our resource names. |
| scripts/setup-github-oidc.sh | A | C | Bootstraps the GitHub-Actions federated identity. Internal CI plumbing. |
| scripts/mirror-postgrest.sh | A | C | ACR mirror of upstream PostgREST. Internal supply-chain step. |
| scripts/install/create-entra-apps.ps1 | A | C | Operator script — creates Entra app registrations. The fact that we ship a one-shot creator is part of the marketplace UX IP. |
| scripts/install/register-redirect-uris.ps1 | A | C | Same — operator OIDC convenience. |
| scripts/install/reset-install.ps1 | A | C | |
| scripts/install/revoke-installer-access.ps1 | A | C | |
| scripts/install/setup-aoai.ps1 | A | C | Operator script that provisions or connects an Azure OpenAI resource. |
The /install route in the backend (Tier B) gracefully degrades when
these scripts are absent — see 06-agent-runbook.md for the
"degrade-gracefully" check the agent must add before publishing.
Local-stack scripts (developer machine)
These are shipped in B because they make the published code testable on a developer's laptop without touching Azure.
| File | Δ | Tier | Why |
|---|---|---|---|
| scripts/local-stack/00-init-roles.sql | A | B | PostgREST role topology for local Postgres. |
scripts/local-stack/Caddyfile |
A | B | Local proxy that maps /rest/v1/* → :3000 so the unmodified supabase-js client works. |
| scripts/local-stack/forge-jwt.mjs | A | B | Mints local HS256 service-role JWTs. |
| scripts/dev-infra-check.ps1 | A | B | Smoke-check the local docker stack. |
docker-compose.dev.yml |
A | B | Local Postgres + PostgREST + Caddy + Azurite. |
Dockerfile |
A | B | The bundled-frontend multi-stage build. |
.dockerignore |
A | B |
Documentation
The repo's docs/ tree is mixed. Some docs reveal deployment IP
(Tier C); some are general design context that ships with the fork
(Tier B); some are entirely about local development and obviously
ship.
| File | Tier | Why |
|---|---|---|
| AGENTS.md | B | General agent guidance for the repo. |
| README.md | B (rewrite) | Replace deployment instructions with prereqs prose; see 03-fork-publication.md. |
| docs/fork-delta.md | B | Useful for any forker. |
| docs/local-first-upstream-strategy.md | B | Useful for any forker. |
| docs/runbook-local-stack.md | B | Local dev runbook. |
| docs/runbook-entra-local-auth.md | B | Local Entra runbook. |
| docs/auth-provider-selection-flow.md | B | Generic auth design. |
| docs/agent-handoff.md | B | |
| docs/runbook-dev-deployment.md | C | Names our rg-mike-dev, FQDNs, SKUs. |
| docs/azure-production-hardening.md | C | Production-hardening recipe specific to our deployment. |
| docs/AzureMove/azure-migration-proposal.md | B (sanitized) | Design doc; useful context for the published fork. Sanitize tenant names. |
docs/Postgres/* |
B (sanitized) | Database design docs. |
docs/storage/* |
B | Storage design docs. |
docs/email/* |
B | Email design (not Azure-specific). |
docs/entraId/* |
B (sanitized) | Entra implementation deep-dives. Sanitize. |
| docs/install/scripts.md | C | Documents the scripts that are themselves Tier C. |
docs/infra/* |
C | Bicep-and-deployment-specific. |
docs/issues/azure-migration/* |
mixed | The 006.1, 006.2, 008.0, 017, 020, 021, 022 design docs are Tier B (provider-boundary thinking). The 001–006, 007, 015, 016, 023, 029 docs are Tier C (deployment / install configurator / marketplace IP). The 010–014 + 024–028 docs are mixed — most are Tier B but each one needs a sanitization pass. 06-agent-runbook.md lists the per-file decisions. |
docs/migration/* |
C | This directory itself. Internal planning. |
.claude/ |
C | Internal agent config. Not relevant to the published fork. |
Build artefacts and lockfiles
| File | Δ | Tier | Why |
|---|---|---|---|
backend/package-lock.json |
M | B | Regenerated as part of the squashed PR. |
frontend/package-lock.json |
M | B | Same. |
| backend/bun.lock, frontend/bun.lock | unchanged | B | Already upstream-shape. |
.gitignore |
M | B | Adds .claude/. Sanitize: keep .claude/ in .gitignore if we're not publishing it. |
Notes on classification edge cases
backend/src/index.ts static-frontend serving. The
findShell() + SPA-fallback machinery is generic Express + Next.js
static-export glue and could go upstream as a contribution. We have
chosen to ship it in Tier B for now and revisit upstreaming after the
public fork is published.
backend/src/lib/access.ts JSONB containment fix. This is a genuine upstream bug — the shipped behaviour throws on Postgres JSONB columns when the user has shared projects. It would make a clean A-tier PR. We have chosen to ship it in Tier B because the provider-boundary PRs are higher-value upstream contributions and we don't want to multiply review surface.
backend/src/lib/llm/openai.ts plain OpenAI adapter. Not Azure- specific; could go upstream. Deferred to a future PR.
Frontend AuthContext.tsx provider abstraction. The shape is
generic but the implementation interleaves all three providers in one
file. Splitting it cleanly enough for an upstream PR would be a real
refactor. Deferred.
Documentation sanitization. Several B-tier docs reference our
internal tenant GUIDs, FQDNs, or resource names. The agent runbook
includes a regex pass that the publication script must run before
pushing to the public fork — see 05-config-extraction.md.