fr_acdd

Pure Dart annotations and extraction utilities for FlowR contract-first pages.

fr_acdd reads @FrAcddPage, @FrAcddDto, and @FrAcddField annotations from a Dart contract library, extracts a shared BFF analysis, and then renders the final artifact as either:

  • proto
  • json5 request/response snippets rendered inside a Markdown document (recommended output suffix: .md)

Recommended DTO preset:

@FrAcddDto(kind: FrAcddDtoKind.root)
@FrAcddFreezed
class NotificationsBootstrapBffRsp with _$NotificationsBootstrapBffRsp {
  const factory NotificationsBootstrapBffRsp({
    required String title,
  }) = _NotificationsBootstrapBffRsp;
}

Use XxxBffReq for every API request DTO, XxxBffRsp for every API response DTO, and XxxDto for transfer data used only inside those boundaries. Keep component state separate as XxxModel.

Use @FrAcddFreezed, @FrAcddFreezedJSON, or @Freezed(...) for extractable DTOs. Keep page-local state on non-DTO models without @FrAcddDto. When the page is scaffolded by fr-mvvm-contract, that usually means FlowR's exported @FrState preset; use @FrStateJson only when the state model truly needs fromJson(), and use plain @Freezed(...) when the state model holds runtime-only or non-JSON-serializable fields.

@FrAcddFreezed is the minimal extraction preset, not a claim that every DTO already crosses a runtime JSON boundary. It keeps fromJson/toJson disabled by default. If an extracted DTO also needs runtime JSON serialization, keep @FrAcddDto and prefer @FrAcddFreezedJSON. That preset still requires the usual generated factory Xxx.fromJson(...) plus a .g.dart part in the owning contract library. Use explicit @Freezed(...) only when you need JSON serialization with custom Freezed options beyond the preset.

Route, Figma, and API split metadata are copied from the contract doc comments when the page follows the fr-mvvm-contract convention:

/// Figma: https://www.figma.com/file/...
/// Route: AppRouter.notifications
/// Models:
/// - [NotificationsModel]: component state
/// BFF-UI-API:
/// - GET <BASE>/notifications-page/bootstrap
///   [NotificationsBootstrapBffReq], [NotificationsBootstrapBffRsp]
/// - GET <BASE>/notifications-page/tabs
///   [NotificationsTabsBffReq], [NotificationsTabsBffRsp]
@FrAcddPage(
  mode: FrAcddMode.bff,
  namespace: 'notifications_page',
)
class NotificationsPage extends StatelessWidget {
  const NotificationsPage({super.key});
}

CLI:

fvm dart run fr_acdd:extract_bff --format proto --input path/to/xxx.dart --output path/to/xxx.proto
fvm dart run fr_acdd:extract_bff --format json5 --input path/to/xxx.dart --output path/to/xxx.md

--input must name the Dart library shell that declares its authored part files. The extractor reads the shell and every authored part as one contract library. It skips generated .freezed.dart and .g.dart parts, so they may be absent during contract extraction; any other declared part must exist. Passing an individual part of file is an error.

FrAcddMode only expresses the contract mode:

  • api
  • bff

The --format flag only selects the derived output format. Do not encode proto or json5 as contract modes.

If the contract comment omits the BFF-UI-API: section, fr_acdd will infer suggested BFF API branches from the root DTO UX shape instead of assuming one page equals one API. Legacy BFF-API: input remains readable and generated output is normalized to canonical BFF-UI-API:.

For proto export, every included root or nested field must declare @FrAcddField(tag: ...). The extractor will fail fast when tags are missing, duplicated, or use the reserved range 19000-19999.

For json5 export, tags are not required. If a field annotation would be just @FrAcddField(), omit it entirely.

wireName defaults to the Dart field name. Omit it unless the exported wire field must differ from the contract field name.

nestedRef is usually inferred from Dart field types, including DTO objects, lists, sets, and maps. Only set it explicitly when inference would be ambiguous.

Use @FrAcddField(...) only when the field needs tag, wireName, nestedRef, or include: false.

@FrAcddDto is only for backend-transfer DTOs. Keep page-local state in unannotated page models or view-model members instead of trying to encode local state as a DTO kind.

Libraries

fr_acdd