Skip to content

Commit 0dbee6a

Browse files
committed
refactor(web): full frontend architecture overhaul
Tooling: - eslint flat config + biome update - yarn .yarnrc + sdks for editor support - package.json + yarn.lock dependency bumps - tsconfig, vite, vitest, openapi-ts config refresh - mise: add lint:web:query task (TanStack Query lint) - .gitattributes: mark routeTree.gen.ts and api-generated/ as linguist-generated Generated SDK: - Move api/generated -> api-generated - Add @tanstack/react-query.gen.ts (query/mutation hooks) - Add zod.gen.ts (runtime schema validation) Shared platform foundation: - shared/platform/api: configureApiClient, query client factory, ApiError - shared/platform/auth: current/anonymous user, reauth flow, session watcher - shared/platform/telemetry: AppInsights/console/noop backends + error boundary - shared/platform/{theme,toast,feature-flags,access-control} - shared/components: EmptyState, ErrorPanel, IconButton, LoadingState, PageHeader, Popover - config/: env, accessControl, featureFlags - mocks/: MSW server + handlers - setupTests.ts updated App shell + Todos cutover: - app/bootstrap: Providers, ApplicationError, createQueryClient - app/error-pages: Forbidden/NotFound/StatusPage/RouteErrorBoundary/UnexpectedError - app/layout: RootLayout, Header, VersionText - app/routes + routeTree.gen.ts (TanStack Router) - app/styles, app/auth/SessionExpiredDialog - features/todos: api (queries/mutations/keys/invalidations/schema), pages/TodosPage with NewTodoForm, TodoItem, TodoList, TodosFilter - index.tsx + index.html: new bootstrap - Removed legacy: App.tsx, router.tsx, auth.ts, common/components/*, contexts/TodoContext, hooks/useTodoAPI, pages/TodoListPage, features/todos/todo-list/*
1 parent aab3abb commit 0dbee6a

182 files changed

Lines changed: 7935 additions & 1238 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,9 @@
1111
# Ignore massive diffs each time you add/update yarn plugins
1212
/web/.yarn/releases/** binary
1313
/web/.yarn/plugins/** binary
14+
15+
# Generated files — hide from GitHub diffs/language stats and mark as not
16+
# hand-edited. The TanStack Router Vite plugin owns routeTree.gen.ts;
17+
# `@hey-api/openapi-ts` owns api-generated/.
18+
/web/src/app/routeTree.gen.ts linguist-generated=true
19+
/web/src/api-generated/** linguist-generated=true

.mise/tasks/lint.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,17 @@ depends = ["install-dependencies:web"]
1515
dir = "{{config_root}}/web"
1616
run = "yarn compile"
1717

18+
["lint:web:query"]
19+
description = "Lint TanStack Query usage in the Web application"
20+
depends = ["install-dependencies:web"]
21+
dir = "{{config_root}}/web"
22+
run = "yarn lint:query"
23+
1824
["lint:web"]
1925
description = "Lint the Web application"
2026
run = [
2127
"mise run lint:web:typecheck",
28+
"mise run lint:web:query",
2229
]
2330

2431
[lint]

biome.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
{
2-
"$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
2+
"$schema": "https://biomejs.dev/schemas/2.4.14/schema.json",
33
"files": {
4-
"includes": ["web/**", "!web/build", "!web/src/api/generated"]
4+
"includes": [
5+
"web/**",
6+
"!web/build",
7+
"!web/.yarn",
8+
"!web/.pnp.*",
9+
"!web/src/api-generated",
10+
"!web/src/app/routeTree.gen.ts"
11+
]
512
},
613
"javascript": {
714
"formatter": {
@@ -19,6 +26,11 @@
1926
"indentWidth": 2
2027
}
2128
},
29+
"css": {
30+
"parser": {
31+
"tailwindDirectives": true
32+
}
33+
},
2234
"linter": {
2335
"rules": {
2436
"a11y": {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env node
2+
3+
const {existsSync} = require(`fs`);
4+
const {createRequire, register} = require(`module`);
5+
const {resolve} = require(`path`);
6+
const {pathToFileURL} = require(`url`);
7+
8+
const relPnpApiPath = "../../../../.pnp.cjs";
9+
10+
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
11+
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
12+
const absRequire = createRequire(absPnpApiPath);
13+
14+
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
15+
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
16+
17+
if (existsSync(absPnpApiPath)) {
18+
if (!process.versions.pnp) {
19+
// Setup the environment to be able to require eslint/bin/eslint.js
20+
require(absPnpApiPath).setup();
21+
if (isPnpLoaderEnabled && register) {
22+
register(pathToFileURL(absPnpLoaderPath));
23+
}
24+
}
25+
}
26+
27+
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
28+
? exports => absRequire(absUserWrapperPath)(exports)
29+
: exports => exports;
30+
31+
// Defer to the real eslint/bin/eslint.js your application uses
32+
module.exports = wrapWithUserWrapper(absRequire(`eslint/bin/eslint.js`));

web/.yarn/sdks/eslint/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "eslint",
3+
"version": "10.3.0-sdk",
4+
"main": "./lib/api.js",
5+
"type": "commonjs",
6+
"bin": {
7+
"eslint": "./bin/eslint.js"
8+
},
9+
"exports": {
10+
".": {
11+
"types": "./lib/types/index.d.ts",
12+
"default": "./lib/api.js"
13+
},
14+
"./config": {
15+
"types": "./lib/types/config-api.d.ts",
16+
"default": "./lib/config-api.js"
17+
},
18+
"./package.json": "./package.json",
19+
"./use-at-your-own-risk": {
20+
"types": "./lib/types/use-at-your-own-risk.d.ts",
21+
"default": "./lib/unsupported-api.js"
22+
},
23+
"./rules": {
24+
"types": "./lib/types/rules.d.ts"
25+
},
26+
"./universal": {
27+
"types": "./lib/types/universal.d.ts",
28+
"default": "./lib/universal.js"
29+
}
30+
}
31+
}

web/.yarn/sdks/integrations.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# This file is automatically generated by @yarnpkg/sdks.
2+
# Manual changes might be lost!
3+
4+
integrations:
5+
- vscode

web/.yarn/sdks/typescript/bin/tsc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env node
2+
3+
const {existsSync} = require(`fs`);
4+
const {createRequire, register} = require(`module`);
5+
const {resolve} = require(`path`);
6+
const {pathToFileURL} = require(`url`);
7+
8+
const relPnpApiPath = "../../../../.pnp.cjs";
9+
10+
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
11+
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
12+
const absRequire = createRequire(absPnpApiPath);
13+
14+
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
15+
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
16+
17+
if (existsSync(absPnpApiPath)) {
18+
if (!process.versions.pnp) {
19+
// Setup the environment to be able to require typescript/bin/tsc
20+
require(absPnpApiPath).setup();
21+
if (isPnpLoaderEnabled && register) {
22+
register(pathToFileURL(absPnpLoaderPath));
23+
}
24+
}
25+
}
26+
27+
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
28+
? exports => absRequire(absUserWrapperPath)(exports)
29+
: exports => exports;
30+
31+
// Defer to the real typescript/bin/tsc your application uses
32+
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsc`));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env node
2+
3+
const {existsSync} = require(`fs`);
4+
const {createRequire, register} = require(`module`);
5+
const {resolve} = require(`path`);
6+
const {pathToFileURL} = require(`url`);
7+
8+
const relPnpApiPath = "../../../../.pnp.cjs";
9+
10+
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
11+
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
12+
const absRequire = createRequire(absPnpApiPath);
13+
14+
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
15+
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
16+
17+
if (existsSync(absPnpApiPath)) {
18+
if (!process.versions.pnp) {
19+
// Setup the environment to be able to require typescript/bin/tsserver
20+
require(absPnpApiPath).setup();
21+
if (isPnpLoaderEnabled && register) {
22+
register(pathToFileURL(absPnpLoaderPath));
23+
}
24+
}
25+
}
26+
27+
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
28+
? exports => absRequire(absUserWrapperPath)(exports)
29+
: exports => exports;
30+
31+
// Defer to the real typescript/bin/tsserver your application uses
32+
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsserver`));
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "typescript",
3+
"version": "6.0.3-sdk",
4+
"main": "./lib/typescript.js",
5+
"type": "commonjs",
6+
"bin": {
7+
"tsc": "./bin/tsc",
8+
"tsserver": "./bin/tsserver"
9+
}
10+
}

web/.yarnrc.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
nodeLinker: pnp
21
enableGlobalCache: true
2+
3+
nodeLinker: pnp

0 commit comments

Comments
 (0)