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
.qgsfile.- 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()). IfNULL(default), reads from the gq registry for the selected template. Must have columnssource_layerandsource_type.- forms
Character vector of form types to include. Must match files in
inst/extdata/forms/. Defaults toc("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. Passcharacter(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. Passcharacter(0)to add none.- tracking
Logical. Enable Mergin Maps position tracking - creates
tracking_layer.gpkg, declares it in the project, and switches the threeMergin/PositionTrackingproperties on. DefaultFALSE, so every existing call behaves as before. Seerfp_qgs_tracking_set()for what the frequency enum means on each platform.- track_fields
Logical. Add
track_name,track_typeandnamed_byto the tracking layer, so a crew can say what a session was rather than reconstructing it off a map later (#186). Requirestracking = TRUE; ignored otherwise. Proven in the field 2026-08-26 - the form opens on tap, both widget types take input, andnamed_bypopulates from its default. StillFALSEby default so existing calls are unchanged; passTRUEto turn it on. Seerfp_tracking_fields_add().- layout
Character.
"split"(default) gives each layer its own GeoPackage underdir_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) resolvesgetOption("rfp.dir_layers").- file_gpkg
Character. Single-GeoPackage name when
layout = "monolith".NULL(default) resolvesgetOption("rfp.file_gpkg").- s3_base
Character. Object-storage base the
awspass reads from, orNULL(default) for the shipped host. Recorded inrfp_project.jsonwhen it is not the default, sorfp_project_update()refreshes from the same bucket rather than silently reverting to upstream (#268).- lookups
Named list of override CSVs for the
osm,urlandstactiers, merged row-wise over the shipped lookups. Passed straight torfp_source(); see there andrfp_source_lookup(). NOT recorded in the project's identity record the ways3_baseis - 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).
Details
The output directory contains:
{name}.qgs- QGIS project file (from the selected template)background layers downloaded via
rfp_source()- one GeoPackage per layer underbackground_layers/by default; see rfp-layouthabitat_lateral.tif- lateral habitat raster (ifawssource included)form_*.gpkg- field data collection formsignore_mobile/photos/- directory for field photosignore_mobile/methods/- provincial methods PDFsignore_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_configselects tables, and a project may style one table several ways. Asking forbcfishpass.streams_vwkeeps all four of the restoration template's stream layers, each with its own symbology. To choose among them, subset afterwards withrfp_project_subset(), whoselayers =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.
