@chidchanun/bcp 0.1.25 → 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,19 +1,19 @@
1
1
  # BCP Framework
2
2
 
3
- BCP Framework is a React full-stack framework focused on file-based routing, server rendering, server-side data loading, guarded application flows, API routes, authentication, database access, validation, logging, file 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 adapters and standalone production deployment.
4
4
 
5
- > **Development target:** `0.1.25`
5
+ > **Release candidate target:** `0.1.26`
6
6
  >
7
- > BCP is still pre-1.0. Features documented for the current development target should not be presented as published npm behavior until the release candidate has passed and the matching version has been published.
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
8
 
9
9
  ## Overview
10
10
 
11
- BCP provides a single application model for React pages and server code:
11
+ BCP keeps React pages and their server behavior close to the route that owns them:
12
12
 
13
13
  ```text
14
14
  Browser
15
15
 
16
- BCP middleware / security
16
+ BCP security / middleware / cache
17
17
 
18
18
  Route guard
19
19
 
@@ -24,7 +24,7 @@ React SSR
24
24
  Hydration / SPA navigation
25
25
  ```
26
26
 
27
- The framework is designed so application code can stay close to the route that owns it:
27
+ A typical route can colocate its page, loader, guard and actions:
28
28
 
29
29
  ```text
30
30
  app/
@@ -57,8 +57,8 @@ app/
57
57
  | Error handling | HTTP error helpers and consistent error responses |
58
58
  | Database | MySQL pool/query helpers, transactions and migrations |
59
59
  | Logging | Structured logger, request logger and request IDs |
60
- | Uploads | Multipart parsing, file validation and safe local persistence |
61
- | Storage | `StorageAdapter`, local storage adapter and file delivery |
60
+ | Uploads | Buffered multipart helpers and production multipart streaming |
61
+ | Storage | Local + S3-compatible adapters, streaming I/O and ranged delivery |
62
62
  | Caching | Response cache and revalidation primitives |
63
63
  | Developer tools | `doctor`, `inspect`, updater and route inspection |
64
64
  | Production | Standalone server build with production middleware pipeline |
@@ -73,8 +73,6 @@ Database features currently target MySQL.
73
73
 
74
74
  ## Quick start
75
75
 
76
- Create a new application:
77
-
78
76
  ```bash
79
77
  npx create-bcp-app@latest my-app
80
78
  cd my-app
@@ -87,7 +85,7 @@ Default development URL:
87
85
  http://localhost:3000
88
86
  ```
89
87
 
90
- A generated project normally exposes scripts such as:
88
+ Generated projects normally include:
91
89
 
92
90
  ```json
93
91
  {
@@ -96,7 +94,8 @@ A generated project normally exposes scripts such as:
96
94
  "build": "bcp build",
97
95
  "start": "bcp start",
98
96
  "routes": "bcp routes",
99
- "update": "bcp update"
97
+ "update": "bcp update",
98
+ "typecheck": "tsc --noEmit"
100
99
  }
101
100
  }
102
101
  ```
@@ -109,13 +108,7 @@ The public framework package is published as:
109
108
  @chidchanun/bcp
110
109
  ```
111
110
 
112
- Applications normally consume it through the dependency key:
113
-
114
- ```text
115
- bcp
116
- ```
117
-
118
- This keeps imports concise:
111
+ Applications normally consume it through the dependency key `bcp`, keeping imports concise:
119
112
 
120
113
  ```ts
121
114
  import {
@@ -125,7 +118,7 @@ import {
125
118
  } from "bcp";
126
119
  ```
127
120
 
128
- Server-only APIs use dedicated entrypoints such as:
121
+ Server-only APIs use dedicated entrypoints:
129
122
 
130
123
  ```ts
131
124
  import {
@@ -137,8 +130,6 @@ import {
137
130
 
138
131
  ## Project structure
139
132
 
140
- A typical application can grow into this layout:
141
-
142
133
  ```text
143
134
  app/
144
135
  ├─ layout.tsx
@@ -168,11 +159,9 @@ package.json
168
159
  tsconfig.json
169
160
  ```
170
161
 
171
- BCP keeps page rendering, route authorization, server data and route mutations close together without requiring one large application router configuration file.
172
-
173
162
  ## Routing
174
163
 
175
- Page routes are discovered from `app/**/page.tsx`.
164
+ Page routes are discovered from `app/**/page.tsx`:
176
165
 
177
166
  ```text
178
167
  app/page.tsx /
@@ -196,15 +185,13 @@ Read more: [Routing](docs/routing.md)
196
185
 
197
186
  ## Layouts and metadata
198
187
 
199
- Routes can inherit layouts from parent directories. The framework resolves the layout chain while rendering both development and standalone production requests.
200
-
201
- Document metadata is route-aware and can be generated alongside the page tree.
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.
202
189
 
203
190
  Read more: [Routing](docs/routing.md)
204
191
 
205
192
  ## Server data loaders
206
193
 
207
- Place `loader.ts` next to a page when the route needs server-side data.
194
+ Place `loader.ts` next to a page when the route needs server-side data:
208
195
 
209
196
  ```ts
210
197
  // app/users/[id]/loader.ts
@@ -218,7 +205,7 @@ export async function loader({
218
205
  }
219
206
  ```
220
207
 
221
- Consume the serializable result in a client page:
208
+ Consume serializable loader data from a client page:
222
209
 
223
210
  ```tsx
224
211
  "use client";
@@ -233,11 +220,7 @@ export default function UserPage() {
233
220
  id: string;
234
221
  }>();
235
222
 
236
- return (
237
- <main>
238
- User {data.id}
239
- </main>
240
- );
223
+ return <main>User {data.id}</main>;
241
224
  }
242
225
  ```
243
226
 
@@ -245,9 +228,7 @@ Read more: [Server Data Loaders](docs/server-data-loaders.md)
245
228
 
246
229
  ## Route guards
247
230
 
248
- A route tree can define `guard.ts` to authorize access before the protected route is rendered.
249
-
250
- Authentication-aware guards are available through `bcp/auth`:
231
+ A route tree can define `guard.ts` to authorize access before rendering:
251
232
 
252
233
  ```ts
253
234
  import {
@@ -267,16 +248,12 @@ Read more:
267
248
 
268
249
  ## Form actions
269
250
 
270
- Route-owned mutations live in `actions.ts` and can be invoked through the public `<Form>` API.
271
-
272
- This supports both progressive form submission and SPA action transport while keeping mutation logic server-only.
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.
273
252
 
274
253
  Read more: [Form Actions](docs/form-actions.md)
275
254
 
276
255
  ## Server request APIs
277
256
 
278
- Request-scoped APIs are exposed through `bcp/server`:
279
-
280
257
  ```ts
281
258
  import {
282
259
  bearerToken,
@@ -289,13 +266,13 @@ import {
289
266
  } from "bcp/server";
290
267
  ```
291
268
 
292
- `requestId()` uses a valid incoming `X-Request-Id` when available or generates a stable UUID for the active request.
269
+ `requestId()` accepts a valid incoming `X-Request-Id` or generates a stable UUID for the active request.
293
270
 
294
271
  Read more: [Server Request APIs](docs/server-request-apis.md)
295
272
 
296
273
  ## Authentication and sessions
297
274
 
298
- High-level authentication helpers are available through:
275
+ High-level authentication helpers:
299
276
 
300
277
  ```ts
301
278
  import {
@@ -305,7 +282,7 @@ import {
305
282
  } from "bcp/auth";
306
283
  ```
307
284
 
308
- Lower-level JWT cookie session primitives are available through `bcp/server`:
285
+ Lower-level JWT cookie session primitives:
309
286
 
310
287
  ```ts
311
288
  import {
@@ -317,7 +294,7 @@ import {
317
294
  } from "bcp/server";
318
295
  ```
319
296
 
320
- Authentication is intentionally separated from application-specific credential lookup so projects can connect their own user table or identity provider.
297
+ Authentication is separated from application-specific credential lookup so projects can connect their own user table or identity provider.
321
298
 
322
299
  Read more:
323
300
 
@@ -346,16 +323,12 @@ export async function middleware(
346
323
  }
347
324
  ```
348
325
 
349
- This allows middleware to run logic both before and after downstream route execution.
350
-
351
326
  Existing middleware v1 behavior remains supported for compatibility.
352
327
 
353
328
  Read more: [Middleware](docs/middleware.md)
354
329
 
355
330
  ## Validation
356
331
 
357
- BCP includes typed validation primitives:
358
-
359
332
  ```ts
360
333
  import {
361
334
  v,
@@ -363,14 +336,10 @@ import {
363
336
  } from "bcp/validation";
364
337
  ```
365
338
 
366
- Validation can be shared by API routes and form actions without coupling application schemas to the rendering layer.
367
-
368
339
  Read more: [Validation](docs/validation.md)
369
340
 
370
341
  ## Error handling
371
342
 
372
- Structured HTTP error helpers are exposed through `bcp/error`:
373
-
374
343
  ```ts
375
344
  import {
376
345
  badRequest,
@@ -397,23 +366,13 @@ Read more: [Error Handling](docs/error-handling.md)
397
366
 
398
367
  ## Database
399
368
 
400
- Database helpers are exposed through:
401
-
402
369
  ```ts
403
370
  import {
404
371
  db,
405
372
  } from "bcp/database";
406
373
  ```
407
374
 
408
- The database layer provides:
409
-
410
- - lazy MySQL pool creation,
411
- - prepared execution,
412
- - query helpers,
413
- - transactions,
414
- - migration status and rollback support.
415
-
416
- Migration commands:
375
+ The database layer provides a lazy MySQL pool, prepared execution, query helpers, transactions and migrations.
417
376
 
418
377
  ```bash
419
378
  bcp db create create_users
@@ -429,8 +388,6 @@ Read more:
429
388
 
430
389
  ## Logging and observability
431
390
 
432
- Structured server logging is available through `bcp/server`:
433
-
434
391
  ```ts
435
392
  import {
436
393
  logger,
@@ -446,26 +403,6 @@ logger.info(
446
403
  );
447
404
  ```
448
405
 
449
- Request-scoped logging can automatically include request identity:
450
-
451
- ```ts
452
- export async function loader() {
453
- const log =
454
- await requestLogger({
455
- feature:
456
- "categories",
457
- });
458
-
459
- log.info(
460
- "Loading categories"
461
- );
462
-
463
- return {
464
- items: [],
465
- };
466
- }
467
- ```
468
-
469
406
  Environment controls:
470
407
 
471
408
  ```env
@@ -473,28 +410,13 @@ BCP_LOG_LEVEL=debug
473
410
  BCP_LOG_FORMAT=json
474
411
  ```
475
412
 
476
- Supported levels:
477
-
478
- ```text
479
- debug
480
- info
481
- warn
482
- error
483
- silent
484
- ```
485
-
486
- Supported formats:
487
-
488
- ```text
489
- pretty
490
- json
491
- ```
413
+ Supported levels are `debug`, `info`, `warn`, `error` and `silent`. Formats are `pretty` and `json`.
492
414
 
493
415
  Read more: [Logging and Observability](docs/development-logging.md)
494
416
 
495
- ## File upload
417
+ ## File uploads
496
418
 
497
- BCP `0.1.24` introduced multipart parsing and file validation:
419
+ BCP keeps the buffered multipart API for small forms:
498
420
 
499
421
  ```ts
500
422
  import {
@@ -503,90 +425,78 @@ import {
503
425
  saveUploadedFile,
504
426
  } from "bcp/server";
505
427
 
506
- export async function POST(
507
- request: Request
508
- ) {
509
- const formData =
510
- await parseMultipartFormData(
511
- request,
512
- {
513
- maxBytes:
514
- 8 * 1024 * 1024,
515
- }
516
- );
517
-
518
- const file =
519
- requireUploadedFile(
520
- formData,
521
- "file",
522
- {
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: {
523
472
  maxBytes:
524
- 5 * 1024 * 1024,
473
+ 80 * 1024 * 1024,
525
474
  allowedTypes: [
526
- "image/png",
527
- "image/jpeg",
528
- "image/webp",
475
+ "application/pdf",
529
476
  ],
530
477
  allowedExtensions: [
531
- ".png",
532
- ".jpg",
533
- ".jpeg",
534
- ".webp",
478
+ ".pdf",
535
479
  ],
536
- }
537
- );
538
-
539
- return Response.json(
540
- await saveUploadedFile(
541
- file,
542
- {
543
- directory:
544
- "./uploads",
545
- }
546
- )
480
+ },
481
+ }
547
482
  );
548
- }
549
483
  ```
550
484
 
551
- Upload helpers provide:
552
-
553
- - multipart validation,
554
- - total request and per-file size limits,
555
- - MIME and extension allowlists,
556
- - required/optional file fields,
557
- - safe UUID-based storage names,
558
- - filename sanitization,
559
- - path traversal protection,
560
- - no-overwrite-by-default persistence,
561
- - SHA-256 checksum metadata.
562
-
563
- The security gateway applies `server.bodyLimit` / `BCP_BODY_LIMIT` before application upload parsing. Applications accepting larger files must raise that outer limit explicitly.
564
-
565
- ```ts
566
- import {
567
- defineConfig,
568
- } from "bcp/config";
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.
569
486
 
570
- export default defineConfig({
571
- server: {
572
- bodyLimit:
573
- 10 * 1024 * 1024,
574
- },
575
- });
576
- ```
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.
577
488
 
578
- MIME type and extension validation are metadata checks, not content-signature verification. Security-sensitive applications should additionally verify content and use malware scanning where appropriate.
489
+ MIME type and extension validation are metadata checks, not content-signature verification.
579
490
 
580
491
  Read more: [File Upload](docs/file-upload.md)
581
492
 
582
493
  ## Storage adapters
583
494
 
584
- BCP `0.1.25` adds the first application-facing storage abstraction.
495
+ ### Local filesystem
585
496
 
586
497
  ```ts
587
498
  import {
588
499
  createLocalStorage,
589
- storeUploadedFile,
590
500
  } from "bcp/server";
591
501
 
592
502
  const storage =
@@ -594,46 +504,76 @@ const storage =
594
504
  directory:
595
505
  "./uploads",
596
506
  });
507
+ ```
597
508
 
598
- const stored =
599
- await storeUploadedFile(
600
- file,
601
- {
602
- storage,
603
- key:
604
- "avatars/user-101.webp",
605
- }
606
- );
509
+ ### S3-compatible storage
510
+
511
+ BCP `0.1.26` adds an S3-compatible backend:
512
+
513
+ ```ts
514
+ import {
515
+ createS3Storage,
516
+ } from "bcp/server";
517
+
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
+ });
607
531
  ```
608
532
 
609
- The `StorageAdapter` contract contains:
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.
536
+
537
+ Read more: [S3-Compatible Storage](docs/s3-storage.md)
538
+
539
+ ### Streaming storage
540
+
541
+ The `StorageAdapter` contract keeps its original buffered methods and adds optional streaming capabilities:
610
542
 
611
543
  ```text
612
544
  put
545
+ putStream? ← 0.1.26
613
546
  stat
614
547
  read
548
+ readStream? ← 0.1.26
615
549
  exists
616
550
  delete
617
551
  ```
618
552
 
619
- Application code can depend on this contract instead of depending directly on filesystem paths.
553
+ Use generic helpers so legacy and native-streaming adapters can share application code:
620
554
 
621
- The built-in adapter in `0.1.25` is local filesystem storage. Cloud/object-storage adapters are planned for a later milestone.
555
+ ```ts
556
+ import {
557
+ getStorageCapabilities,
558
+ putStorageStream,
559
+ readStorageStream,
560
+ } from "bcp/server";
561
+ ```
562
+
563
+ Both built-in `0.1.26` adapters support native streaming reads, streaming writes and byte ranges.
622
564
 
623
- Storage keys are logical relative paths. Absolute paths and traversal segments are rejected.
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.
624
566
 
625
567
  Read more: [Storage and File Delivery](docs/storage.md)
626
568
 
627
569
  ## Production file delivery
628
570
 
629
- Storage objects can be returned through a hardened HTTP response helper:
630
-
631
571
  ```ts
632
572
  import {
633
573
  createStorageResponse,
634
574
  } from "bcp/server";
635
575
 
636
- export async function GET(
576
+ export function GET(
637
577
  request: Request
638
578
  ) {
639
579
  return createStorageResponse(
@@ -650,41 +590,36 @@ export async function GET(
650
590
  }
651
591
  ```
652
592
 
653
- `createStorageResponse()` supports:
593
+ `createStorageResponse()` uses storage streaming and supports:
654
594
 
655
- - `GET`,
656
- - `HEAD`,
657
- - `ETag`,
658
- - `Last-Modified`,
659
- - `If-None-Match`,
660
- - `If-Modified-Since`,
595
+ - `GET` / `HEAD`,
596
+ - ETag / Last-Modified validators,
661
597
  - `If-Range`,
662
598
  - single byte ranges with `206 Partial Content`,
663
599
  - `304 Not Modified`,
664
600
  - `416 Range Not Satisfiable`,
665
- - safe `Content-Disposition` filenames.
601
+ - safe `Content-Disposition` filenames,
602
+ - configurable cache control.
666
603
 
667
- The default cache policy is intentionally conservative:
604
+ The default cache policy remains:
668
605
 
669
606
  ```text
670
607
  private, max-age=0, must-revalidate
671
608
  ```
672
609
 
673
- Public immutable caching must be opted into explicitly.
674
-
675
- Multiple byte ranges are intentionally not supported in `0.1.25`.
610
+ Multiple byte ranges remain intentionally unsupported in `0.1.26`.
676
611
 
677
612
  Read more: [Storage and File Delivery](docs/storage.md)
678
613
 
679
614
  ## Caching
680
615
 
681
- BCP includes server response caching and revalidation primitives used by development and standalone production runtimes.
616
+ BCP includes response caching and revalidation primitives used by development and standalone production runtimes.
682
617
 
683
618
  Read more: [Caching](docs/caching.md)
684
619
 
685
620
  ## Security
686
621
 
687
- The framework security layer includes request body limits and production request handling defaults. Application authorization is still the responsibility of route guards and application logic.
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.
688
623
 
689
624
  Storage keys, filenames and MIME metadata must not be treated as authorization decisions.
690
625
 
@@ -698,60 +633,48 @@ Application configuration lives in:
698
633
  bcp.config.ts
699
634
  ```
700
635
 
701
- Public environment variables use the prefix:
636
+ Public environment variables use:
702
637
 
703
638
  ```text
704
639
  BCP_PUBLIC_
705
640
  ```
706
641
 
707
- Server-only environment values remain server-side and are not emitted into browser bundles.
642
+ Server-only values remain server-side and are not emitted into browser bundles.
708
643
 
709
644
  Read more: [Configuration](docs/configuration.md)
710
645
 
711
646
  ## Developer tools
712
647
 
713
- BCP includes project diagnostics:
714
-
715
648
  ```bash
716
649
  bcp doctor
717
650
  bcp inspect
718
651
  ```
719
652
 
720
- `bcp doctor` checks areas such as:
653
+ `bcp doctor` checks project structure, BCP/React installation parity, duplicate framework copies, environment/config loading, route conflicts and client/server boundaries.
721
654
 
722
- - project structure,
723
- - BCP installation,
724
- - React / ReactDOM compatibility,
725
- - duplicate framework copies,
726
- - environment/config loading,
727
- - route conflicts,
728
- - client/server boundaries.
729
-
730
- `bcp inspect` reports resolved configuration, environment sources, dependencies and discovered routes.
655
+ `bcp inspect` reports resolved configuration, environment sources, dependency versions and discovered routes.
731
656
 
732
657
  Read more: [Developer Tools](docs/developer-tools.md)
733
658
 
734
659
  ## Windows CLI
735
660
 
736
- Microsoft SQL Server also installs an executable named `bcp.exe` on Windows.
737
-
738
- BCP therefore publishes the collision-free alias:
739
-
740
- ```text
741
- bcp-framework
742
- ```
661
+ Microsoft SQL Server can install another executable named `bcp.exe`. BCP therefore publishes the collision-free alias `bcp-framework`.
743
662
 
744
- Inside project npm scripts, `bcp` remains safe because npm puts `node_modules/.bin` at the front of `PATH`.
663
+ Inside npm scripts, `bcp` is safe because npm prepends the project's `node_modules/.bin` to `PATH`.
745
664
 
746
- For direct PowerShell usage, prefer:
665
+ For direct PowerShell usage, use the project-local CLI:
747
666
 
748
667
  ```powershell
668
+ npm exec -- bcp-framework --version
749
669
  npm exec -- bcp-framework doctor
750
670
  npm exec -- bcp-framework inspect
671
+ npm exec -- bcp-framework routes
751
672
  npm exec -- bcp-framework dev
752
673
  npm exec -- bcp-framework build
753
674
  ```
754
675
 
676
+ This keeps the CLI version aligned with the framework installed by the application.
677
+
755
678
  ## CLI reference
756
679
 
757
680
  ```bash
@@ -774,9 +697,7 @@ bcp db rollback
774
697
 
775
698
  ## Development behavior
776
699
 
777
- BCP includes Fast Refresh and deterministic development hydration behavior.
778
-
779
- Recent stabilization work also covers:
700
+ BCP includes Fast Refresh and deterministic development hydration behavior. Recent stabilization work covers:
780
701
 
781
702
  - Windows line-ending parity,
782
703
  - multiline JSX hydration parity,
@@ -784,25 +705,16 @@ Recent stabilization work also covers:
784
705
  - automatic page-route/client-bundle graph resynchronization,
785
706
  - standalone authentication guard request-context parity.
786
707
 
787
- A development topology change should no longer require manually deleting `.bcp-framework` to recover a missing client route bundle.
788
-
789
708
  Read more: [Hydration](docs/hydration.md)
790
709
 
791
710
  ## Production build
792
711
 
793
- Build an application:
794
-
795
712
  ```bash
796
713
  npm run build
797
- ```
798
-
799
- Start the generated standalone runtime:
800
-
801
- ```bash
802
714
  npm run start
803
715
  ```
804
716
 
805
- Production output is written under:
717
+ Production output:
806
718
 
807
719
  ```text
808
720
  .bcp-framework/build/
@@ -814,7 +726,7 @@ Production output is written under:
814
726
 
815
727
  The standalone runtime composes production middleware, security, cache, actions, guards, loaders and page rendering into the final HTTP pipeline.
816
728
 
817
- Runtime hostname/port overrides can be supplied to `bcp start` without rebuilding the application.
729
+ Runtime hostname/port overrides can be supplied to `bcp start` without rebuilding.
818
730
 
819
731
  Read more: [Deployment](docs/deployment.md)
820
732
 
@@ -824,11 +736,11 @@ Read more: [Deployment](docs/deployment.md)
824
736
  bcp update
825
737
  bcp update --check
826
738
  bcp update --dry-run
827
- bcp update 0.1.25
739
+ bcp update 0.1.26
828
740
  bcp update next
829
741
  ```
830
742
 
831
- Projects created before the updater was introduced can bootstrap it once using the public package:
743
+ Projects created before the updater was introduced can bootstrap it once with:
832
744
 
833
745
  ```bash
834
746
  npx @chidchanun/bcp@latest update
@@ -836,14 +748,15 @@ npx @chidchanun/bcp@latest update
836
748
 
837
749
  Read more: [Updating](docs/updating.md)
838
750
 
839
- ## Framework development
751
+ ## Framework development and release validation
840
752
 
841
- When working inside the BCP Framework repository itself:
753
+ Inside the BCP Framework repository:
842
754
 
843
755
  ```bash
844
756
  npm install
845
757
  npm run typecheck
846
758
  npm run test:unit
759
+ npm run test:integration
847
760
  npm run test:e2e
848
761
  npm run test:package
849
762
  ```
@@ -854,13 +767,13 @@ Full release-candidate validation:
854
767
  npm run rc:check
855
768
  ```
856
769
 
857
- A version must not be tagged or published until its release candidate and packed-package verification pass.
770
+ A version must not be tagged or published until RC and packed-package verification pass.
858
771
 
859
772
  Read more: [Releasing](docs/releasing.md)
860
773
 
861
774
  ## Documentation source
862
775
 
863
- The `docs/` directory is the source content intended to feed the future **`bcp-docs-web`** documentation website.
776
+ The `docs/` directory is the source content for the future **`bcp-docs-web`** documentation website.
864
777
 
865
778
  Start with:
866
779
 
@@ -877,6 +790,7 @@ Start with:
877
790
  - [Error Handling](docs/error-handling.md)
878
791
  - [File Upload](docs/file-upload.md)
879
792
  - [Storage and File Delivery](docs/storage.md)
793
+ - [S3-Compatible Storage](docs/s3-storage.md)
880
794
  - [Authentication](docs/authentication.md)
881
795
  - [Auth Route Guards](docs/auth-route-guards.md)
882
796
  - [JWT Sessions](docs/session-auth.md)
@@ -892,9 +806,7 @@ Start with:
892
806
  - [Updating](docs/updating.md)
893
807
  - [Releasing](docs/releasing.md)
894
808
 
895
- ## Documentation website model
896
-
897
- When `bcp-docs-web` is built, the recommended top-level information architecture is:
809
+ Recommended `bcp-docs-web` top-level navigation:
898
810
 
899
811
  ```text
900
812
  Getting Started
@@ -902,21 +814,14 @@ Routing & Data
902
814
  Authentication
903
815
  Database
904
816
  Runtime & Infrastructure
817
+ Storage & Uploads
905
818
  API Reference
906
819
  Releases
907
820
  ```
908
821
 
909
- `docs/README.md` contains the proposed route-to-source mapping for that website.
910
-
911
822
  ## Release history
912
823
 
913
- Release notes are stored under:
914
-
915
- ```text
916
- docs/releases/
917
- ```
918
-
919
- Recent milestones:
824
+ Release notes live under `docs/releases/`.
920
825
 
921
826
  | Version | Milestone |
922
827
  | --- | --- |
@@ -926,17 +831,18 @@ Recent milestones:
926
831
  | `0.1.23` | Logging and observability |
927
832
  | `0.1.24` | File Upload Foundation |
928
833
  | `0.1.25` | Storage Adapters and File Delivery |
834
+ | `0.1.26` | S3-Compatible Storage and Production Streaming |
929
835
 
930
- ## Roadmap
836
+ ## Next direction
931
837
 
932
- Current planned direction after `0.1.25`:
838
+ After `0.1.26`, the recommended direction is:
933
839
 
934
- 1. S3-compatible / cloud storage adapter integration.
935
- 2. Production upload streaming.
936
- 3. Broader storage adapter ecosystem.
937
- 4. Additional production hardening as new workloads expose edge cases.
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.
938
844
 
939
- Roadmap items are plans, not published API guarantees.
845
+ These are roadmap items, not `0.1.26` API guarantees.
940
846
 
941
847
  ## License
942
848