You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/adr/0002-site-config-schema-versioning.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,6 +16,8 @@ Keep `schema_version` at `1.0` for additive, backward-compatible changes.
16
16
17
17
Increment `schema_version` only when a stored `custom/v8s-site-config.json` file needs a migration or when existing field semantics change incompatibly.
18
18
19
+
Record additive field changes in `docs/schema-changelog.md`, even when `schema_version` does not change.
20
+
19
21
When `schema_version` changes, the same change should include:
20
22
21
23
- the new default schema version in `defaults/v8s-site-config.json`
vanityURLs instances need to receive product updates without overwriting local links, policies, branding, and operator settings.
10
+
11
+
The repository contains product-owned defaults and scripts, instance-owned custom files, and generated build output.
12
+
13
+
## Decision
14
+
15
+
Product-owned files live under `defaults/` and `scripts/`.
16
+
17
+
Instance-owned files live under `custom/`.
18
+
19
+
Generated output lives under `build/` and `src/`.
20
+
21
+
The build copies product defaults, overlays `custom/`, then writes generated runtime artifacts. Instance owners should edit `custom/`, not `defaults/` or `build/`, unless they are contributing product changes upstream.
22
+
23
+
## Consequences
24
+
25
+
- Instances can upgrade product files while preserving local configuration
26
+
-`custom/` is the operational boundary for links, policies, site config, public overrides, and local helper settings
27
+
- Build output can be deleted and regenerated
28
+
- Documentation can refer to source files without turning generated artifacts into edit targets
New users need a fast phase-1 path to get a redirector online. Full privacy, terms, and standalone security pages require operator-specific legal decisions that may take longer.
10
+
11
+
At the same time, a public short-link domain still needs abuse and vulnerability contact paths early.
12
+
13
+
## Decision
14
+
15
+
Setup supports deferring full privacy, terms, and standalone security pages with `operator.legal_pages_enabled`.
16
+
17
+
When full legal pages are deferred:
18
+
19
+
- Trust & Safety still deploys
20
+
-`/.well-known/security.txt` still deploys when security contact data is valid
21
+
- privacy, terms, and standalone security pages are skipped until configured
22
+
23
+
## Consequences
24
+
25
+
- Quickstart remains focused on first deployment
26
+
- Operators can publish basic trust contact paths before finishing full legal review
27
+
- Full legal pages still require operator, jurisdiction, contact, and date fields
28
+
- Setup can be rerun later to enable the full page set
The `lnk` CLI can generate short slugs when the user does not provide one. Fully unrestricted random strings can include characters that are visually ambiguous or awkward to read over the phone.
10
+
11
+
Different teams may also want different generated slug lengths for different tags.
12
+
13
+
## Decision
14
+
15
+
Generated slugs use a readable alphabet from `custom/v8s-site-config.json`, falling back to the product default.
16
+
17
+
The site config also stores:
18
+
19
+
-`links.random_slug_length`
20
+
-`links.random_slug_alphabet`
21
+
-`links.tag_random_slug_lengths`
22
+
23
+
When multiple tags define random slug lengths, `lnk` uses the shortest configured length.
24
+
25
+
## Consequences
26
+
27
+
- Generated slugs are easier to read and type
28
+
- Instances can keep short defaults while using longer slugs for selected tags
29
+
- The schema fields are additive and do not require a `schema_version` bump
The policy layer blocks scanner probes such as WordPress and PHP endpoint scans. Some strings, such as `.php`, are unsafe as requested paths on a non-PHP redirector but can be legitimate in long-link destinations.
10
+
11
+
Blocking those strings everywhere can reject valid redirects.
12
+
13
+
## Decision
14
+
15
+
Scanner-probe keywords default to request scope unless explicitly configured otherwise.
16
+
17
+
Policy entries can set `scope` to control whether a keyword applies to request paths, redirect targets, or both.
18
+
19
+
## Consequences
20
+
21
+
- Scanner probes are still blocked before short-link lookup
22
+
- Valid long URLs ending in `.php` can be used as redirect targets
23
+
- Existing scanner policies remain compatible
24
+
- Policy authors can still opt into target blocking for specific keywords
# 0008. Detach instances and upgrade product files
2
+
3
+
Date: 2026-05-26
4
+
5
+
Status: Accepted
6
+
7
+
## Context
8
+
9
+
Users create their own instance repository from the vanityURLs code. That repository should become theirs, with its own GitHub remote, while still being able to refresh product files from upstream.
10
+
11
+
## Decision
12
+
13
+
`npm run detach` removes upstream project metadata that should not belong to a new instance.
14
+
15
+
`npm run upgrade` refreshes product-owned paths from upstream while protecting instance-owned paths such as `custom/`, `wrangler.toml`, and `.dev.vars`.
16
+
17
+
The default upgrade path includes product files such as `defaults/`, `scripts/`, `package.json`, `package-lock.json`, `README.md`, `LICENSE`, and `cloudflare-setup.md`.
18
+
19
+
## Consequences
20
+
21
+
- New instances can start as independent repositories
22
+
- Upgrades can refresh product behavior without overwriting local configuration
23
+
- Protected local paths remain the operator's responsibility
24
+
- Release metadata and upstream workflow files do not leak into detached instances
This changelog records field-level schema changes for vanityURLs configuration files, including additive changes that do not bump `schema_version`.
4
+
5
+
`schema_version` is reserved for incompatible stored-config changes that need migration. See `docs/adr/0002-site-config-schema-versioning.md`.
6
+
7
+
## 2026-05-26
8
+
9
+
### v8s-site-config.json
10
+
11
+
Added optional field under `operator`:
12
+
13
+
-`operator_domain`
14
+
15
+
Compatibility: additive, no `schema_version` bump
16
+
17
+
Migration: none required. When `operator.operator_domain` is blank or absent, setup defaults role-based email addresses from the short domain. When it is set, setup defaults operator, privacy, Trust & Safety, and security email addresses from the operator domain.
18
+
19
+
### v8s-site-config.json
20
+
21
+
Added optional fields under `links`:
22
+
23
+
-`random_slug_length`
24
+
-`random_slug_alphabet`
25
+
-`tag_random_slug_lengths`
26
+
27
+
Compatibility: additive, no `schema_version` bump
28
+
29
+
Migration: none required. `lnk` reads missing values from `defaults/v8s-site-config.json`.
30
+
31
+
### v8s-site-config.json
32
+
33
+
Added installer-managed branding fields:
34
+
35
+
-`branding.domain`
36
+
-`branding.custom_public`
37
+
-`branding.wordmark.black`
38
+
-`branding.wordmark.green`
39
+
40
+
Compatibility: additive, no `schema_version` bump
41
+
42
+
Migration: none required. Existing instances without `branding` continue to use default public assets or custom public files.
43
+
44
+
### v8s-site-config.json
45
+
46
+
Added deferred legal-page mode:
47
+
48
+
-`operator.legal_pages_enabled`
49
+
50
+
Compatibility: additive, no `schema_version` bump
51
+
52
+
Migration: none required. Missing values behave like enabled legal pages only when the operator fields are fully configured.
53
+
54
+
### v8s-site-config.json
55
+
56
+
Expanded operator fields used by generated privacy, terms, Trust & Safety, security, and `security.txt` output:
57
+
58
+
-`operator.legal_name`
59
+
-`operator.short_domain`
60
+
-`operator.jurisdiction`
61
+
-`operator.governing_law`
62
+
-`operator.contact_email`
63
+
-`operator.privacy_contact`
64
+
-`operator.abuse_contact`
65
+
-`operator.security_contact`
66
+
-`operator.last_updated`
67
+
-`operator.umami_geo_ip_mode`
68
+
-`operator.analytics_disclosure`
69
+
-`operator.analytics_retention`
70
+
-`operator.abuse_response_window`
71
+
72
+
Compatibility: additive, no `schema_version` bump
73
+
74
+
Migration: none required for plain redirect behavior. Generated legal pages require the relevant fields before launch.
75
+
76
+
### v8s-local-config.json
77
+
78
+
Added local helper and local publish configuration:
79
+
80
+
-`shell_helper`
81
+
-`lnk_cli`
82
+
-`local_publish`
83
+
-`registry`
84
+
-`repository`
85
+
86
+
Compatibility: additive, no `schema_version` bump
87
+
88
+
Migration: none required. `npm run local-install` writes workstation-specific values.
89
+
90
+
### v8s-policies.json
91
+
92
+
Replaced legacy blocklist naming with the broader policy source:
93
+
94
+
-`defaults`
95
+
-`allow_domains`
96
+
-`blocked_keywords`
97
+
-`block_domains`
98
+
- optional `generated_sources`
99
+
100
+
Compatibility: additive and rename-compatible, no `schema_version` bump
101
+
102
+
Migration: legacy `v8s-blocklist.json` filenames are still recognized for migration compatibility, but new instances should use `v8s-policies.json`.
103
+
104
+
### v8s-schedules.json
105
+
106
+
Added schedule configuration keyed by slug:
107
+
108
+
-`timezone`
109
+
-`default`
110
+
- shortcut rules such as `9to5`
111
+
-`rules[]` entries with `label`, `timezone`, `days`, `from`, `to`, and `target`
112
+
113
+
Compatibility: additive, no `schema_version` bump
114
+
115
+
Migration: none required. Missing custom schedules mean the link uses its normal target.
args.operatorJurisdiction=awaitquestion(rl,"Operator jurisdiction, for example Canada",args.operatorJurisdiction||configuredOperator.jurisdiction||"");
args.operatorLastUpdated=awaitquestion(rl,"Legal pages last updated date",args.operatorLastUpdated||configuredOperator.last_updated||gitLastUpdatedDate()||todayIsoDate());
110
112
}else{
@@ -292,14 +294,17 @@ function normalizeWordmarkSplit(args) {
0 commit comments