Repository navigation
feat(web): bootstrap web client scaffolding and design system - #1
Conversation
There was a problem hiding this comment.
Review — PR #1: Web client scaffolding and design system
Hi 👋 Thanks for the work. The foundation is solid, and I verified locally that the current branch installs and builds (npm ci, npm run build:web, tsc --noEmit) and that the documentation checks pass. The PR is not ready to merge yet: the Bun migration below is required, and the remaining issues are fixable. I have grouped them into: required decisions, required changes, code fixes, and follow-ups.
Before anything else, please rebase — the branch is one commit behind main (the Elixir/PostgreSQL scaffold), and that commit adds documentation files this PR must update.
git remote add upstream https://github.com/DevHustlers-Community/ASN.git
git fetch upstream
git rebase upstream/main
git push --force-with-lease origin feature/web-client-scaffolding-and-design-systemAfter rebasing, run:
bun install --frozen-lockfile
bun run typecheck
bun run build:web
python3 scripts/ci/check-changelog.py --all
python3 scripts/ci/check-links.pyThe GitHub Actions run for this PR is currently action_required because it comes from a fork. Ask a maintainer to approve the workflow after the rebase.
1) Required: standardize the TypeScript toolchain on Bun
Maintainer decision: this repository uses Bun for all TypeScript tooling, including apps/web. This is not a preference for this PR only; it removes the npm/Bun split and makes the repository consistent with the Bun direction already documented for the TypeScript services.
Please migrate this PR from npm to Bun before merge:
1.1 Remove the npm lockfile and generate the Bun lockfile
At the repository root:
rm -rf node_modules package-lock.json
bun installCommit the generated Bun lockfile (bun.lock with current Bun; do not commit both bun.lock and bun.lockb). Do not commit node_modules.
Why: two lockfiles for the same workspace cause non-reproducible installs and CI drift. package-lock.json must not remain.
1.2 Pin the Bun version in one place and reuse it everywhere
Add the same exact version to:
-
.tool-versions(somise installinstalls it):bun <pinned-version> -
root
package.json:{ "packageManager": "bun@<pinned-version>" } -
the CI workflow (
oven-sh/setup-bun), shown below.
Replace <pinned-version> with the current stable Bun version you standardize on. Do not leave it floating.
1.3 Update the workspace dependency
In apps/web/package.json, replace:
"@asn/config-typescript": "file:../../packages/config-typescript"with:
"@asn/config-typescript": "workspace:*"Why: workspace:* tells Bun to link the local workspace package, makes the relationship explicit, and avoids accidentally installing a nested copy.
1.4 Update root scripts to Bun
The current root scripts invoke npm. Replace them with Bun workspace filters:
{
"packageManager": "bun@<pinned-version>",
"scripts": {
"dev": "bun run --filter '@asn/web' dev",
"dev:web": "bun run --filter '@asn/web' dev",
"build": "bun run --filter '@asn/web' build",
"build:web": "bun run --filter '@asn/web' build",
"typecheck": "bun run --filter '@asn/web' typecheck",
"lint": "bun run --filter '@asn/web' lint",
"test": "bun run --filter '@asn/web' test"
}
}Add the matching scripts to apps/web/package.json:
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"test": "vitest run"
}
}If you prefer Bun's own test runner, use bun test with happy-dom instead of Vitest. Either is acceptable, but pick one, document it, and make CI run it through Bun.
1.5 Update CI to Bun
Add a web workflow (or extend the existing workflow) using the same pinned Bun version:
name: Web
on:
pull_request:
jobs:
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: <pinned-version>
- run: bun install --frozen-lockfile
- run: bun run typecheck
- run: bun run lint
- run: bun run test
- run: bun run build:web--frozen-lockfile is important: it fails if bun.lock is out of sync with package.json, instead of silently changing dependency resolution in CI.
1.6 Remove every npm reference
Update all of these from npm to Bun:
apps/web/README.md—bun install,bun run dev,bun run build.AGENTS.md§7 — the JS/TS verification row must usebun installandbun run typecheck|lint|test.docs/development/getting-started.md— add Bun to prerequisites and use Bun commands for the web app.docs/development/local-environment.md— add the Bun version to the versions table.docs/changelog/2026-10-24-web-scaffolding-and-design-system.md— replacenpm install/npm run build:webwith the Bun commands actually run.- The PR body — same.
Verify the migration with:
grep -rn "npm\|package-lock" --include='*.md' --include='*.json' --include='*.yml' . | grep -v node_modulesThe only acceptable matches are historical changelog entries or unrelated text; there should be no active npm command or package-lock.json reference.
1.7 Verify Bun actually runs the build
Do not assume Vite works under Bun just because the package manager changed. Run:
rm -rf node_modules
bun install --frozen-lockfile
bun run build:web
bun run dev # check that the Vite dev server starts on port 3000If a script still resolves to a Node shebang, force Bun with bun --bun run <script> (or bunx --bun) and document that in the README. The goal is that a clean clone needs Bun, not Node.
2) Decisions that need an explicit owner ruling
2.1 The name “Tawasol / تواصل”
docs/GLOSSARY.md contains an explicit rule:
Product name: ASN (Arabian Social Network). No alternate product name is used in code, docs, UI, or file names.
The new name appears in:
apps/web/index.html(title and description)apps/web/src/app/App.tsxapps/web/README.mddocs/changelog/2026-10-24-web-scaffolding-and-design-system.mddocs/architecture/design-system.md
There are two valid paths, but this needs an owner decision before implementation:
- Recommended for this PR: use ASN everywhere in the files above, and treat “Tawasol” as a separate proposal.
- If the name is intentional: add an ADR, update
docs/GLOSSARY.md, and document ownership/licensing of the name and logo. The changelog currently calls the logo “provisional”; a provisional asset must not become the product name in the UI and documentation.
2.2 The design-system document says “Approved” without approval
docs/architecture/design-system.md declares Status: Approved, but this PR has not been approved and has no ADR. docs/decisions/README.md says every significant, hard-to-reverse decision gets a numbered ADR. The document itself makes hard-to-reverse decisions: theme axes, token names, fonts, RTL rules, spacing, and accessibility standards.
Please:
- change the status to
Proposeduntil it is reviewed, and add an owner and date; - add an ADR (for example,
0012-frontend-design-system-and-theming.md) with context, decision, consequences, and alternatives; - link the document from
docs/architecture/README.md(table and reading order) and from the ADR. Right now the document is orphaned: searching fordesign-systemonly finds the changelog line; - note that
docs/architecture/README.mdsays the folder describes the current design, while this document is a target specification. Either label it explicitly as target design or move it somewhere more appropriate.
2.3 Web E2EE and auth decisions are being made implicitly
apps/web/README.mdandfeatures/chat/README.mdclaim E2EE for the web client, but ADR 0010 (Web E2EE parity policy) is still open indocs/decisions/README.md.features/auth/README.mdspecifies a token strategy (access tokens in memory, refresh tokens in HttpOnly cookies, PKCE), whilearchitecture-and-schema.md§9 lists token/session strategy as an open decision.
Please either remove these specifics or label them as proposed and blocked on the relevant ADR. Do not let a documentation PR resolve a security-sensitive open decision silently. The same applies to “private keys live in secure storage” on the web: client storage is not decided yet.
3) Update the source-of-truth documentation
docs/README.md says:
No stale stack assumptions. When the stack changes, every affected document is updated or explicitly marked superseded.
After the rebase, these files will be wrong:
3.1 AGENTS.md
- §1: “There are no … TypeScript manifests yet” — no longer true.
apps/web/package.json, the Bun lockfile, andpackages/config-typescriptnow exist. - §7: the JS/TS row must reflect the actual Bun commands and include the web app’s typecheck/build.
- Check any other statement that assumes web is not scaffolded.
3.2 docs/development/getting-started.md
-
“Social, Moderation, web, admin, and mobile have no manifests yet” — web now has one.
-
“Bun | not required yet” — no longer true.
-
Add the web app to the run instructions:
bun install bun run dev:web
-
Update “What works today” and “What does not work yet”.
3.3 docs/development/local-environment.md
- Port
3000: “Reserved; no manifest” → “Vite dev server (apps/web)”. - Add Bun to the versions table, sourced from
.tool-versions. - Keep the port number consistent with
apps/web/vite.config.ts(currently 3000, which is correct).
3.4 packages/config-typescript
README.mdstill saysStatus: not written yet, and listsbun.jsonandreact-native.jsonthat do not exist.package.jsonlistsbun.jsoninfiles, but the file is missing.- Either add the preset or remove it from
filesand document it as planned. If Bun is now the runtime, abun.jsonpreset is a reasonable addition, but do not reference a file that does not exist. - Document that
base.jsonandreact.jsonare now present and used byapps/web.
3.5 apps/web/README.md
The previous version had Owns, Boundaries, Tests, and Status, which AGENTS.md §8 requires for an app README. The new version removed them. Restore them, for example:
**Owns:** browser UI state and non-sensitive client cache only.
**Boundaries:**
- Consumes REST under `/api/v1/` and the Chat WebSocket channel.
- Does not read another service's database, hold service credentials, or decide
visibility/authorization on its own.
- Chat envelopes are opaque handles; the browser never sends plaintext message
bodies to Chat.
**Tests:** unit and component tests next to the feature; end-to-end flows live in
`tests/end-to-end`.
**Status:** scaffolded; no product routes or API integration yet.The directory layout currently presents lib/api/, lib/websocket/, lib/auth/, Dialog, and Tabs as if there were implemented. Split the layout into Current and Planned, and do not write “built with” for anything that is not implemented.
3.6 Feature and utility READMEs
The thirteen feature READMEs describe complete features that do not exist, and some resolve open decisions:
- Add
**Status:** planned — no implementation yet.to every feature README. features/auth/README.md:react-hook-formandzodare not installed. Either add them or mark the forms as planned.features/settings/README.md: “Who can message you — Everyone / Followers / Nobody” does not matchchat_privacy_settings.allow_non_friend_messages, which is a boolean. Align with the schema or leave the product rule undecided.features/chat/README.mdand the design document:chat_db.streaksis friendship-based in the architecture, not community streaks. Correct the attribution.app/README.md: the route list (/c/:slug,/u/:username, etc.) is a product proposal, not an existing contract. Mark it as proposed or remove it until the contracts exist.hooks/README.mdandlib/README.md: list only what exists (cn), and mark the rest as planned.ChatBubblereceipts: align witharchitecture-and-schema.md§3.11. Large channels use per-conversationlast_read_seq; per-message receipts are reserved for direct chats or features that need them.
3.7 Design-system document consistency
Please fix these internal contradictions:
tokens.cssdoes not implement the documented light/dark status values. Add the light-theme overrides and use#ef4444for destructive in dark mode, as documented.- The document references
--elevation-*, buttokens.cssuses--bg-*. Rename one side. - The scope lists
packages/tokens, which does not exist. Remove it or add the package. - The document says arbitrary values are rejected by CI, but there is no such lint, and the code contains
text-[11px]. - The document claims a strict 4px grid, but the code uses 6px and 10px values (
gap-1.5,px-2.5,w-2.5,w-3.5). Either allow half-steps and document them, or use the nearest 4px multiple. - The document claims a 12px minimum font size, but
input.tsxuses 11px.
4) Code fixes
4.1 Tailwind drops opacity modifiers on token colors
Utilities such as bg-primary/10, bg-status-success/10, and border-status-success/30 are not generated in the final CSS. I verified this in dist/assets/*.css: there is no primary\/10, status-success\/10, or primary\/30, while bg-white/90 works because it is a literal color.
As a result, the default Badge loses its background tint, the success box loses its tint, and the intended borders are missing.
Choose one fix:
Option A — explicit tint tokens (smaller change):
:root {
--primary-surface: rgba(16, 185, 129, 0.10);
--primary-border: rgba(16, 185, 129, 0.30);
--status-success-surface: rgba(16, 185, 129, 0.10);
--status-success-border: rgba(16, 185, 129, 0.30);
}primary: {
DEFAULT: 'var(--primary)',
surface: 'var(--primary-surface)',
border: 'var(--primary-border)',
}Then use bg-primary-surface and border-primary-border instead of /10 and /30.
Option B — RGB channels (better long-term):
:root {
--primary: 16 185 129;
}primary: {
DEFAULT: 'rgb(var(--primary) / <alpha-value>)',
}This requires converting all tokens and theme overrides to RGB triplets. If that is too large for this PR, do Option A now and record Option B as a follow-up.
Verify after building:
bun run build:web
grep -F 'bg-primary\/10' apps/web/dist/assets/*.css4.2 Accessibility: the claims do not match the implementation
The design document claims WCAG 2.1 AA, but:
- White on accent colors: emerald 2.54, amber 2.15, cyan 2.43, crimson 3.67, indigo 4.47 — all below 4.5 for 12–14px button text.
--text-dimon cards is 3.87, and 4.35 on OLED.--status-destructiveon cards is 3.87.text-[11px]ininput.tsxviolates the document’s own 12px floor.- Presence and accent selection rely on color alone; there is no
aria-pressed, andaria-labelis attached to a plain<span>. - The demo label is not associated with its input (
htmlFor).
Please:
- add
--primary-foregroundper accent and usetext-primary-foregroundinstead oftext-white; verify every combination reaches 4.5:1 (use dark text on amber/cyan/emerald/crimson, and either dark text or a darker indigo); - raise
--text-dimin dark themes (for example,#9ca3af) until it reaches 4.5:1; - use
#ef4444for destructive status in dark mode; - replace
text-[11px]withtext-xs; - add
aria-pressedand accessible labels to the theme/accent buttons, plus a visible focus ring; - add a hidden text label or icon for presence, and a proper role;
- use
useIdandhtmlForinInput/demo forms; - add
eslint-plugin-jsx-a11ythrough@asn/config-eslint.
4.3 Tests, lint, and CI
Currently there are no tests, lint is just tsc --noEmit, and there is no web CI job.
Add:
- a real
typecheckscript; - ESLint and Prettier using
@asn/config-eslintand@asn/config-formatting(currently README stubs); - unit/component tests for
cn, Button variants andisLoading, theme switching ondocument.documentElement, and Badge variants; - the Bun CI workflow from section 1.5.
Do not add plaintext chat fixtures; the E2EE rules still apply.
4.4 Assets
- Convert the fonts (1.2MB of TTF) to WOFF2 with an Arabic/Latin subset, and preload the regular weight.
- Remove the duplicate logo:
public/logo.pngandsrc/assets/logo.pngare identical (~196KB each). - The logo has an opaque near-white background (
254,254,254,255), which is why the header needsbg-white/90on OLED. Provide a transparent or theme-aware variant, ideally SVG. - 1024×559 is not a usable favicon. Add a square mark and 32/180/512 PNGs, plus
apple-touch-icon. - Add the OFL licenses for IBM Plex and JetBrains Mono under
apps/web/public/fonts/orapps/web/LICENSES/, and document the logo’s source and license.
4.5 Dependencies
- Remove or start using:
zustand,lucide-react,react-router-dom,phoenix,@radix-ui/react-dialog,@radix-ui/react-dropdown-menu,@radix-ui/react-tabs. - If
phoenixstays, align it with the server’s Phoenix 1.8.16 rather than 1.7.14. - React 18 / Vite 5 / Tailwind 3 are older than the current ecosystem in 2026. You do not have to upgrade in this PR, but record the rationale in the ADR instead of leaving it implicit.
4.6 Hygiene
.gitignore: remove_legacy_archive/andASN-Design-System.md. They are unrelated to this PR, and globally ignoring a documentation filename is risky.- The changelog uses
pyinstead ofpython3; correct it and list the commands that actually ran. - Fill in the PR template: Type, Contracts/Data, Verification, Security checklist, Risk/rollback.
- Add screenshots or a short GIF of the demo in OLED/Dim/Light and RTL, so the visual review is possible.
- If you split the PR into multiple commits, give each commit its own change record, as required by
docs/changelog/README.md.
5) Final verification
rm -rf node_modules
bun install --frozen-lockfile
bun run typecheck
bun run lint
bun run test
bun run build:web
bun run dev # confirm the dev server starts on port 3000
python3 scripts/ci/check-changelog.py --all
python3 scripts/ci/check-links.py
# Name check
grep -rn "Tawasol\|تواصل" apps docs AGENTS.md \
--include='*.md' --include='*.ts' --include='*.tsx' --include='*.html'
# Stale documentation
grep -rn "no manifest\|not scaffolded\|not required yet" AGENTS.md docs apps
# No npm leftovers
grep -rn "npm\|package-lock" --include='*.md' --include='*.json' --include='*.yml' . \
| grep -v node_modules
# Tailwind tint utilities
grep -F 'bg-primary\/10' apps/web/dist/assets/*.css6) Acceptance checklist
- Branch rebased on
main, CI approved and green. -
package-lock.jsonremoved;bun.lockcommitted;packageManagerand.tool-versionspin the same Bun version. - Clean clone works with
bun install --frozen-lockfileandbun run build:web; no Node-only assumption remains. - All docs/commands use Bun; no npm references remain.
- CI uses
oven-sh/setup-bunwith the pinned version and--frozen-lockfile. - Name decision resolved: ASN only, or ADR + glossary + name/logo ownership.
- ADR 0001 (monorepo/toolchain) and ADR 0012 (design system) exist, or the design document is
Proposedand indexed. -
AGENTS.md,docs/development/*, andpackages/config-typescript/README.mdmatch the new reality. -
apps/web/README.mdrestores Owns/Boundaries/Tests/Status, with current vs planned separated. - Feature READMEs are marked planned and do not resolve open auth/E2EE/privacy decisions.
- Tailwind tints and borders are present in
dist. - All small text meets 4.5:1; no 11px text; interactive controls have names and states.
- Tests, ESLint/Prettier, and web CI exist.
- WOFF2 fonts + OFL licenses; one logo + proper favicon sizes.
- Unused dependencies removed or justified.
- PR template completed, screenshots added, changelog verification accurate.
7) Closing note
This is a good foundation for the web client, and I do not want the work to be lost. If any of the owner decisions above are outside your scope, leave a TODO and ask for an explicit ruling instead of deciding implicitly — that matches AGENTS.md §10.
Happy to re-review after the Bun migration and the documentation updates. Thanks 🙏
- Initialize root monorepo workspace configuration and @asn/config-typescript. - Scaffold apps/web with React 18, Vite, TypeScript, and Tailwind CSS. - Download and configure local offline fonts (IBM Plex Sans Arabic and JetBrains Mono). - Integrate provisional brand logo and favicon. - Author complete design system specification in docs/architecture/design-system.md. - Add structured documentation for all feature directories in apps/web/src/. Changelog: docs/changelog/2026-10-24-web-scaffolding-and-design-system.md
8dca3f1 to
b789ae0
Compare
|
Hi @Yako-Ken, Thanks again for the work on this PR. The Bun migration, the RGB token change, ADR 0012, the accessibility pass, the tests, and the new web CI are all solid, and I appreciate the care you put into the docs and the component structure. This is a strong foundation. I pulled the latest head (
The PR is close. Before we can accept it, please address the following final items. Must fix before merge
Follow-ups (please open issues)
Once these are in and the Thanks again — I don't want this work to stall. Happy to help with a small follow-up commit if useful. — HMH |
- Remove package-lock.json and adopt native bun.lock. - Pin Bun package manager to eliminate lockfile divergence across the monorepo. Changelog: docs/changelog/2026-10-24-adopt-bun-lock.md
…e WCAG AA - Standardize frontend toolchain on Bun (pin 1.4.4, workspace:*, Bun scripts, and CI workflow). - Resolve product naming strictly to ASN per docs/GLOSSARY.md; replace provisional logo with square ASN icons (32x32, 180x180, 512x512). - Restore documentation sections in local-environment.md and testing.md, and restore ADR 0009 in decisions index. - Align design tokens and specification in docs/architecture/design-system.md (UTF-8 without BOM, valid CSS Appendix B). - Enforce WCAG 2.1 AA accessibility (>= 4.5:1 text contrast across all themes; >= 3.0:1 focus rings) via per-theme semantic status foreground tokens and --primary-text. - Add visible indicator for active accent selection and explicit visible presence indicator in metadata. - Clean apps/web/README.md and remove redundant lint script in favor of standard typecheck. - Add component unit tests with Bun test and happy-dom. Changelog: docs/changelog/2026-10-24-pr-review-remediation.md
b789ae0 to
34ba7e2
Compare
Changelog: docs/changelog/2026-10-24-web-scaffolding-and-design-system.md
Summary
Related issue
Change record
Changelog: docs/changelog/YYYY-MM-DD-slug.mdType
Contracts and data
Verification
Security and E2EE checklist
Risk and rollback
Reviewer notes