Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ jobs:
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run build
- run: npm run test:browser
- name: Save browser diagnostics
if: always()
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ node_modules/
.playwright-cli/
output/
.vercel/
dist/
.astro/
.env*.local
16 changes: 8 additions & 8 deletions HOSTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ This removes Render's sleeping web service from the page-delivery path. Function

- Project: `flow-study`, in `manas-projects-e9259329` (verified Hobby scope).
- Framework: Other; `vercel.json` explicitly sets `framework: null`.
- Build command: empty; no frontend compilation is needed.
- Output directory: `public`.
- Install command: `npm ci --omit=dev`.
- API functions reuse the tested Express handlers; public files are excluded from their bundles.
- Build command: `npm run build` (Astro static generation).
- Output directory: `dist`.
- Install command: `npm ci`; TypeScript and build tools are needed during deployment.
- API functions reuse the tested Express handlers; `public`, `src`, and `dist` are excluded from their bundles. Set Node.js to a supported version (at least 22.23.4).
- Git repository: `ManasDasri/Flow-study`, production branch `main`.

The project is connected to GitHub for automatic deployments after merges. Keep the existing GitHub CI checks enabled. Deployment files and local credentials under `.vercel` are ignored by Git; only `public` is statically served, and `.env`, SQL, tests, and screenshots are excluded from uploads.
The project is connected to GitHub for automatic deployments after merges. Keep the existing GitHub CI checks enabled. Deployment files and local credentials under `.vercel` are ignored by Git; only the generated `dist` directory is statically served, and `.env`, SQL, tests, and screenshots are excluded from uploads.

## Move server credentials

Expand All @@ -41,17 +41,17 @@ Do not put these values in public files, Git, or chat. Existing Supabase public
Current domain configuration is visible at:
https://vercel.com/manas-projects-e9259329/flow-study/settings/domains

At preparation time, Namecheap serves the apex A record `216.24.57.1` for Render. Vercel's API recommends `216.198.79.1` as the primary replacement. In Namecheap Advanced DNS, edit the A record with host `@` to that value, keeping TTL Automatic. Re-check Vercel's domain settings before applying a later cutover. Do not change nameservers or unrelated MX/TXT records. The saved Render value is the rollback destination.
The apex A record was switched from Render (`216.24.57.1`) to Vercel (`216.198.79.1`) on October 31, 2026. Re-check Vercel's domain settings before any later DNS change. Do not change nameservers or unrelated MX/TXT records. The saved Render value is the rollback destination.

## Latency and limits

Both pages load the native HTML Speed Insights integration. It loads Vercel's deferred performance script on the custom domain and Vercel deployment URLs, strips query strings/fragments from reported URLs, and stays disabled on localhost. Enable Speed Insights in the project's dashboard to see incoming real-user measurements; no Next.js component or frontend build is required. The fixture browser suite intercepts telemetry so synthetic stress runs do not enter the dashboard. No paid Insights upgrade is enabled by this code.
Both pages load the native HTML Speed Insights integration. It loads Vercel's deferred performance script on the custom domain and Vercel deployment URLs, strips query strings/fragments from reported URLs, and stays disabled on localhost. Enable Speed Insights in the project's dashboard to see incoming real-user measurements; the integration is bundled by Astro and does not require a Next.js component. The fixture browser suite intercepts telemetry so synthetic stress runs do not enter the dashboard. No paid Insights upgrade is enabled by this code.

The browser loads the site without waiting for an API function. Groq has a 15-second request deadline without SDK retries. Twilio token requests have a four-second deadline, and the browser stops waiting for TURN after five seconds and continues with STUN. STUN-only calls may still fail on restrictive networks; a working TURN configuration remains important.

The existing API request limits remain in Express. Those counters are local to each function instance, so they are not a global distributed quota. Monitor provider and Hobby usage before increasing traffic; distributed quotas can be added when needed.

Local development remains `npm ci` followed by `npm start`. No Astro or design migration is included in this hosting change.
Local development uses `npm ci` followed by `npm run dev` on port 4321. For the production server, run `npm run build` and then `npm start`. The Astro migration changes page generation and bundling without changing the database or provider endpoints.

To run the isolated browser fixture suite against a deployed frontend instead of a local server:

Expand Down
36 changes: 29 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Flow.

[![CI](https://github.com/ManasDasri/Flow-study/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ManasDasri/Flow-study/actions/workflows/ci.yml)
[![Astro](https://img.shields.io/badge/Astro-7-bc52ee)](https://astro.build/)
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-22%20%7C%2024%20%7C%2026-5f8056)](https://nodejs.org/)
[![Open Flow](https://img.shields.io/badge/demo-flow--study.me-b6d3ac)](https://flow-study.me)

Expand All @@ -23,19 +25,28 @@ A shared study room for focused work. Bring your group, set a timer, and work th

## Run locally

Use Node.js 22, 24, or 26. CI exercises all three.
Use Node.js 22.23.4 or newer. CI exercises the latest releases of Node 22, 24, and 26.

```sh
git clone https://github.com/ManasDasri/Flow-study.git
cd Flow-study
npm ci
cp .env.example .env
npm run dev
```

Open `http://localhost:4321`. Astro provides live reload and forwards `/api/*` to the existing Express handlers.

To run the production build locally:

```sh
npm run build
npm start
```

Open `http://localhost:3000`. Set `PORT` to use another port.
The production server uses `http://localhost:3000`; set `PORT` to change that port.

The browser connects to the Supabase project configured in [`public/js/modules/supabase.js`](public/js/modules/supabase.js). For your own deployment, replace its project URL and **public publishable/anon key** with your project's values. Never put a service-role key in browser code.
The browser connects to the Supabase project configured in [`src/client/modules/supabase.ts`](src/client/modules/supabase.ts). For your own deployment, replace its project URL and **public publishable/anon key** with your project's values. Never put a service-role key in browser code.

### Server configuration

Expand Down Expand Up @@ -80,7 +91,18 @@ Generation loads Instrument Sans from Google Fonts; the deployed PNG has no font

## Architecture

The frontend is HTML, CSS, and browser JavaScript modules. Instrument Sans and an outlined `f.` mark provide the visual identity.
Astro generates static HTML from typed pages and reusable components. Strict TypeScript powers the interactive room modules, and Vite bundles and fingerprints JavaScript/CSS into `dist/_astro`. GSAP adds a single entry reveal and short responses to opening dialogs, switching panels, and completing tasks. Motion follows the system preference, including changes during a visit. Instrument Sans and an outlined `f.` mark preserve the visual identity.

| Location | Responsibility |
| --- | --- |
| `src/pages` | Login and room page templates |
| `src/layouts`, `src/components` | Shared metadata, page layout, room sections, and dialogs |
| `src/client` | Typed browser behavior, service models, and motion |
| `src/styles` | Shared design tokens, themes, and responsive layouts |
| `public` | Images, favicon, and social preview copied unchanged to the build |
| `api`, `server.js` | AI/TURN functions and the conventional Node server |

No client framework runtime is needed. Pages are generated at build time, while rooms remain fully interactive in the browser.

Express serves the site and the AI/TURN endpoints. Supabase handles authentication, PostgreSQL persistence, task changes, presence, and room broadcasts. WebRTC carries camera and microphone media between peers, with TURN relay support when configured. Groq handles assistant requests through the server. Room chat and broadcasts are transient; tasks, profiles, and completed sessions are stored.

Expand All @@ -106,7 +128,7 @@ GitHub Actions runs on pull requests to `main`, pushes/merges to `main`, and man

| Check | What it verifies |
| --- | --- |
| Node.js 22 / 24 / 26 | JavaScript parsing, HTTP boundaries, local concurrency, URL validation, and focus accounting |
| Node.js 22 / 24 / 26 | Strict Astro/TypeScript checks, production builds, JavaScript parsing, HTTP boundaries, local concurrency, URL validation, and focus accounting |
| PostgreSQL 17 | Both schema variants, migration repeatability, preserved data, room/PIN access, and task policies |
| Chromium | Complete interactive flows, failure recovery, stress fixtures, and ten responsive tool layouts |
| Dependency audit | Production dependencies fail the job on reported high/critical vulnerabilities |
Expand All @@ -115,8 +137,8 @@ Browser screenshots, results, and failure traces are uploaded as `browser-diagno

## Deploy

For free CDN hosting, use the included `vercel.json`: the `public` directory is served directly by the CDN, and the two files in `api` expose the existing Express endpoints as Node functions. This keeps Render's web-service startup out of page loads. See [HOSTING.md](HOSTING.md) for credentials, domain cutover, verification, and rollback.
For free CDN hosting, use the included `vercel.json`: Astro builds the `dist` directory, which is served directly by the CDN, and the two files in `api` expose the existing Express endpoints as Node functions. This keeps Render's web-service startup out of page loads. See [HOSTING.md](HOSTING.md) for credentials, domain cutover, verification, and rollback.

Conventional Node hosting remains supported with `npm ci --omit=dev` and `npm start`. Serve the public site over HTTPS for camera/microphone access. Keep server credentials in the host's secret settings.
Conventional Node hosting remains supported with `npm ci`, `npm run build`, and `npm start`. Build dependencies must be installed before generating `dist`. Serve the public site over HTTPS for camera/microphone access. Keep server credentials in the host's secret settings.

Before a wider launch, validate live authentication, two-account room behavior, physical media across networks, TURN, provider success paths, and browser compatibility. Local fixture stress checks are documented measurements, not a hosted-capacity guarantee.
34 changes: 15 additions & 19 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,9 @@ The browser runner starts an ephemeral local server and closes it after checking

The runner executes ui-smoke.js and then tools-layout.js in one browser context. The layout check covers ten viewport sizes, including 1366x600 and 1440x500, verifies composer and fullscreen control bounds, checks that labels fit inside their buttons, and exercises Shift+Enter versus Enter. It also verifies the outlined f. SVG favicon loads without a runtime font dependency.

For interactive debugging with Playwright CLI, start npm start, open its local URL, and run both scripts in the same session:
`npm test` first runs strict Astro/TypeScript diagnostics and a fresh production build. The browser suite serves that built output. Run `npm run build` before invoking the browser suite on its own. Its RTC harness compiles the real TypeScript media module with fixture signalling and is intercepted only by Playwright; it is never included in `dist` or deployed. The SDK fixture replaces the external Supabase SDK at the network boundary, while the actual bundled app handles interactions and callbacks.

```sh
playwright-cli open http://localhost:3000/login.html
playwright-cli run-code --filename=scripts/ui-smoke.js
playwright-cli run-code --filename=scripts/tools-layout.js
```
The browser suite also exercises normal motion, closing a dialog during its entrance, changing to reduced motion during an entrance, and focus restoration. Use Playwright CLI against `npm run dev` for manual debugging; the complete automated fixture setup is owned by `scripts/browser-ci.cjs`.

Database checks require an isolated local PostgreSQL server owned by a test superuser named `flow_test`. They connect only to `127.0.0.1`, create disposable `flow_ui_*` databases, and remove those databases afterward. Do not point these checks at Supabase or a shared database.

Expand All @@ -31,26 +27,26 @@ FLOW_TEST_PGPORT=55439 npm run test:db

## Continuous integration

The workflow in .github/workflows/ci.yml runs on PRs targeting main, pushes to main (including merges), and manual dispatch. Node tests run on 22, 24, and 26; migration tests use an isolated PostgreSQL 17 service; Chromium runs the browser suite; the production dependency audit fails on high/critical findings. Browser diagnostics are uploaded even on failure and retained for seven days. Configure required status checks in GitHub branch rules if merges should be blocked.
The workflow in .github/workflows/ci.yml runs on PRs targeting main, pushes to main (including merges), and manual dispatch. Strict diagnostics, production builds, and Node tests run on 22, 24, and 26; migration tests use an isolated PostgreSQL 17 service; Chromium runs the browser suite; the production dependency audit fails on high/critical findings. Browser diagnostics are uploaded even on failure and retained for seven days. Configure required status checks in GitHub branch rules if merges should be blocked.

The test server clears AI and Twilio provider credentials before loading Express. CI never needs production secrets. The PostgreSQL service password is a disposable fixture value.

## Coverage inventory

| Area | Exercised behavior |
| --- | --- |
| `login.js`, `login.html` | Native form validation, Enter submission, service rejection recovery, signup, theme persistence, malformed stored login, logout, password visibility, interactive timer preview |
| `app.js`, `index.html` | Room code/PIN validation, wrong PIN, rejected join, bounded code collisions, host/join exclusion, invite clipboard fallback, media links, leave cancellation and confirmation |
| `feedback.js` | Inline feedback, toasts, dialog focus containment, Escape, focus restoration, inert background |
| `ui.js` | Task reconciliation, assignment, completion, pending controls, empty states, text escaping, presence cards, progress |
| `tasks.js` | Add/update/delete rejection, empty RLS write results, rollback, preserved draft text, in-flight duplicate prevention, task-load retry |
| `chat.js` | Normal sends, failed delivery, AI errors and success, question retry, hostile/long text, bounded history |
| `timer.js` | Start/pause/reset, all modes, settings bounds, rejected malformed sync, completion, wall-time catch-up after simulated throttling |
| `presence.js`, `profile.js` | Local/remote status, focus transitions, profile edits/failure recovery, session completion and stats refresh, matching live profile/card time, pause exclusion, save reconciliation, local-midnight accounting |
| `socket.js` | Subscription state, tracking rejection/recovery, participant leave/rejoin grace period, disconnect and stale callback suppression |
| `rtc.js` | Denied-media fallback, stalled TURN request deadline, local offer and answer negotiation, two received synthetic tracks, peer removal, track shutdown, late peer creation cancellation |
| `supabase.js`, `utils.js` | Request deadlines and caller cancellation, corrupted storage, Unicode escaping, supported YouTube/Spotify URLs and lookalike rejection |
| audio.js | YouTube/Spotify provider switching, canonical embeds, stopping the old player, invalid link rejection, incoming room audio |
| `login.ts`, `login.astro` | Native form validation, Enter submission, service rejection recovery, signup, theme persistence, malformed stored login, logout, password visibility, interactive timer preview |
| `app.ts`, `index.astro` | Room code/PIN validation, wrong PIN, rejected join, bounded code collisions, host/join exclusion, invite clipboard fallback, media links, leave cancellation and confirmation |
| `feedback.ts` | Inline feedback, toasts, dialog focus containment, Escape, focus restoration, inert background |
| `ui.ts` | Task reconciliation, assignment, completion, pending controls, empty states, text escaping, presence cards, progress |
| `tasks.ts` | Add/update/delete rejection, empty RLS write results, rollback, preserved draft text, in-flight duplicate prevention, task-load retry |
| `chat.ts` | Normal sends, failed delivery, AI errors and success, question retry, hostile/long text, bounded history |
| `timer.ts` | Start/pause/reset, all modes, settings bounds, rejected malformed sync, completion, wall-time catch-up after simulated throttling |
| `presence.ts`, `profile.ts` | Local/remote status, focus transitions, profile edits/failure recovery, session completion and stats refresh, matching live profile/card time, pause exclusion, save reconciliation, local-midnight accounting |
| `socket.ts` | Subscription state, tracking rejection/recovery, participant leave/rejoin grace period, disconnect and stale callback suppression |
| `rtc.ts` | Denied-media fallback, stalled TURN request deadline, local offer and answer negotiation, two received synthetic tracks, peer removal, track shutdown, late peer creation cancellation |
| `supabase.ts`, `utils.ts` | Request deadlines and caller cancellation, corrupted storage, Unicode escaping, supported YouTube/Spotify URLs and lookalike rejection |
| audio.ts | YouTube/Spotify provider switching, canonical embeds, stopping the old player, invalid link rejection, incoming room audio |
| CSS and HTML | Browser-rendered checks at 320, 390, 768, 1024, and 1440px; horizontal overflow, primary text contrast in all themes, reduced motion, desktop/mobile screenshots |
| `server.js` | Static assets and missing/private paths, malformed/type/size boundaries, unconfigured providers, rate limiting, local concurrent static requests |
| SQL | Legacy TEXT and current UUID fixtures, data preservation, repeat application, PIN checks, task isolation, author validation, publication preservation |
Expand Down
21 changes: 21 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from 'astro/config';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

export default defineConfig({
site: 'https://flow-study.me',
output: 'static',
build: { format: 'file' },
vite: {
plugins: [{
name: 'flow-local-api',
configureServer(server) {
const app = require('./server.js');
server.middlewares.use((req, res, next) => {
if (req.url?.startsWith('/api/')) app(req, res, next);
else next();
});
}
}]
}
});
Loading
Loading