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
-[specs/deferred.md](../specs/deferred.md) — features intentionally out of scope (do NOT silently implement these)
21
+
-[specs/api/](../specs/api/) — endpoint contracts (one file per resource group)
22
+
-[specs/screens/](../specs/screens/) — one file per route — what the user sees, what they can do
23
+
-[specs/behaviors/](../specs/behaviors/) — cross-cutting rules referenced from multiple screens/APIs
24
24
25
25
## Spec drift auditing
26
26
@@ -30,11 +30,20 @@ Run `/audit-spec-drift` to launch a comprehensive audit comparing `specs/` again
30
30
31
31
`plans/` is the micro-DAG of work that bridges `specs/` to the running code. If specs describe **state** (what should be true forever), plans describe **motion** (how we get there). Start a feature with a plan; the plan declares its scope, the specs it implements, its dependencies, and concrete validation criteria.
1.**Add a plan** when starting a new chunk of work. `status: planned` + `depends:` set.
36
-
2.**Move to `in-progress`** when you start. Multiple plans can be in-progress in parallel across people, but one plan per contributor at a time is the norm.
37
-
3.**Move to `done`** when validation criteria all pass. Link the merged PR in frontmatter (`pr: 42`).
36
+
2.**Move to `in-progress`** when you start, as the first commit on the branch (`chore(plans): mark <slug> in-progress`). Skippable for tiny plans — going straight to `done` at the end is fine. Multiple plans can be in-progress in parallel across people, but one plan per contributor at a time is the norm.
37
+
3.**Move to `done` as the last commit on the branch, before merge.** That commit does the following, all in one shot, with message `chore(plans): mark <slug> done (PR #<n>)`:
-**Validation checklist: flip each `- [ ]` to `- [x]` for criteria you verified.** If a criterion can't be verified at merge time (depends on a downstream plan, needs production deploy, etc.), leave it unchecked and add a one-line note in the Notes section explaining why and where it'll close out. Never silently rewrite a validation criterion to match what you ended up doing — that's a plan amendment in its own earlier commit.
40
+
-**Notes** section: non-actionable carry-forwards — decisions, surprises, gotchas, learnings. Things future-you would want to know.
41
+
-**Follow-ups** section: actionable items that didn't ship with this plan. Each entry is one of:
42
+
-`Issue [#N](link) — short description` — when actionable and not owned by an existing planned-or-in-progress plan, file the issue first (`gh-axi issue create`) and link it
43
+
-`Deferred to [`<other-plan>`](<other-plan>.md) — short description` — when an unstarted (`status: planned`) downstream plan should own the work. **The same closeout commit must also edit that downstream plan to absorb the deferral** — typically a new bullet under Approach and a new criterion under Validation. If the downstream plan is already `in-progress` or `done`, use the Issue shape instead; never modify a plan that's actively being implemented or already frozen.
44
+
-`Tracked as: <free-form pointer>` — for anything else (waiting on community input, vendor response, etc.)
45
+
-`None.` — explicit when there's nothing, so a future reader can see the section was considered, not just absent
46
+
- The plan is frozen after merge — historical record, no further edits
38
47
4.**Update `depends:`** as the DAG sharpens — a plan can discover it needs a new prereq mid-stream.
39
48
5.**Specs come first.** A plan implements specs that already exist. If you realize specs need to change mid-plan, the spec change is its own PR before the plan continues.
40
49
6.**Splitting a plan**: rename and add the new one with `depends:` updated.
`specs:` is for specs we own — the spec-drift-auditor matches them against implementation. `upstream-specs:` is for specs owned by dependencies (e.g., gitsheets) that this plan consumes; they're informational only and the spec-drift-auditor doesn't check them. Use the `<repo>:<path>` form so it's obvious where to look.
60
69
61
-
A plan's body follows the template in [plans/README.md](plans/README.md): Scope, Implements, Approach, Validation, Risks/unknowns, Notes. The Validation section is the load-bearing part — it converts "in-progress" to "done."
70
+
A plan's body follows the template in [plans/README.md](../plans/README.md): Scope, Implements, Approach, Validation, Risks/unknowns, Notes, Follow-ups. The Validation section is the load-bearing part — it converts "in-progress" to "done."
62
71
63
72
**Plans are not specs.** They're project-management artifacts. Plans rot fast — once a plan is `done`, it's a historical record; don't keep editing it. The `spec-drift-auditor` reads `specs/`, not `plans/`.
-**Public storage** — [gitsheets](https://github.com/JarvusInnovations/gitsheets) (TOML records in a git repo). Public-by-design — civic transparency. No persistent OLTP. See [specs/behaviors/storage.md](specs/behaviors/storage.md).
69
-
-**Private storage** — S3-compatible bucket holding two `.jsonl` files (private profiles + legacy password hashes). Boot-load + in-memory; PUT on mutation. See [specs/behaviors/private-storage.md](specs/behaviors/private-storage.md).
77
+
-**Public storage** — [gitsheets](https://github.com/JarvusInnovations/gitsheets) (TOML records in a git repo). Public-by-design — civic transparency. No persistent OLTP. See [specs/behaviors/storage.md](../specs/behaviors/storage.md).
78
+
-**Private storage** — S3-compatible bucket holding two `.jsonl` files (private profiles + legacy password hashes). Boot-load + in-memory; PUT on mutation. See [specs/behaviors/private-storage.md](../specs/behaviors/private-storage.md).
70
79
-**Schemas** — Zod in `packages/shared`, consumed by both web and api, validating records in both stores.
71
80
-**Full-text search** — in-memory SQLite FTS5 (or MiniSearch fallback), rebuilt at boot from gitsheets state.
72
-
-**Auth** — GitHub OAuth as the sole primary identity provider; stateless JWT sessions. We are also the SAML IdP for codeforphilly.slack.com. See [specs/api/auth.md](specs/api/auth.md), [specs/api/saml.md](specs/api/saml.md).
81
+
-**Auth** — GitHub OAuth as the sole primary identity provider; stateless JWT sessions. We are also the SAML IdP for codeforphilly.slack.com. See [specs/api/auth.md](../specs/api/auth.md), [specs/api/saml.md](../specs/api/saml.md).
See [specs/architecture.md](specs/architecture.md) for the full stack rationale.
84
+
See [specs/architecture.md](../specs/architecture.md) for the full stack rationale.
76
85
77
86
Per the user's global rules: `npm` workspaces (not bun), `asdf` manages the Node version, commit lockfiles.
78
87
@@ -82,7 +91,7 @@ Per the user's global rules: `npm` workspaces (not bun), `asdf` manages the Node
82
91
2.**Private bucket** — emails, newsletter prefs, legacy password hashes during migration. Production-only; devs use a local filesystem backend with seeded fakes.
83
92
3.**Public snapshot** (`codeforphilly-data-snapshot`) — anonymized, contributor-cloneable copy of the public data. PII-free by construction.
84
93
85
-
**Real production private data never lands on a dev machine** — see [specs/behaviors/private-storage.md](specs/behaviors/private-storage.md).
94
+
**Real production private data never lands on a dev machine** — see [specs/behaviors/private-storage.md](../specs/behaviors/private-storage.md).
86
95
87
96
## Tooling
88
97
@@ -115,9 +124,9 @@ npm run -w apps/web dev
115
124
- Field names: `camelCase` in TS and in TOML records. No casing translation.
116
125
- IDs: UUIDv7. Slugs (not IDs) in user-facing URLs.
117
126
- Timestamps: ISO 8601 UTC strings (e.g., `"2026-05-15T18:42:00Z"`) — in requests, responses, and on disk.
118
-
- Use the response envelope from [specs/api/conventions.md](specs/api/conventions.md) for every endpoint.
119
-
- Markdown is rendered server-side. Clients never run a markdown library on user content. See [specs/behaviors/markdown-rendering.md](specs/behaviors/markdown-rendering.md).
120
-
- Mutations go through the in-process write mutex documented in [specs/behaviors/storage.md](specs/behaviors/storage.md). Don't write to the data repo from anywhere else.
127
+
- Use the response envelope from [specs/api/conventions.md](../specs/api/conventions.md) for every endpoint.
128
+
- Markdown is rendered server-side. Clients never run a markdown library on user content. See [specs/behaviors/markdown-rendering.md](../specs/behaviors/markdown-rendering.md).
129
+
- Mutations go through the in-process write mutex documented in [specs/behaviors/storage.md](../specs/behaviors/storage.md). Don't write to the data repo from anywhere else.
121
130
122
131
## Source control
123
132
@@ -131,8 +140,8 @@ npm run -w apps/web dev
131
140
132
141
We are migrating from a MySQL-backed PHP/Emergence app to a gitsheets-backed Node app. Every user-facing URL stays the same. See:
133
142
134
-
-[specs/behaviors/slug-handles.md](specs/behaviors/slug-handles.md) — slug format and uniqueness
135
-
-[specs/behaviors/legacy-id-mapping.md](specs/behaviors/legacy-id-mapping.md) — `legacyId` column and URL redirects
143
+
-[specs/behaviors/slug-handles.md](../specs/behaviors/slug-handles.md) — slug format and uniqueness
144
+
-[specs/behaviors/legacy-id-mapping.md](../specs/behaviors/legacy-id-mapping.md) — `legacyId` column and URL redirects
136
145
- The one-shot importer lives at `apps/api/scripts/import-laddr.ts` (not yet implemented)
A modernization of [laddr](https://github.com/CodeForPhilly/laddr) — the platform behind [codeforphilly.org](https://codeforphilly.org) — onto a Fastify + Vite/React + [gitsheets](https://github.com/JarvusInnovations/gitsheets) stack.
4
+
5
+
This site is **spec-driven**: [`specs/`](specs/) declares what should be true and the implementation is brought into conformance with it. Plans in [`plans/`](plans/) are the bridge between specs and code.
6
+
7
+
## Quick links
8
+
9
+
-[`specs/README.md`](specs/README.md) — what specs cover, how they're authored, where to start
-**Auth** — GitHub OAuth + stateless JWT sessions; we are also the SAML IdP for codeforphilly.slack.com
38
+
39
+
See [`specs/architecture.md`](specs/architecture.md) for the rationale on each choice.
40
+
41
+
## Contributing
42
+
43
+
Spec-first: before writing or changing code, read the relevant spec. If the spec doesn't cover what you're about to do, update the spec first. See [`specs/README.md`](specs/README.md) for the workflow and [`.claude/CLAUDE.md`](.claude/CLAUDE.md) for conventions.
0 commit comments