Overview
artcdn is the centralized storage layer for all DigitalOcean Spaces operations across the Artalytics platform and agent infrastructure. It replaces the CDN functions previously embedded in artcore with a registry-driven design: buckets are declared in a single YAML file, the S3 client is cached per session, and all operations are generic (no domain assumptions baked in).
Adding a new bucket is a one-line change to inst/buckets.yml.
Where This Package Fits (Artalytics Ecosystem)
Artalytics follows a layered architecture with strict dependency boundaries:
+---------------------------------------------------------+
| appPlatform |
| (Main Shiny Application) |
+---------------------------------------------------------+
| modArtist | modBrowse | modUpload | modGallery |
| (Shiny Modules) |
+---------------------------------------------------------+
| artopenai | artgemini | artpixeltrace | artcurator |
| (API & Domain Packages) |
+---------------------------------------------------------+
| artutils |
| (High-level utilities & data access) |
+---------------------------------------------------------+
| artcore | artcdn |
| (DB, UUID, HTTP) | (CDN/S3 storage) |
+---------------------------------------------------------+
Dependency rules (internal Artalytics packages):
-
artcore: must not depend on any other Artalytics package -
artcdn: must not depend on any other Artalytics package -
artutils: may depend onartcoreand/orartcdn - API/domain packages (
artopenai,artgemini, etc.): may depend onartcore,artcdn, and/orartutils - Shiny module packages (
mod*): may depend onartutils(and thusartcore/artcdn), but never on other modules -
appPlatform: may depend on modules + utilities as needed
If your package violates these boundaries, it will create circular dependencies and break deploy/install flows.
Installation
Install from GitHub (internal Artalytics packages)
Use pak for fast, reliable installs:
install.packages("pak")
pak::pkg_install("artalytics/artcdn")If your package depends on private repos, you will need a GitHub PAT available as GITHUB_PAT.
Install dependencies (development)
install.packages("pak")
pak::pkg_install(c("devtools", "roxygen2", "testthat", "lintr", "covr"))Usage
# Registry: see what buckets are configured
artcdn::cdn_buckets()
#> [1] "art-public" "art-coa" "art-data" "art-vault" "art-corpus"
artcdn::cdn_bucket_info("art-corpus")
#> $visibility
#> [1] "private"
#> $description
#> [1] "Agent-optimized codebase documentation and source files"
# Upload a file
artcdn::cdn_upload("art-corpus", "source/artcore/R/database.R", "/tmp/database.R")
# Upload a directory
artcdn::cdn_upload_dir("art-data", "processed/uuid-a/uuid-b/", "/tmp/artwork_files/")
# Check existence
artcdn::cdn_has_object("art-public", "thumbnails/artist/artwork.jpeg")
artcdn::cdn_has_prefix("art-data", "processed/uuid-a/uuid-b")
# List and count
artcdn::cdn_list_keys("art-vault", "uploads/uuid-a/uuid-b")
artcdn::cdn_count_keys("art-public", "thumbnails/uuid-a")
# Get a URL (auto-presigns private buckets)
artcdn::cdn_url("art-public", "thumbnails/artist/artwork.jpeg")
artcdn::cdn_url("art-data", "processed/uuid-a/uuid-b/img.png")
# Delete
artcdn::cdn_delete("art-data", "processed/uuid-a/uuid-b/file.txt")
artcdn::cdn_delete_prefix("art-data", "processed/uuid-a/uuid-b", recursive = TRUE)
# Platform write helpers (UUID-validated, canonical key paths)
artcdn::write_art_vault(artist, artwork, "path/to/bundle/")
artcdn::write_art_data(artist, artwork, "path/to/processed/")
artcdn::write_art_public(artist, artwork, "path/to/thumb.jpeg")
artcdn::write_art_coa(artist, artwork, "path/to/certificate.pdf")
# Soft-delete artwork across all 4 platform buckets
artcdn::cdn_soft_delete(artist, artwork, dry_run = TRUE)Bucket Registry
All buckets are declared in inst/buckets.yml:
endpoint: "https://sfo3.digitaloceanspaces.com"
region: "sfo3"
buckets:
art-public:
visibility: public
description: Public thumbnails and static site assets
art-coa:
visibility: private
description: Certificates of authenticity
art-data:
visibility: private
description: Processed artwork data and analysis outputs
art-vault:
visibility: private
description: Original artist uploads and source bundles
art-corpus:
visibility: private
description: Agent-optimized codebase documentation and source filesTo add a new bucket, add an entry to this file. Every function in the package validates against this registry.
Configuration (Environment Variables)
# Required for all CDN operations. Put in ~/.Renviron (never commit).
ART_BUCKETS_KEY_ID="..."
ART_BUCKETS_KEY_SECRET="..."Documentation
- Roxygen2 for exported functions and user-facing objects
- Optional vignettes for tutorials / deep guides
Local commands:
devtools::document()
devtools::build_vignettes()If this package has a website, configure pkgdown in _pkgdown.yml and build locally:
pkgdown::build_site()Package Layout (Standard)
Artalytics packages follow the standard R package structure:
-
R/– R source code (functions, module definitions, internal helpers) -
man/– generated.Rddocs (via roxygen2) -
tests/testthat/– unit tests (testthat, edition 3) -
inst/– installed assets (data, templates, JS/CSS, etc.) -
vignettes/– optional long-form docs (Rmd/Quarto) -
.github/workflows/– CI:R CMD check, lint, coverage, etc.
Keep “source of truth” logic in R/. Anything in man/ should be treated as generated output.
Coding Standards (Artalytics Defaults)
These are the platform expectations for all packages:
-
data.table-first: use
data.tablefor tabular data (avoid tibbles/dplyr). -
Native pipe: use base R
|>(avoid magrittr%>%). -
String ops: prefer
stringr::str_*functions over basegsub/grepl/...(exceptpaste0()for concatenation). -
Explicit namespaces: prefer
pkg::fn()throughout (avoid attaching many packages). - snake_case: for function and variable names.
- Compact code: optimize for readability + fewer lines, especially in Shiny/module code.
For sensitive operations, ensure you follow:
-
Env vars for secrets: never commit keys/tokens; use
.Renvironlocally and CI secrets in workflows.
Development Commands (Local)
The minimum local loop:
devtools::document()
lintr::lint_package()
devtools::test()
devtools::check()CI (GitHub Actions)
This template ships standard workflows under .github/workflows/:
-
R-CMD-check.yaml– build + test gate -
lint.yaml–lintr::lint_package() -
test-coverage.yaml– coverage reporting (if configured)
Secrets policy:
- Put dev secrets in
.Renviron(never commit) - Put CI secrets in GitHub Actions secrets (e.g.,
GITHUB_PAT,CODECOV_TOKEN)
