@chidchanun/bcp 0.1.26 → 0.1.28

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,52 +1,16 @@
1
1
  # BCP Framework
2
2
 
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.
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 and standalone production deployment.
4
4
 
5
- > **Release candidate target:** `0.1.26`
5
+ > **Development target:** `0.1.28`
6
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
- ```
7
+ > BCP is pre-1.0. The `0.1.28` source adds Production Hardening and remains an unreleased development target until local validation, RC checks, tagging and npm publication complete.
44
8
 
45
9
  ## Current capabilities
46
10
 
47
11
  | Area | Capability |
48
12
  | --- | --- |
49
- | Application | React SSR, hydration, layouts, metadata, SPA navigation |
13
+ | Application | React SSR, hydration, layouts, metadata and SPA navigation |
50
14
  | Routing | Static, dynamic, catch-all, optional catch-all and route groups |
51
15
  | Server data | `loader.ts`, request-scoped server APIs |
52
16
  | Mutations | Route-owned `actions.ts` and `<Form>` |
@@ -58,10 +22,10 @@ app/
58
22
  | Database | MySQL pool/query helpers, transactions and migrations |
59
23
  | Logging | Structured logger, request logger and request IDs |
60
24
  | Uploads | Buffered multipart helpers and production multipart streaming |
61
- | Storage | Local + S3-compatible adapters, streaming I/O and ranged delivery |
25
+ | Storage | Local + S3-compatible adapters, streaming, listing, copy/move, metadata, bulk delete and signed S3 URLs |
62
26
  | Caching | Response cache and revalidation primitives |
63
27
  | Developer tools | `doctor`, `inspect`, updater and route inspection |
64
- | Production | Standalone server build with production middleware pipeline |
28
+ | Production | Standalone build, hardening gateway, graceful shutdown, trusted-proxy controls and HTTP timeouts |
65
29
 
66
30
  ## Requirements
67
31
 
@@ -79,16 +43,13 @@ cd my-app
79
43
  npm run dev
80
44
  ```
81
45
 
82
- Default development URL:
83
-
84
- ```text
85
- http://localhost:3000
86
- ```
87
-
88
- Generated projects normally include:
46
+ Generated projects normally use the application dependency key `bcp`:
89
47
 
90
48
  ```json
91
49
  {
50
+ "dependencies": {
51
+ "bcp": "npm:@chidchanun/bcp@latest"
52
+ },
92
53
  "scripts": {
93
54
  "dev": "bcp dev",
94
55
  "build": "bcp build",
@@ -100,68 +61,45 @@ Generated projects normally include:
100
61
  }
101
62
  ```
102
63
 
103
- ## Packages
64
+ Keep only one framework dependency named `bcp`. Installing both `bcp` and `@chidchanun/bcp` directly can load duplicate framework/React contexts.
104
65
 
105
- The public framework package is published as:
66
+ ## Application model
106
67
 
107
68
  ```text
108
- @chidchanun/bcp
109
- ```
110
-
111
- Applications normally consume it through the dependency key `bcp`, keeping imports concise:
112
-
113
- ```ts
114
- import {
115
- Form,
116
- Link,
117
- useLoaderData,
118
- } from "bcp";
119
- ```
120
-
121
- Server-only APIs use dedicated entrypoints:
122
-
123
- ```ts
124
- import {
125
- cookies,
126
- logger,
127
- requestId,
128
- } from "bcp/server";
69
+ Browser
70
+
71
+ BCP security / middleware / cache
72
+
73
+ Route guard
74
+
75
+ Loader / action / API route
76
+
77
+ React SSR
78
+
79
+ Hydration / SPA navigation
129
80
  ```
130
81
 
131
- ## Project structure
82
+ A route can keep page, loader, guard and actions together:
132
83
 
133
84
  ```text
134
85
  app/
135
86
  ├─ layout.tsx
136
87
  ├─ page.tsx
137
- ├─ login/
138
- │ └─ page.tsx
139
88
  ├─ dashboard/
140
89
  │ ├─ guard.ts
141
- │ ├─ page.tsx
142
90
  │ └─ users/
143
91
  │ └─ [id]/
144
92
  │ ├─ loader.ts
145
93
  │ ├─ actions.ts
146
94
  │ └─ page.tsx
147
95
  └─ api/
148
- ├─ auth/
149
- │ └─ login/
150
- │ └─ route.ts
151
96
  └─ upload/
152
97
  └─ route.ts
153
-
154
- lib/
155
- public/
156
- migrations/
157
- bcp.config.ts
158
- package.json
159
- tsconfig.json
160
98
  ```
161
99
 
162
100
  ## Routing
163
101
 
164
- Page routes are discovered from `app/**/page.tsx`:
102
+ Page routes are discovered from `app/**/page.tsx` and API routes from `app/**/route.ts`.
165
103
 
166
104
  ```text
167
105
  app/page.tsx /
@@ -170,65 +108,16 @@ app/users/[id]/page.tsx /users/:id
170
108
  app/docs/[...slug]/page.tsx /docs/*
171
109
  app/catalog/[[...slug]]/page.tsx /catalog and /catalog/*
172
110
  app/(admin)/settings/page.tsx /settings
173
- ```
174
111
 
175
- Static routes have priority over dynamic and catch-all routes.
176
-
177
- API routes use `route.ts`:
178
-
179
- ```text
180
- app/api/users/route.ts /api/users
181
- app/api/users/[id]/route.ts /api/users/:id
112
+ app/api/users/route.ts /api/users
113
+ app/api/users/[id]/route.ts /api/users/:id
182
114
  ```
183
115
 
184
116
  Read more: [Routing](docs/routing.md)
185
117
 
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:
195
-
196
- ```ts
197
- // app/users/[id]/loader.ts
198
- export async function loader({
199
- params,
200
- }) {
201
- return {
202
- id:
203
- params.id,
204
- };
205
- }
206
- ```
207
-
208
- Consume serializable loader data from a client page:
209
-
210
- ```tsx
211
- "use client";
212
-
213
- import {
214
- useLoaderData,
215
- } from "bcp";
216
-
217
- export default function UserPage() {
218
- const data =
219
- useLoaderData<{
220
- id: string;
221
- }>();
222
-
223
- return <main>User {data.id}</main>;
224
- }
225
- ```
226
-
227
- Read more: [Server Data Loaders](docs/server-data-loaders.md)
118
+ ## Server data, guards and actions
228
119
 
229
- ## Route guards
230
-
231
- A route tree can define `guard.ts` to authorize access before rendering:
120
+ Server loaders live next to their route in `loader.ts`. Route authorization can be defined in `guard.ts`, while route-owned mutations live in `actions.ts`.
232
121
 
233
122
  ```ts
234
123
  import {
@@ -239,40 +128,14 @@ export const guard =
239
128
  requireRole("admin");
240
129
  ```
241
130
 
242
- The standalone production pipeline preserves the same active request context used by authentication and server request APIs.
243
-
244
131
  Read more:
245
132
 
133
+ - [Server Data Loaders](docs/server-data-loaders.md)
246
134
  - [Route Guards](docs/route-guards.md)
247
135
  - [Auth Route Guards](docs/auth-route-guards.md)
136
+ - [Form Actions](docs/form-actions.md)
248
137
 
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)
254
-
255
- ## Server request APIs
256
-
257
- ```ts
258
- import {
259
- bearerToken,
260
- clientIp,
261
- cookies,
262
- headers,
263
- requestId,
264
- requestMethod,
265
- requestUrl,
266
- } from "bcp/server";
267
- ```
268
-
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:
138
+ ## Authentication and server APIs
276
139
 
277
140
  ```ts
278
141
  import {
@@ -280,89 +143,23 @@ import {
280
143
  requireAuth,
281
144
  requireRole,
282
145
  } from "bcp/auth";
283
- ```
284
146
 
285
- Lower-level JWT cookie session primitives:
286
-
287
- ```ts
288
147
  import {
289
- createSession,
290
- createSessionToken,
291
- destroySession,
292
- getSession,
293
- verifySessionToken,
148
+ cookies,
149
+ headers,
150
+ requestId,
151
+ requestMethod,
152
+ requestUrl,
294
153
  } from "bcp/server";
295
154
  ```
296
155
 
297
- Authentication is separated from application-specific credential lookup so projects can connect their own user table or identity provider.
156
+ BCP also exposes lower-level JWT cookie session primitives through `bcp/server`.
298
157
 
299
158
  Read more:
300
159
 
301
160
  - [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.
327
-
328
- Read more: [Middleware](docs/middleware.md)
329
-
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)
161
+ - [JWT Sessions](docs/session-auth.md)
162
+ - [Server Request APIs](docs/server-request-apis.md)
366
163
 
367
164
  ## Database
368
165
 
@@ -372,7 +169,7 @@ import {
372
169
  } from "bcp/database";
373
170
  ```
374
171
 
375
- The database layer provides a lazy MySQL pool, prepared execution, query helpers, transactions and migrations.
172
+ The database layer provides lazy MySQL pool creation, prepared execution, query helpers, transactions and migrations.
376
173
 
377
174
  ```bash
378
175
  bcp db create create_users
@@ -386,71 +183,9 @@ Read more:
386
183
  - [Database](docs/database.md)
387
184
  - [Database Migrations](docs/database-migrations.md)
388
185
 
389
- ## Logging and observability
390
-
391
- ```ts
392
- import {
393
- logger,
394
- requestLogger,
395
- } from "bcp/server";
396
-
397
- logger.info(
398
- "Application event",
399
- {
400
- feature:
401
- "catalog",
402
- }
403
- );
404
- ```
405
-
406
- Environment controls:
407
-
408
- ```env
409
- BCP_LOG_LEVEL=debug
410
- BCP_LOG_FORMAT=json
411
- ```
412
-
413
- Supported levels are `debug`, `info`, `warn`, `error` and `silent`. Formats are `pretty` and `json`.
414
-
415
- Read more: [Logging and Observability](docs/development-logging.md)
416
-
417
- ## File uploads
418
-
419
- BCP keeps the buffered multipart API for small forms:
420
-
421
- ```ts
422
- import {
423
- parseMultipartFormData,
424
- requireUploadedFile,
425
- saveUploadedFile,
426
- } from "bcp/server";
427
-
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
- ```
186
+ ## Uploads and streaming
452
187
 
453
- BCP `0.1.26` adds direct multipart-to-storage streaming for larger production uploads:
188
+ BCP supports the original buffered multipart helpers as well as production multipart-to-storage streaming:
454
189
 
455
190
  ```ts
456
191
  import {
@@ -462,35 +197,24 @@ const stored =
462
197
  request,
463
198
  {
464
199
  storage,
465
- fieldName:
466
- "file",
467
- key:
468
- "documents/report.pdf",
469
- maxBytes:
470
- 100 * 1024 * 1024,
200
+ fieldName: "file",
201
+ key: "documents/report.pdf",
202
+ maxBytes: 100 * 1024 * 1024,
471
203
  constraints: {
472
- maxBytes:
473
- 80 * 1024 * 1024,
204
+ maxBytes: 80 * 1024 * 1024,
474
205
  allowedTypes: [
475
206
  "application/pdf",
476
207
  ],
477
- allowedExtensions: [
478
- ".pdf",
479
- ],
480
208
  },
481
209
  }
482
210
  );
483
211
  ```
484
212
 
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.
488
-
489
- MIME type and extension validation are metadata checks, not content-signature verification.
213
+ `storeMultipartFile()` consumes `Request.body` incrementally and streams the selected file directly into storage. Request/body infrastructure limits still apply.
490
214
 
491
215
  Read more: [File Upload](docs/file-upload.md)
492
216
 
493
- ## Storage adapters
217
+ ## Storage
494
218
 
495
219
  ### Local filesystem
496
220
 
@@ -501,14 +225,13 @@ import {
501
225
 
502
226
  const storage =
503
227
  createLocalStorage({
504
- directory:
505
- "./uploads",
228
+ directory: "./uploads",
506
229
  });
507
230
  ```
508
231
 
509
- ### S3-compatible storage
232
+ `create-bcp-app --storage local` creates `lib/storage.ts` plus a visible `storage/README.md` / `.gitkeep` scaffold. Runtime objects remain ignored by Git.
510
233
 
511
- BCP `0.1.26` adds an S3-compatible backend:
234
+ ### S3 / R2 / MinIO
512
235
 
513
236
  ```ts
514
237
  import {
@@ -517,40 +240,21 @@ import {
517
240
 
518
241
  const storage =
519
242
  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,
243
+ bucket: process.env.S3_BUCKET!,
244
+ region: process.env.S3_REGION!,
245
+ endpoint: process.env.S3_ENDPOINT,
246
+ accessKeyId: process.env.S3_ACCESS_KEY_ID,
247
+ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
530
248
  });
531
249
  ```
532
250
 
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.
534
-
535
- Keep cloud credentials server-only. Never expose them through `BCP_PUBLIC_*` variables.
251
+ Custom endpoints and `forcePathStyle` support common S3-compatible deployments such as MinIO. Keep credentials server-only.
536
252
 
537
253
  Read more: [S3-Compatible Storage](docs/s3-storage.md)
538
254
 
539
255
  ### Streaming storage
540
256
 
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:
257
+ The stable minimum `StorageAdapter` retains its buffered API while adapters can expose optional `putStream()` and `readStream()` implementations.
554
258
 
555
259
  ```ts
556
260
  import {
@@ -560,109 +264,122 @@ import {
560
264
  } from "bcp/server";
561
265
  ```
562
266
 
563
- Both built-in `0.1.26` adapters support native streaming reads, streaming writes and byte ranges.
564
-
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.
267
+ Both built-in local and S3 adapters support streaming reads/writes and byte ranges.
566
268
 
567
269
  Read more: [Storage and File Delivery](docs/storage.md)
568
270
 
569
- ## Production file delivery
271
+ ### Storage Ecosystem — 0.1.27
272
+
273
+ BCP `0.1.27` adds a richer, additive object-storage API without invalidating older `StorageAdapter` implementations:
570
274
 
571
275
  ```ts
572
276
  import {
573
- createStorageResponse,
277
+ copyStorageObject,
278
+ createStorageSignedReadUrl,
279
+ createStorageSignedWriteUrl,
280
+ deleteStorageObjects,
281
+ getStorageEcosystemCapabilities,
282
+ getStorageMetadata,
283
+ listStorageObjects,
284
+ moveStorageObject,
285
+ setStorageMetadata,
574
286
  } from "bcp/server";
575
-
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
- }
591
287
  ```
592
288
 
593
- `createStorageResponse()` uses storage streaming and supports:
289
+ Listing supports prefix filtering, limits and opaque cursors. Copy and move use native adapter operations when available, with portable fallback behavior where practical. Portable user metadata is string-to-string metadata and is distinct from authorization/business state.
594
290
 
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.
291
+ S3-compatible storage also supports short-lived presigned direct-transfer URLs. Local storage intentionally does not emulate signed URLs.
603
292
 
604
- The default cache policy remains:
293
+ Read more: [Storage Ecosystem](docs/storage-ecosystem.md)
605
294
 
606
- ```text
607
- private, max-age=0, must-revalidate
608
- ```
295
+ ## File delivery
609
296
 
610
- Multiple byte ranges remain intentionally unsupported in `0.1.26`.
297
+ `createStorageResponse()` serves local or cloud-backed objects through the same API with `GET`, `HEAD`, ETag/Last-Modified validators and single byte ranges.
611
298
 
612
- Read more: [Storage and File Delivery](docs/storage.md)
299
+ ```ts
300
+ import {
301
+ createStorageResponse,
302
+ } from "bcp/server";
613
303
 
614
- ## Caching
304
+ return createStorageResponse(
305
+ request,
306
+ storage,
307
+ "documents/report.pdf"
308
+ );
309
+ ```
615
310
 
616
- BCP includes response caching and revalidation primitives used by development and standalone production runtimes.
311
+ Read more: [Storage and File Delivery](docs/storage.md)
617
312
 
618
- Read more: [Caching](docs/caching.md)
313
+ ## Middleware, validation, errors and caching
619
314
 
620
- ## Security
315
+ BCP includes Middleware System v2, typed validation helpers, structured HTTP errors, structured logging and response caching/revalidation.
621
316
 
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.
317
+ Read more:
623
318
 
624
- Storage keys, filenames and MIME metadata must not be treated as authorization decisions.
319
+ - [Middleware](docs/middleware.md)
320
+ - [Validation](docs/validation.md)
321
+ - [Error Handling](docs/error-handling.md)
322
+ - [Logging and Observability](docs/development-logging.md)
323
+ - [Caching](docs/caching.md)
324
+ - [Security](docs/security.md)
625
325
 
626
- Read more: [Security](docs/security.md)
326
+ ## Production build
627
327
 
628
- ## Environment and configuration
328
+ ```bash
329
+ npm run build
330
+ npm run start
331
+ ```
629
332
 
630
- Application configuration lives in:
333
+ Standalone output is written under:
631
334
 
632
335
  ```text
633
- bcp.config.ts
336
+ .bcp-framework/build/
337
+ ├─ client/
338
+ ├─ public/
339
+ └─ server/
340
+ └─ server.mjs
634
341
  ```
635
342
 
636
- Public environment variables use:
343
+ ### Production Hardening — 0.1.28
637
344
 
638
- ```text
639
- BCP_PUBLIC_
640
- ```
345
+ The standalone runtime is wrapped by a public hardening gateway with configurable HTTP and shutdown behavior:
641
346
 
642
- Server-only values remain server-side and are not emitted into browser bundles.
347
+ ```dotenv
348
+ BCP_REQUEST_TIMEOUT_MS=120000
349
+ BCP_HEADERS_TIMEOUT_MS=66000
350
+ BCP_KEEP_ALIVE_TIMEOUT_MS=65000
351
+ BCP_SHUTDOWN_TIMEOUT_MS=10000
352
+ BCP_TRUST_PROXY=false
353
+ ```
643
354
 
644
- Read more: [Configuration](docs/configuration.md)
355
+ Standalone production handles `SIGTERM` and `SIGINT`, drains the public listener, runs application cleanup hooks and then stops internal runtime layers.
645
356
 
646
- ## Developer tools
357
+ ```ts
358
+ import {
359
+ registerShutdownHook,
360
+ } from "bcp/server";
647
361
 
648
- ```bash
649
- bcp doctor
650
- bcp inspect
362
+ registerShutdownHook(
363
+ () => {
364
+ storage.destroy();
365
+ },
366
+ {
367
+ name: "storage",
368
+ }
369
+ );
651
370
  ```
652
371
 
653
- `bcp doctor` checks project structure, BCP/React installation parity, duplicate framework copies, environment/config loading, route conflicts and client/server boundaries.
372
+ Trusted proxy mode is disabled by default. Enable `BCP_TRUST_PROXY=true` only when direct untrusted traffic cannot bypass the trusted reverse proxy/load balancer.
654
373
 
655
- `bcp inspect` reports resolved configuration, environment sources, dependency versions and discovered routes.
656
-
657
- Read more: [Developer Tools](docs/developer-tools.md)
374
+ Read more: [Production Hardening](docs/production-hardening.md)
658
375
 
659
376
  ## Windows CLI
660
377
 
661
- Microsoft SQL Server can install another executable named `bcp.exe`. BCP therefore publishes the collision-free alias `bcp-framework`.
378
+ Microsoft SQL Server can install another executable named `bcp.exe`. BCP publishes the collision-free alias `bcp-framework`.
662
379
 
663
- Inside npm scripts, `bcp` is safe because npm prepends the project's `node_modules/.bin` to `PATH`.
380
+ Inside project npm scripts, `bcp` is safe because npm prepends `node_modules/.bin` to `PATH`.
664
381
 
665
- For direct PowerShell usage, use the project-local CLI:
382
+ For direct PowerShell usage:
666
383
 
667
384
  ```powershell
668
385
  npm exec -- bcp-framework --version
@@ -673,62 +390,7 @@ npm exec -- bcp-framework dev
673
390
  npm exec -- bcp-framework build
674
391
  ```
675
392
 
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
696
- ```
697
-
698
- ## Development behavior
699
-
700
- BCP includes Fast Refresh and deterministic development hydration behavior. Recent stabilization work covers:
701
-
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.
707
-
708
- Read more: [Hydration](docs/hydration.md)
709
-
710
- ## Production build
711
-
712
- ```bash
713
- npm run build
714
- npm run start
715
- ```
716
-
717
- Production output:
718
-
719
- ```text
720
- .bcp-framework/build/
721
- ├─ client/
722
- ├─ public/
723
- └─ server/
724
- └─ server.mjs
725
- ```
726
-
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)
393
+ Read more: [Developer Tools](docs/developer-tools.md)
732
394
 
733
395
  ## Updating BCP
734
396
 
@@ -736,22 +398,14 @@ Read more: [Deployment](docs/deployment.md)
736
398
  bcp update
737
399
  bcp update --check
738
400
  bcp update --dry-run
739
- bcp update 0.1.26
401
+ bcp update 0.1.28
740
402
  bcp update next
741
403
  ```
742
404
 
743
- Projects created before the updater was introduced can bootstrap it once with:
744
-
745
- ```bash
746
- npx @chidchanun/bcp@latest update
747
- ```
748
-
749
405
  Read more: [Updating](docs/updating.md)
750
406
 
751
407
  ## Framework development and release validation
752
408
 
753
- Inside the BCP Framework repository:
754
-
755
409
  ```bash
756
410
  npm install
757
411
  npm run typecheck
@@ -759,70 +413,41 @@ npm run test:unit
759
413
  npm run test:integration
760
414
  npm run test:e2e
761
415
  npm run test:package
762
- ```
763
-
764
- Full release-candidate validation:
765
-
766
- ```bash
767
416
  npm run rc:check
768
417
  ```
769
418
 
770
- A version must not be tagged or published until RC and packed-package verification pass.
419
+ A version must not be tagged or published until its RC and packed-package verification pass.
771
420
 
772
421
  Read more: [Releasing](docs/releasing.md)
773
422
 
774
423
  ## Documentation source
775
424
 
776
- The `docs/` directory is the source content for the future **`bcp-docs-web`** documentation website.
425
+ The `docs/` directory is the authored source for **`bcp-docs-web`**.
777
426
 
778
- Start with:
427
+ Recommended starting points:
779
428
 
780
429
  - [Documentation Source Map](docs/README.md)
781
430
  - [Getting Started](docs/getting-started.md)
782
431
  - [Configuration](docs/configuration.md)
783
- - [Application Modules](docs/application-modules.md)
784
432
  - [Routing](docs/routing.md)
785
433
  - [Server Data Loaders](docs/server-data-loaders.md)
786
434
  - [Route Guards](docs/route-guards.md)
787
435
  - [Form Actions](docs/form-actions.md)
788
436
  - [Server Request APIs](docs/server-request-apis.md)
789
- - [Validation](docs/validation.md)
790
- - [Error Handling](docs/error-handling.md)
791
437
  - [File Upload](docs/file-upload.md)
792
438
  - [Storage and File Delivery](docs/storage.md)
439
+ - [Storage Ecosystem](docs/storage-ecosystem.md)
793
440
  - [S3-Compatible Storage](docs/s3-storage.md)
441
+ - [Production Hardening](docs/production-hardening.md)
794
442
  - [Authentication](docs/authentication.md)
795
- - [Auth Route Guards](docs/auth-route-guards.md)
796
- - [JWT Sessions](docs/session-auth.md)
797
443
  - [Database](docs/database.md)
798
- - [Database Migrations](docs/database-migrations.md)
799
444
  - [Middleware](docs/middleware.md)
800
- - [Hydration](docs/hydration.md)
801
445
  - [Developer Tools](docs/developer-tools.md)
802
- - [Logging and Observability](docs/development-logging.md)
803
- - [Caching](docs/caching.md)
804
- - [Security](docs/security.md)
805
446
  - [Deployment](docs/deployment.md)
806
- - [Updating](docs/updating.md)
807
447
  - [Releasing](docs/releasing.md)
808
448
 
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
449
  ## Release history
823
450
 
824
- Release notes live under `docs/releases/`.
825
-
826
451
  | Version | Milestone |
827
452
  | --- | --- |
828
453
  | `0.1.20` | Hydration line-ending stabilization |
@@ -832,17 +457,20 @@ Release notes live under `docs/releases/`.
832
457
  | `0.1.24` | File Upload Foundation |
833
458
  | `0.1.25` | Storage Adapters and File Delivery |
834
459
  | `0.1.26` | S3-Compatible Storage and Production Streaming |
460
+ | `0.1.27` | Storage Ecosystem |
461
+ | `0.1.28` | Production Hardening |
835
462
 
836
463
  ## Next direction
837
464
 
838
- After `0.1.26`, the recommended direction is:
465
+ After `0.1.28`, the planned milestone is **`0.1.29 — Developer Experience`**:
839
466
 
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.
467
+ 1. route/API/middleware/migration generators,
468
+ 2. richer `doctor` and `inspect` diagnostics,
469
+ 3. clearer build/runtime error messages,
470
+ 4. improved create-app presets and automation flags,
471
+ 5. production configuration diagnostics.
844
472
 
845
- These are roadmap items, not `0.1.26` API guarantees.
473
+ These are roadmap items, not `0.1.28` guarantees.
846
474
 
847
475
  ## License
848
476