Skip to contents

Assembles a complete QGIS project directory with background layers, field forms, methods documentation, and provincial templates. Ready to deploy to Mergin Maps for mobile field collection via rfp_mergin_create().

Usage

rfp_project_create(
  name,
  watershed_groups,
  template = .rfp_template_choices(),
  path_out = "~/Projects/gis",
  layer_config = NULL,
  forms = c("pscis", "fiss_site"),
  services = rfp_qgs_services()$layer_key,
  themes = unique(rfp_qgs_theme_lookup()$layers$theme),
  tracking = FALSE,
  track_fields = FALSE,
  layout = c("split", "monolith"),
  dir_layers = NULL,
  file_gpkg = NULL,
  s3_base = NULL,
  lookups = NULL
)

Arguments

name

Character. Project name. Used for the directory and .qgs file.

watershed_groups

Character vector of BC watershed group codes (e.g., c("ELKR")).

template

Character. QGIS project template. One of "bcfishpass_mobile" or "bcrestoration_mobile".

path_out

Character. Parent directory for the project. The project will be created at file.path(path_out, name). Defaults to ~/Projects/gis/.

layer_config

A data.frame of layers to download (e.g., from rfp_project_layers()). If NULL (default), reads from the gq registry for the selected template. Must have columns source_layer and source_type.

forms

Character vector of form types to include. Must match files in inst/extdata/forms/. Defaults to c("pscis", "fiss_site").

services

Character vector of remote services to declare - see rfp_qgs_services(). Defaults to every service in the registry, which is what both templates already carry, so the default changes nothing. Pass character(0) for a project with no remote layers at all.

themes

Character vector of map themes to add - see rfp_qgs_theme_lookup(). Defaults to every theme in the registry. An existing theme is left alone rather than replaced, so the default is a no-op for the themes the template already carries and adds only the ones it lacks. Pass character(0) to add none.

tracking

Logical. Enable Mergin Maps position tracking - creates tracking_layer.gpkg, declares it in the project, and switches the three Mergin/PositionTracking properties on. Default FALSE, so every existing call behaves as before. See rfp_qgs_tracking_set() for what the frequency enum means on each platform.

track_fields

Logical. Add track_name, track_type and named_by to the tracking layer, so a crew can say what a session was rather than reconstructing it off a map later (#186). Requires tracking = TRUE; ignored otherwise. Proven in the field 2026-08-26 - the form opens on tap, both widget types take input, and named_by populates from its default. Still FALSE by default so existing calls are unchanged; pass TRUE to turn it on. See rfp_tracking_fields_add().

layout

Character. "split" (default) gives each layer its own GeoPackage under dir_layers; "monolith" keeps the pre-#89 single GeoPackage. Split projects push a changed layer as one small file rather than re-uploading everything.

dir_layers

Character. Directory for per-layer GeoPackages. NULL (default) resolves getOption("rfp.dir_layers").

file_gpkg

Character. Single-GeoPackage name when layout = "monolith". NULL (default) resolves getOption("rfp.file_gpkg").

s3_base

Character. Object-storage base the aws pass reads from, or NULL (default) for the shipped host. Recorded in rfp_project.json when it is not the default, so rfp_project_update() refreshes from the same bucket rather than silently reverting to upstream (#268).

lookups

Named list of override CSVs for the osm, url and stac tiers, merged row-wise over the shipped lookups. Passed straight to rfp_source(); see there and rfp_source_lookup(). NOT recorded in the project's identity record the way s3_base is - the file lives in the caller's repo, so a path written into a Mergin-synced project would be machine-specific and would sync to field devices (rfp#285).

Value

Invisible path to the created project directory.

Details

The output directory contains:

  • {name}.qgs - QGIS project file (from the selected template)

  • background layers downloaded via rfp_source() - one GeoPackage per layer under background_layers/ by default; see rfp-layout

  • habitat_lateral.tif - lateral habitat raster (if aws source included)

  • form_*.gpkg - field data collection forms

  • ignore_mobile/photos/ - directory for field photos

  • ignore_mobile/methods/ - provincial methods PDFs

  • ignore_mobile/templates/ - provincial form templates

Layer set

The .qgs is reconciled to the data the project actually holds, so a narrowed layer_config gives a project that opens clean instead of one reporting dozens of missing layers. A template layer is dropped only when its datasource resolves to a file inside the project that is not there; basemaps, WMS and any other source rfp cannot resolve locally are always kept.

Two consequences worth knowing:

  • layer_config selects tables, and a project may style one table several ways. Asking for bcfishpass.streams_vw keeps all four of the restoration template's stream layers, each with its own symbology. To choose among them, subset afterwards with rfp_project_subset(), whose layers = names layers rather than tables.

  • A requested layer that fails to download is kept, with a warning, rather than trimmed - so a later refresh can fill it in. Only layers nobody asked for are removed.

What the project records about itself

Creation writes rfp_project.json at the project root, recording the template, the date, and the rfp version. The template is the part that is consumed: rfp_project_update(), rfp_project_audit() and rfp_manifest_create() resolve it from there, so they stop assuming bcfishpass_mobile when you do not pass one. It is also the style source for a layer added after creation, which the project .qgs cannot cover.

It has to be recorded because it cannot be inferred: the bcfishpass_mobile layer-id set is a strict subset of bcrestoration_mobile's, so a trimmed restoration project is indistinguishable from a fishpass one.

The project manifest

Creation writes rfp_manifest.csv at the project root — the project's birth certificate — so it starts inside the lifecycle rfp_project_update() and rfp_project_audit() depend on rather than needing a rfp_manifest_create() backfill. Without one, update runs in registry mode: it refreshes against a template that merely defaults to bcfishpass_mobile, cannot add a layer declaratively, and offers no frozen-layer protection.

The manifest records intent, so it is derived from layer_config rather than from what landed on disk. A layer that was requested but is not present — empty in this area, or a download that failed — stays in it deliberately: the audit reports it as informational, and the next update run adds it.

It is also a valid layer_config, so a project can be rebuilt from one:

m <- rfp_manifest_read("~/Projects/gis/some_project/rfp_manifest.csv")
rfp_project_create("some_project_rebuilt", watershed_groups = "BULK",
                   layer_config = m)

Edit the CSV to change what a project carries; rfp_manifest_create() is still there for projects created before this was written.

The round-trip restores the layer set, not the project's arrangement of it. A manifest is two columns, so a rebuild reconstructs which layers the project carries — and from that, its own manifest, rfp_project.json and a .qgs trimmed to those layers. It does not reconstruct:

  • map themes created after the original project was made

  • changes to which layers a theme shows, or whether a layer is on in it

  • layer-tree group placement and order for anything added after creation

Those live only in the source project's .qgs, and no other artifact records them. Seeding a new project from an existing one's layer list — the usual reason to do this — is unaffected, since there is no arrangement to lose. Rebuilding a project you want back as it was is where it bites.

Styling

The background GeoPackages are written with their own layer_styles table, taken from the project .qgs. QGIS reads that table on Add Layer and never on project open, so this is what makes a layer arrive styled when it is added to another project later, or re-added after a refresh — the project itself renders from the symbology stored in its .qgs either way.

Styles are lifted after the layer set is reconciled, so only layers this project holds are styled. A layer the .qgs does not reference gets no style; adding it in QGIS Desktop and running rfp_project_update() supplies one.

Styling never aborts creation. If it fails the project is written unstyled, with a warning, and rfp_styles_apply() can be run against it afterwards.

Examples

if (FALSE) { # \dontrun{
rfp_project_create(
  name = "elk_river_2026",
  watershed_groups = c("ELKR"),
  template = "bcfishpass_mobile",
  forms = c("pscis", "fiss_site")
)
} # }