@chidchanun/bcp 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,75 @@
1
1
  # BCP Framework
2
2
 
3
- BCP Framework is a React full-stack framework with file-based routing, SSR, SPA navigation, API routes, middleware, loaders, guards, form actions, authentication, MySQL primitives, validation, structured errors, logging, file uploads and standalone production builds.
3
+ BCP Framework is a React full-stack framework focused on file-based routing, SSR, server data loading, guarded application flows, API routes, authentication, database access, validation, logging, uploads, storage adapters and standalone production deployment.
4
4
 
5
- > Current release target: `0.1.24`. BCP is pre-1.0 and each release candidate is validated before the manual npm publish step.
5
+ > **Release candidate target:** `0.1.26`
6
+ >
7
+ > BCP is pre-1.0. The `0.1.26` source is complete for RC validation, but it must not be presented as a published npm release until the full release checks pass and the matching packages are published.
8
+
9
+ ## Overview
10
+
11
+ BCP keeps React pages and their server behavior close to the route that owns them:
12
+
13
+ ```text
14
+ Browser
15
+
16
+ BCP security / middleware / cache
17
+
18
+ Route guard
19
+
20
+ Loader / action / API route
21
+
22
+ React SSR
23
+
24
+ Hydration / SPA navigation
25
+ ```
26
+
27
+ A typical route can colocate its page, loader, guard and actions:
28
+
29
+ ```text
30
+ app/
31
+ ├─ layout.tsx
32
+ ├─ page.tsx
33
+ ├─ dashboard/
34
+ │ ├─ guard.ts
35
+ │ └─ users/
36
+ │ └─ [id]/
37
+ │ ├─ loader.ts
38
+ │ ├─ actions.ts
39
+ │ └─ page.tsx
40
+ └─ api/
41
+ └─ upload/
42
+ └─ route.ts
43
+ ```
44
+
45
+ ## Current capabilities
46
+
47
+ | Area | Capability |
48
+ | --- | --- |
49
+ | Application | React SSR, hydration, layouts, metadata, SPA navigation |
50
+ | Routing | Static, dynamic, catch-all, optional catch-all and route groups |
51
+ | Server data | `loader.ts`, request-scoped server APIs |
52
+ | Mutations | Route-owned `actions.ts` and `<Form>` |
53
+ | Authorization | `guard.ts`, `requireAuth()`, `requireRole()` |
54
+ | Authentication | JWT cookie sessions and auth helpers |
55
+ | Middleware | Middleware System v2 with onion execution |
56
+ | Validation | Typed validation helpers and structured validation errors |
57
+ | Error handling | HTTP error helpers and consistent error responses |
58
+ | Database | MySQL pool/query helpers, transactions and migrations |
59
+ | Logging | Structured logger, request logger and request IDs |
60
+ | Uploads | Buffered multipart helpers and production multipart streaming |
61
+ | Storage | Local + S3-compatible adapters, streaming I/O and ranged delivery |
62
+ | Caching | Response cache and revalidation primitives |
63
+ | Developer tools | `doctor`, `inspect`, updater and route inspection |
64
+ | Production | Standalone server build with production middleware pipeline |
65
+
66
+ ## Requirements
67
+
68
+ - Node.js `24.11` or newer
69
+ - React `19`
70
+ - npm
71
+
72
+ Database features currently target MySQL.
6
73
 
7
74
  ## Quick start
8
75
 
@@ -18,36 +85,48 @@ Default development URL:
18
85
  http://localhost:3000
19
86
  ```
20
87
 
21
- ## CLI
88
+ Generated projects normally include:
22
89
 
23
- ```bash
24
- bcp dev
25
- bcp routes
26
- bcp build
27
- bcp start
28
- bcp doctor
29
- bcp doctor --json
30
- bcp inspect
31
- bcp inspect --json
32
- bcp update
33
- bcp version
90
+ ```json
91
+ {
92
+ "scripts": {
93
+ "dev": "bcp dev",
94
+ "build": "bcp build",
95
+ "start": "bcp start",
96
+ "routes": "bcp routes",
97
+ "update": "bcp update",
98
+ "typecheck": "tsc --noEmit"
99
+ }
100
+ }
101
+ ```
34
102
 
35
- bcp db create create_users
36
- bcp db migrate
37
- bcp db status
38
- bcp db rollback
103
+ ## Packages
104
+
105
+ The public framework package is published as:
106
+
107
+ ```text
108
+ @chidchanun/bcp
39
109
  ```
40
110
 
41
- Microsoft SQL Server also installs a Windows executable named `bcp.exe`. BCP Framework therefore also publishes the collision-free alias:
111
+ Applications normally consume it through the dependency key `bcp`, keeping imports concise:
42
112
 
43
- ```powershell
44
- bcp-framework doctor
45
- bcp-framework inspect
46
- bcp-framework dev
47
- bcp-framework build
113
+ ```ts
114
+ import {
115
+ Form,
116
+ Link,
117
+ useLoaderData,
118
+ } from "bcp";
48
119
  ```
49
120
 
50
- Normal project npm scripts can continue using `bcp` because npm places `node_modules/.bin` first on the script PATH.
121
+ Server-only APIs use dedicated entrypoints:
122
+
123
+ ```ts
124
+ import {
125
+ cookies,
126
+ logger,
127
+ requestId,
128
+ } from "bcp/server";
129
+ ```
51
130
 
52
131
  ## Project structure
53
132
 
@@ -55,21 +134,26 @@ Normal project npm scripts can continue using `bcp` because npm places `node_mod
55
134
  app/
56
135
  ├─ layout.tsx
57
136
  ├─ page.tsx
137
+ ├─ login/
138
+ │ └─ page.tsx
58
139
  ├─ dashboard/
59
140
  │ ├─ guard.ts
141
+ │ ├─ page.tsx
60
142
  │ └─ users/
61
143
  │ └─ [id]/
62
144
  │ ├─ loader.ts
63
145
  │ ├─ actions.ts
64
146
  │ └─ page.tsx
65
147
  └─ api/
66
- ├─ hello/
67
- │ └─ route.ts
148
+ ├─ auth/
149
+ │ └─ login/
150
+ │ └─ route.ts
68
151
  └─ upload/
69
152
  └─ route.ts
70
153
 
71
154
  lib/
72
155
  public/
156
+ migrations/
73
157
  bcp.config.ts
74
158
  package.json
75
159
  tsconfig.json
@@ -77,6 +161,8 @@ tsconfig.json
77
161
 
78
162
  ## Routing
79
163
 
164
+ Page routes are discovered from `app/**/page.tsx`:
165
+
80
166
  ```text
81
167
  app/page.tsx /
82
168
  app/about/page.tsx /about
@@ -88,9 +174,24 @@ app/(admin)/settings/page.tsx /settings
88
174
 
89
175
  Static routes have priority over dynamic and catch-all routes.
90
176
 
91
- ## Server data
177
+ API routes use `route.ts`:
92
178
 
93
- A route can load server-only data with `loader.ts`:
179
+ ```text
180
+ app/api/users/route.ts /api/users
181
+ app/api/users/[id]/route.ts /api/users/:id
182
+ ```
183
+
184
+ Read more: [Routing](docs/routing.md)
185
+
186
+ ## Layouts and metadata
187
+
188
+ Routes inherit layouts from parent directories. BCP resolves the layout chain in development and standalone production. Document metadata is route-aware and can be generated alongside the page tree.
189
+
190
+ Read more: [Routing](docs/routing.md)
191
+
192
+ ## Server data loaders
193
+
194
+ Place `loader.ts` next to a page when the route needs server-side data:
94
195
 
95
196
  ```ts
96
197
  // app/users/[id]/loader.ts
@@ -104,7 +205,7 @@ export async function loader({
104
205
  }
105
206
  ```
106
207
 
107
- The page consumes the serializable value with:
208
+ Consume serializable loader data from a client page:
108
209
 
109
210
  ```tsx
110
211
  "use client";
@@ -119,11 +220,37 @@ export default function UserPage() {
119
220
  id: string;
120
221
  }>();
121
222
 
122
- return <main>{data.id}</main>;
223
+ return <main>User {data.id}</main>;
123
224
  }
124
225
  ```
125
226
 
126
- Protected route trees can use `guard.ts`, and route-owned mutations can use `actions.ts` with the public `<Form>` client API.
227
+ Read more: [Server Data Loaders](docs/server-data-loaders.md)
228
+
229
+ ## Route guards
230
+
231
+ A route tree can define `guard.ts` to authorize access before rendering:
232
+
233
+ ```ts
234
+ import {
235
+ requireRole,
236
+ } from "bcp/auth";
237
+
238
+ export const guard =
239
+ requireRole("admin");
240
+ ```
241
+
242
+ The standalone production pipeline preserves the same active request context used by authentication and server request APIs.
243
+
244
+ Read more:
245
+
246
+ - [Route Guards](docs/route-guards.md)
247
+ - [Auth Route Guards](docs/auth-route-guards.md)
248
+
249
+ ## Form actions
250
+
251
+ Route-owned mutations live in `actions.ts` and can be invoked through the public `<Form>` API. BCP supports progressive form submission and SPA action transport while keeping mutation code server-only.
252
+
253
+ Read more: [Form Actions](docs/form-actions.md)
127
254
 
128
255
  ## Server request APIs
129
256
 
@@ -139,11 +266,127 @@ import {
139
266
  } from "bcp/server";
140
267
  ```
141
268
 
142
- `requestId()` accepts a valid incoming `X-Request-Id` or generates a stable UUID for the request.
269
+ `requestId()` accepts a valid incoming `X-Request-Id` or generates a stable UUID for the active request.
270
+
271
+ Read more: [Server Request APIs](docs/server-request-apis.md)
272
+
273
+ ## Authentication and sessions
274
+
275
+ High-level authentication helpers:
276
+
277
+ ```ts
278
+ import {
279
+ auth,
280
+ requireAuth,
281
+ requireRole,
282
+ } from "bcp/auth";
283
+ ```
284
+
285
+ Lower-level JWT cookie session primitives:
286
+
287
+ ```ts
288
+ import {
289
+ createSession,
290
+ createSessionToken,
291
+ destroySession,
292
+ getSession,
293
+ verifySessionToken,
294
+ } from "bcp/server";
295
+ ```
296
+
297
+ Authentication is separated from application-specific credential lookup so projects can connect their own user table or identity provider.
298
+
299
+ Read more:
300
+
301
+ - [Authentication](docs/authentication.md)
302
+ - [JWT Cookie Sessions](docs/session-auth.md)
303
+
304
+ ## Middleware
305
+
306
+ Middleware System v2 uses onion-style execution:
307
+
308
+ ```ts
309
+ export async function middleware(
310
+ request,
311
+ context,
312
+ next
313
+ ) {
314
+ const response =
315
+ await next();
316
+
317
+ response.headers.set(
318
+ "x-app",
319
+ "example"
320
+ );
321
+
322
+ return response;
323
+ }
324
+ ```
325
+
326
+ Existing middleware v1 behavior remains supported for compatibility.
143
327
 
144
- ## Logging & Observability
328
+ Read more: [Middleware](docs/middleware.md)
145
329
 
146
- BCP 0.1.23 introduced structured server logging:
330
+ ## Validation
331
+
332
+ ```ts
333
+ import {
334
+ v,
335
+ validateFormData,
336
+ } from "bcp/validation";
337
+ ```
338
+
339
+ Read more: [Validation](docs/validation.md)
340
+
341
+ ## Error handling
342
+
343
+ ```ts
344
+ import {
345
+ badRequest,
346
+ forbidden,
347
+ notFoundResponse,
348
+ toErrorResponse,
349
+ unauthorized,
350
+ } from "bcp/error";
351
+ ```
352
+
353
+ The common error envelope is:
354
+
355
+ ```json
356
+ {
357
+ "error": {
358
+ "status": 400,
359
+ "code": "BAD_REQUEST",
360
+ "message": "Invalid request"
361
+ }
362
+ }
363
+ ```
364
+
365
+ Read more: [Error Handling](docs/error-handling.md)
366
+
367
+ ## Database
368
+
369
+ ```ts
370
+ import {
371
+ db,
372
+ } from "bcp/database";
373
+ ```
374
+
375
+ The database layer provides a lazy MySQL pool, prepared execution, query helpers, transactions and migrations.
376
+
377
+ ```bash
378
+ bcp db create create_users
379
+ bcp db migrate
380
+ bcp db status
381
+ bcp db rollback
382
+ ```
383
+
384
+ Read more:
385
+
386
+ - [Database](docs/database.md)
387
+ - [Database Migrations](docs/database-migrations.md)
388
+
389
+ ## Logging and observability
147
390
 
148
391
  ```ts
149
392
  import {
@@ -158,25 +401,9 @@ logger.info(
158
401
  "catalog",
159
402
  }
160
403
  );
161
-
162
- export async function loader() {
163
- const log =
164
- await requestLogger({
165
- feature:
166
- "categories",
167
- });
168
-
169
- log.info(
170
- "Loading categories"
171
- );
172
-
173
- return {
174
- items: [],
175
- };
176
- }
177
404
  ```
178
405
 
179
- Configure output with:
406
+ Environment controls:
180
407
 
181
408
  ```env
182
409
  BCP_LOG_LEVEL=debug
@@ -185,9 +412,11 @@ BCP_LOG_FORMAT=json
185
412
 
186
413
  Supported levels are `debug`, `info`, `warn`, `error` and `silent`. Formats are `pretty` and `json`.
187
414
 
188
- ## File Upload
415
+ Read more: [Logging and Observability](docs/development-logging.md)
416
+
417
+ ## File uploads
189
418
 
190
- BCP 0.1.24 adds server-only multipart/file helpers through `bcp/server`:
419
+ BCP keeps the buffered multipart API for small forms:
191
420
 
192
421
  ```ts
193
422
  import {
@@ -196,202 +425,296 @@ import {
196
425
  saveUploadedFile,
197
426
  } from "bcp/server";
198
427
 
199
- export async function POST(
200
- request: Request
201
- ) {
202
- const formData =
203
- await parseMultipartFormData(
204
- request,
205
- {
206
- maxBytes:
207
- 8 * 1024 * 1024,
208
- }
209
- );
210
-
211
- const file =
212
- requireUploadedFile(
213
- formData,
214
- "file",
215
- {
428
+ const formData =
429
+ await parseMultipartFormData(
430
+ request,
431
+ {
432
+ maxBytes:
433
+ 8 * 1024 * 1024,
434
+ }
435
+ );
436
+
437
+ const file =
438
+ requireUploadedFile(
439
+ formData,
440
+ "file",
441
+ {
442
+ maxBytes:
443
+ 5 * 1024 * 1024,
444
+ allowedTypes: [
445
+ "image/png",
446
+ "image/jpeg",
447
+ "image/webp",
448
+ ],
449
+ }
450
+ );
451
+ ```
452
+
453
+ BCP `0.1.26` adds direct multipart-to-storage streaming for larger production uploads:
454
+
455
+ ```ts
456
+ import {
457
+ storeMultipartFile,
458
+ } from "bcp/server";
459
+
460
+ const stored =
461
+ await storeMultipartFile(
462
+ request,
463
+ {
464
+ storage,
465
+ fieldName:
466
+ "file",
467
+ key:
468
+ "documents/report.pdf",
469
+ maxBytes:
470
+ 100 * 1024 * 1024,
471
+ constraints: {
216
472
  maxBytes:
217
- 5 * 1024 * 1024,
473
+ 80 * 1024 * 1024,
218
474
  allowedTypes: [
219
- "image/png",
220
- "image/jpeg",
221
- "image/webp",
475
+ "application/pdf",
222
476
  ],
223
477
  allowedExtensions: [
224
- ".png",
225
- ".jpg",
226
- ".jpeg",
227
- ".webp",
478
+ ".pdf",
228
479
  ],
229
- }
230
- );
231
-
232
- const saved =
233
- await saveUploadedFile(
234
- file,
235
- {
236
- directory:
237
- "./uploads",
238
- }
239
- );
240
-
241
- return Response.json({
242
- fileName:
243
- saved.fileName,
244
- size:
245
- saved.size,
246
- checksumSha256:
247
- saved.checksumSha256,
248
- });
249
- }
480
+ },
481
+ }
482
+ );
250
483
  ```
251
484
 
252
- Upload helpers provide:
485
+ `storeMultipartFile()` parses `Request.body` incrementally and streams the selected file directly into the configured `StorageAdapter`. It does not call `request.formData()` for the target file.
486
+
487
+ The security gateway still applies `server.bodyLimit` / `BCP_BODY_LIMIT` as the outer request limit. Streaming controls memory use; it does not bypass proxy/platform/body limits.
253
488
 
254
- - multipart validation,
255
- - total and per-file size limits,
256
- - MIME/extension allowlists,
257
- - optional or required file fields,
258
- - safe UUID-based storage names,
259
- - filename sanitization,
260
- - path traversal protection,
261
- - no-overwrite-by-default storage,
262
- - SHA-256 checksum metadata.
489
+ MIME type and extension validation are metadata checks, not content-signature verification.
263
490
 
264
- The security gateway enforces `server.bodyLimit` / `BCP_BODY_LIMIT` before request data reaches application handlers. The default is 1 MiB, so applications accepting larger files must raise it explicitly.
491
+ Read more: [File Upload](docs/file-upload.md)
492
+
493
+ ## Storage adapters
494
+
495
+ ### Local filesystem
265
496
 
266
497
  ```ts
267
498
  import {
268
- defineConfig,
269
- } from "bcp/config";
499
+ createLocalStorage,
500
+ } from "bcp/server";
270
501
 
271
- export default defineConfig({
272
- server: {
273
- bodyLimit:
274
- 10 * 1024 * 1024,
275
- },
276
- });
502
+ const storage =
503
+ createLocalStorage({
504
+ directory:
505
+ "./uploads",
506
+ });
277
507
  ```
278
508
 
279
- MIME type and extension are metadata checks, not content-signature verification. Security-sensitive applications should additionally inspect file content and use malware scanning where appropriate.
280
-
281
- See [File Upload](docs/file-upload.md).
509
+ ### S3-compatible storage
282
510
 
283
- ## Development route graph recovery
511
+ BCP `0.1.26` adds an S3-compatible backend:
284
512
 
285
- BCP 0.1.24 fixes a development route/client-bundle synchronization issue that could produce:
513
+ ```ts
514
+ import {
515
+ createS3Storage,
516
+ } from "bcp/server";
286
517
 
287
- ```text
288
- Client bundle was not found for route "/docs/[...slug]".
518
+ const storage =
519
+ createS3Storage({
520
+ bucket:
521
+ process.env.S3_BUCKET!,
522
+ region:
523
+ process.env.S3_REGION!,
524
+ endpoint:
525
+ process.env.S3_ENDPOINT,
526
+ accessKeyId:
527
+ process.env.S3_ACCESS_KEY_ID,
528
+ secretAccessKey:
529
+ process.env.S3_SECRET_ACCESS_KEY,
530
+ });
289
531
  ```
290
532
 
291
- The problem happened when the actual page topology changed but Windows/editor filesystem events were classified as `change` instead of `add`/`unlink`. The route scanner could see a new route while the incremental client bundle graph still represented the previous route tree.
533
+ Custom endpoints and `forcePathStyle` allow use with S3-compatible services such as MinIO. Explicit credentials are optional; when omitted, the AWS SDK can use its normal server-side credential provider chain.
292
534
 
293
- The dev gateway now compares the actual pathname/page/layout graph and automatically refreshes the internal development server/client bundler when topology changes. Manually deleting `.bcp-framework` should no longer be required to recover this state.
535
+ Keep cloud credentials server-only. Never expose them through `BCP_PUBLIC_*` variables.
294
536
 
295
- ## Developer diagnostics
537
+ Read more: [S3-Compatible Storage](docs/s3-storage.md)
296
538
 
297
- ```bash
298
- bcp doctor
299
- bcp inspect
539
+ ### Streaming storage
540
+
541
+ The `StorageAdapter` contract keeps its original buffered methods and adds optional streaming capabilities:
542
+
543
+ ```text
544
+ put
545
+ putStream? ← 0.1.26
546
+ stat
547
+ read
548
+ readStream? ← 0.1.26
549
+ exists
550
+ delete
551
+ ```
552
+
553
+ Use generic helpers so legacy and native-streaming adapters can share application code:
554
+
555
+ ```ts
556
+ import {
557
+ getStorageCapabilities,
558
+ putStorageStream,
559
+ readStorageStream,
560
+ } from "bcp/server";
300
561
  ```
301
562
 
302
- `bcp doctor` checks project structure, BCP/React installations, React renderer parity, duplicate framework copies, environment/config loading, route conflicts and client/server boundaries. Blocking failures return a non-zero exit code.
563
+ Both built-in `0.1.26` adapters support native streaming reads, streaming writes and byte ranges.
303
564
 
304
- `bcp inspect` prints resolved configuration, development env filenames, public variable names, dependency versions and discovered routes.
565
+ Streaming writes support `maxBytes` and `AbortSignal`. Local incomplete objects are removed on failure; S3 multipart uploads are configured to clean up parts on failed completion.
305
566
 
306
- For local release verification, install packed `.tgz` artifacts under the existing `bcp` dependency key. Do not install a second `@chidchanun/bcp` copy next to `node_modules/bcp`, because separate framework copies can split React contexts and produce misleading loader/hook errors.
567
+ Read more: [Storage and File Delivery](docs/storage.md)
307
568
 
308
- ## Validation and errors
569
+ ## Production file delivery
309
570
 
310
571
  ```ts
311
572
  import {
312
- v,
313
- validateFormData,
314
- } from "bcp/validation";
573
+ createStorageResponse,
574
+ } from "bcp/server";
315
575
 
316
- import {
317
- badRequest,
318
- unauthorized,
319
- toErrorResponse,
320
- } from "bcp/error";
576
+ export function GET(
577
+ request: Request
578
+ ) {
579
+ return createStorageResponse(
580
+ request,
581
+ storage,
582
+ "documents/report.pdf",
583
+ {
584
+ disposition:
585
+ "attachment",
586
+ downloadName:
587
+ "report.pdf",
588
+ }
589
+ );
590
+ }
321
591
  ```
322
592
 
323
- Structured error responses use the common envelope:
593
+ `createStorageResponse()` uses storage streaming and supports:
324
594
 
325
- ```json
326
- {
327
- "error": {
328
- "status": 400,
329
- "code": "BAD_REQUEST",
330
- "message": "Invalid request"
331
- }
332
- }
595
+ - `GET` / `HEAD`,
596
+ - ETag / Last-Modified validators,
597
+ - `If-Range`,
598
+ - single byte ranges with `206 Partial Content`,
599
+ - `304 Not Modified`,
600
+ - `416 Range Not Satisfiable`,
601
+ - safe `Content-Disposition` filenames,
602
+ - configurable cache control.
603
+
604
+ The default cache policy remains:
605
+
606
+ ```text
607
+ private, max-age=0, must-revalidate
333
608
  ```
334
609
 
335
- ## Database
610
+ Multiple byte ranges remain intentionally unsupported in `0.1.26`.
336
611
 
337
- ```ts
338
- import {
339
- db,
340
- } from "bcp/database";
612
+ Read more: [Storage and File Delivery](docs/storage.md)
613
+
614
+ ## Caching
615
+
616
+ BCP includes response caching and revalidation primitives used by development and standalone production runtimes.
617
+
618
+ Read more: [Caching](docs/caching.md)
619
+
620
+ ## Security
621
+
622
+ The framework security layer includes request body limits and production request handling defaults. Application authorization remains the responsibility of route guards and application logic.
623
+
624
+ Storage keys, filenames and MIME metadata must not be treated as authorization decisions.
625
+
626
+ Read more: [Security](docs/security.md)
627
+
628
+ ## Environment and configuration
629
+
630
+ Application configuration lives in:
631
+
632
+ ```text
633
+ bcp.config.ts
634
+ ```
635
+
636
+ Public environment variables use:
637
+
638
+ ```text
639
+ BCP_PUBLIC_
341
640
  ```
342
641
 
343
- The database layer provides a lazy MySQL pool, prepared execution, queries and transactions. Database migrations are managed through `bcp db` commands.
642
+ Server-only values remain server-side and are not emitted into browser bundles.
344
643
 
345
- ## Authentication
644
+ Read more: [Configuration](docs/configuration.md)
346
645
 
347
- ```ts
348
- import {
349
- auth,
350
- requireAuth,
351
- requireRole,
352
- } from "bcp/auth";
646
+ ## Developer tools
647
+
648
+ ```bash
649
+ bcp doctor
650
+ bcp inspect
353
651
  ```
354
652
 
355
- BCP also exposes lower-level JWT cookie session helpers through `bcp/server`.
653
+ `bcp doctor` checks project structure, BCP/React installation parity, duplicate framework copies, environment/config loading, route conflicts and client/server boundaries.
356
654
 
357
- ## Middleware
655
+ `bcp inspect` reports resolved configuration, environment sources, dependency versions and discovered routes.
358
656
 
359
- Middleware v2 uses true onion execution:
657
+ Read more: [Developer Tools](docs/developer-tools.md)
360
658
 
361
- ```ts
362
- export async function middleware(
363
- request,
364
- context,
365
- next
366
- ) {
367
- const response =
368
- await next();
659
+ ## Windows CLI
369
660
 
370
- response.headers.set(
371
- "x-app",
372
- "example"
373
- );
661
+ Microsoft SQL Server can install another executable named `bcp.exe`. BCP therefore publishes the collision-free alias `bcp-framework`.
374
662
 
375
- return response;
376
- }
663
+ Inside npm scripts, `bcp` is safe because npm prepends the project's `node_modules/.bin` to `PATH`.
664
+
665
+ For direct PowerShell usage, use the project-local CLI:
666
+
667
+ ```powershell
668
+ npm exec -- bcp-framework --version
669
+ npm exec -- bcp-framework doctor
670
+ npm exec -- bcp-framework inspect
671
+ npm exec -- bcp-framework routes
672
+ npm exec -- bcp-framework dev
673
+ npm exec -- bcp-framework build
674
+ ```
675
+
676
+ This keeps the CLI version aligned with the framework installed by the application.
677
+
678
+ ## CLI reference
679
+
680
+ ```bash
681
+ bcp dev
682
+ bcp routes
683
+ bcp build
684
+ bcp start
685
+ bcp doctor
686
+ bcp doctor --json
687
+ bcp inspect
688
+ bcp inspect --json
689
+ bcp update
690
+ bcp version
691
+
692
+ bcp db create create_users
693
+ bcp db migrate
694
+ bcp db status
695
+ bcp db rollback
377
696
  ```
378
697
 
379
- Existing v1 middleware remains supported.
698
+ ## Development behavior
380
699
 
381
- ## Hydration parity
700
+ BCP includes Fast Refresh and deterministic development hydration behavior. Recent stabilization work covers:
382
701
 
383
- BCP 0.1.20 normalized Windows CRLF/CR source line endings in development instrumentation. BCP 0.1.21 completed SSR/client JSX semantic parity by preserving JSX through the Babel React Refresh pass and allowing esbuild to perform the development JSX transform.
702
+ - Windows line-ending parity,
703
+ - multiline JSX hydration parity,
704
+ - duplicate BCP installation detection,
705
+ - automatic page-route/client-bundle graph resynchronization,
706
+ - standalone authentication guard request-context parity.
384
707
 
385
- Multiline quoted JSX attributes are supported without rewriting classes onto a single line or applying `suppressHydrationWarning` as a framework workaround.
708
+ Read more: [Hydration](docs/hydration.md)
386
709
 
387
- ## Production
710
+ ## Production build
388
711
 
389
712
  ```bash
390
713
  npm run build
391
- npm start
714
+ npm run start
392
715
  ```
393
716
 
394
- Standalone output is generated under:
717
+ Production output:
395
718
 
396
719
  ```text
397
720
  .bcp-framework/build/
@@ -401,44 +724,73 @@ Standalone output is generated under:
401
724
  └─ server.mjs
402
725
  ```
403
726
 
404
- ## Updating
727
+ The standalone runtime composes production middleware, security, cache, actions, guards, loaders and page rendering into the final HTTP pipeline.
728
+
729
+ Runtime hostname/port overrides can be supplied to `bcp start` without rebuilding.
730
+
731
+ Read more: [Deployment](docs/deployment.md)
732
+
733
+ ## Updating BCP
405
734
 
406
735
  ```bash
407
736
  bcp update
408
737
  bcp update --check
409
738
  bcp update --dry-run
410
- bcp update 0.1.24
739
+ bcp update 0.1.26
411
740
  bcp update next
412
741
  ```
413
742
 
414
- Projects published before the updater can bootstrap it once with:
743
+ Projects created before the updater was introduced can bootstrap it once with:
415
744
 
416
745
  ```bash
417
746
  npx @chidchanun/bcp@latest update
418
747
  ```
419
748
 
420
- ## Release validation
749
+ Read more: [Updating](docs/updating.md)
750
+
751
+ ## Framework development and release validation
752
+
753
+ Inside the BCP Framework repository:
421
754
 
422
755
  ```bash
756
+ npm install
423
757
  npm run typecheck
424
758
  npm run test:unit
759
+ npm run test:integration
760
+ npm run test:e2e
761
+ npm run test:package
762
+ ```
763
+
764
+ Full release-candidate validation:
765
+
766
+ ```bash
425
767
  npm run rc:check
426
768
  ```
427
769
 
428
- After RC passes, releases are tagged and published manually with the guarded release scripts.
770
+ A version must not be tagged or published until RC and packed-package verification pass.
429
771
 
430
- ## Documentation
772
+ Read more: [Releasing](docs/releasing.md)
431
773
 
774
+ ## Documentation source
775
+
776
+ The `docs/` directory is the source content for the future **`bcp-docs-web`** documentation website.
777
+
778
+ Start with:
779
+
780
+ - [Documentation Source Map](docs/README.md)
432
781
  - [Getting Started](docs/getting-started.md)
782
+ - [Configuration](docs/configuration.md)
433
783
  - [Application Modules](docs/application-modules.md)
434
784
  - [Routing](docs/routing.md)
435
- - [Server Request APIs](docs/server-request-apis.md)
436
785
  - [Server Data Loaders](docs/server-data-loaders.md)
437
- - [Protected Route Guards](docs/route-guards.md)
786
+ - [Route Guards](docs/route-guards.md)
438
787
  - [Form Actions](docs/form-actions.md)
788
+ - [Server Request APIs](docs/server-request-apis.md)
439
789
  - [Validation](docs/validation.md)
440
790
  - [Error Handling](docs/error-handling.md)
441
791
  - [File Upload](docs/file-upload.md)
792
+ - [Storage and File Delivery](docs/storage.md)
793
+ - [S3-Compatible Storage](docs/s3-storage.md)
442
794
  - [Authentication](docs/authentication.md)
443
795
  - [Auth Route Guards](docs/auth-route-guards.md)
444
796
  - [JWT Sessions](docs/session-auth.md)
@@ -447,17 +799,50 @@ After RC passes, releases are tagged and published manually with the guarded rel
447
799
  - [Middleware](docs/middleware.md)
448
800
  - [Hydration](docs/hydration.md)
449
801
  - [Developer Tools](docs/developer-tools.md)
450
- - [Development Logging](docs/development-logging.md)
802
+ - [Logging and Observability](docs/development-logging.md)
451
803
  - [Caching](docs/caching.md)
452
804
  - [Security](docs/security.md)
453
805
  - [Deployment](docs/deployment.md)
454
806
  - [Updating](docs/updating.md)
455
807
  - [Releasing](docs/releasing.md)
456
808
 
457
- ## Requirements
809
+ Recommended `bcp-docs-web` top-level navigation:
810
+
811
+ ```text
812
+ Getting Started
813
+ Routing & Data
814
+ Authentication
815
+ Database
816
+ Runtime & Infrastructure
817
+ Storage & Uploads
818
+ API Reference
819
+ Releases
820
+ ```
821
+
822
+ ## Release history
823
+
824
+ Release notes live under `docs/releases/`.
825
+
826
+ | Version | Milestone |
827
+ | --- | --- |
828
+ | `0.1.20` | Hydration line-ending stabilization |
829
+ | `0.1.21` | Hydration semantic parity |
830
+ | `0.1.22` | Developer tools and diagnostics |
831
+ | `0.1.23` | Logging and observability |
832
+ | `0.1.24` | File Upload Foundation |
833
+ | `0.1.25` | Storage Adapters and File Delivery |
834
+ | `0.1.26` | S3-Compatible Storage and Production Streaming |
835
+
836
+ ## Next direction
837
+
838
+ After `0.1.26`, the recommended direction is:
839
+
840
+ 1. signed storage URLs where needed,
841
+ 2. object listing/copy/move capabilities,
842
+ 3. broader production hardening and graceful shutdown,
843
+ 4. stronger storage/provider diagnostics.
458
844
 
459
- - Node.js 24.11 or newer
460
- - React 19
845
+ These are roadmap items, not `0.1.26` API guarantees.
461
846
 
462
847
  ## License
463
848