Skip to content
Open
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 AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- `npm run dev` — development server (Express + Vite HMR)
- `npm run lint` / `npm run lint:fix` — ESLint
- `npm run type-check` — TypeScript type verification
- `npm run check:docs` — docs drift/consistency validation
- `npm run build` — production build
- `npm run test` — Full suite: lint + type-check + E2E
- `npm run test:e2e` — Cypress E2E tests (dev server must be running)
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added `scripts/check-docs-consistency.mjs` and `npm run check:docs` to detect high-risk documentation drift automatically.
- Added shared `LoadingFallback` and `BackHomeCta` UI components to reduce repeated loading/CTA markup.
- Added `skills/migrate-design-system-to-shadcn/SKILL.md` to guide full Chakra-to-shadcn migration with explicit removal criteria.
- Added `skills/add-form-manager/SKILL.md` to standardize React Hook Form + Zod adoption, starting with login-form migration guidance.
Expand Down
2 changes: 1 addition & 1 deletion docs/AUTHENTICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This project uses a simple, production-leaning auth flow built around:
- `passport-local` for username/password verification
- signed JWTs for stateless auth
- an `httpOnly` cookie (`token`) for browser session continuity
- login rate limiting on `POST /login/password` to reduce brute-force attempts
- login rate limiting on `POST /api/session` and `POST /login/password` to reduce brute-force attempts
- one hardcoded default user for local use

## How it works (server + client)
Expand Down
1 change: 1 addition & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ We welcome contributions! Here's how to get started:
Before submitting your pull request, make sure to:

- Run `npm run test` to ensure code quality, verify TypeScript types, and run the E2E tests.
- Run `npm run check:docs` when editing documentation to catch known cross-doc drift (also included in `npm run test`).
- Run `npm run check:i18n` when your change adds/updates message ids and you are keeping locale files fully in sync.
- Test your changes locally with `npm run dev`

Expand Down
11 changes: 9 additions & 2 deletions docs/SCRIPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ Runs ESLint and automatically fixes issues where possible.
## Testing

### `npm run test`
Runs the full validation suite: lint, type-check, and E2E tests.
- Equivalent to: `npm run lint && npm run type-check && npm run test:e2e`
Runs the full validation suite: lint, type-check, docs consistency check, and E2E tests.
- Equivalent to: `npm run lint && npm run type-check && npm run check:docs && npm run test:e2e`

**When to use:** Before committing, in CI/CD, when preparing for deployment

Expand Down Expand Up @@ -102,6 +102,13 @@ Validates i18n locale files (optional; only when fully translating all locales).

**When to use:** Before committing when changing UI strings, if using option 3. See [scripts/README.md](../scripts/README.md) and [docs/I18N.md](I18N.md) for details.

### `npm run check:docs`
Validates critical documentation consistency rules.
- Guards against known drift patterns between core docs
- Exits with code 1 when a rule is violated

**When to use:** Before committing docs changes and in CI via `npm run test`.

## Common Workflows

### Starting a new feature
Expand Down
2 changes: 1 addition & 1 deletion docs/TECHNOLOGY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ To ensure data persistence across browser refreshes and sessions, we use the nat

## Passport.js

By integrating Passport.js as an example login process, we can demonstrate authentication without compromising security or scalability. Future improvements will focus on implementing additional features like CSRF protection and login attempts limits, which may require a database solution.
By integrating Passport.js as an example login process, we can demonstrate authentication without compromising security or scalability. CSRF protection and login rate limiting are already enabled in this boilerplate. Future evolution focuses on swapping the local starter account for a real auth backing profile (Supabase or Postgres).

## React Router

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
"build": "tsc -b && vite build",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"check:docs": "node ./scripts/check-docs-consistency.mjs",
"check:i18n": "node ./scripts/check-i18n-keys.mjs",
"preview": "vite preview",
"start": "NODE_ENV=production tsx src/server/main.ts",
"type-check": "tsc --noEmit",
"test": "npm run lint && npm run type-check && npm run test:e2e",
"test": "npm run lint && npm run type-check && npm run check:docs && npm run test:e2e",
"test:e2e": "cypress run",
"test:e2e:open": "cypress open"
},
Expand Down
14 changes: 14 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,17 @@ Part of the [i18n system](../docs/I18N.md). Validates that i18n locale files sta
On success, prints a confirmation. On failure, prints which keys are missing or extra and exits with code 1.

**When to run:** Only if using option 3 (full translation). Before committing when you add or change UI strings.

## check-docs-consistency.mjs

Invoked via `npm run check:docs`.

Validates known cross-doc consistency rules to prevent drift between canonical guides. Current checks include:

1. `docs/TECHNOLOGY.md` must not describe CSRF/login-rate-limiting as future work.
2. `docs/TECHNOLOGY.md` must explicitly state CSRF/login-rate-limiting are already enabled.
3. `docs/AUTHENTICATION.md` must document both `POST /api/session` and `POST /login/password` rate-limited login paths.

On success, prints a confirmation. On failure, prints the violated rule(s) and exits with code 1.

**When to run:** Before committing documentation changes and in CI via `npm run test`.
62 changes: 62 additions & 0 deletions scripts/check-docs-consistency.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const workspaceRoot = path.resolve(__dirname, '..');

const readFile = (relativePath) => {
const fullPath = path.join(workspaceRoot, relativePath);
return fs.readFileSync(fullPath, 'utf8');
};

const checks = [
{
type: 'forbid',
file: 'docs/TECHNOLOGY.md',
regex: /Future improvements will focus on implementing additional features like CSRF protection and login attempts limits/i,
message: 'TECHNOLOGY.md still describes CSRF/rate-limits as future work.',
},
{
type: 'require',
file: 'docs/TECHNOLOGY.md',
regex: /CSRF protection and login rate limiting are already enabled/i,
message: 'TECHNOLOGY.md should explicitly reflect that CSRF/rate-limiting are already enabled.',
},
{
type: 'require',
file: 'docs/AUTHENTICATION.md',
regex: /`POST \/api\/session`/i,
message: 'AUTHENTICATION.md should include the REST login endpoint (`POST /api/session`).',
},
{
type: 'require',
file: 'docs/AUTHENTICATION.md',
regex: /`POST \/login\/password`/i,
message: 'AUTHENTICATION.md should include the legacy login endpoint (`POST /login/password`).',
},
];

let hasFailure = false;

for (const check of checks) {
const content = readFile(check.file);
const matched = check.regex.test(content);

if (check.type === 'require' && !matched) {
console.error(`Docs consistency check failed: ${check.message}`);
hasFailure = true;
}

if (check.type === 'forbid' && matched) {
console.error(`Docs consistency check failed: ${check.message}`);
hasFailure = true;
}
}

if (hasFailure) {
process.exit(1);
}

console.log(`Docs consistency check passed for ${checks.length} checks.`);