Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ CodePlans sits between your issue tracker and your architecture diagram:
from the product architecture to a service's specs, design decisions, active
plans, known issues, and delivery history.

- **See the architecture:** an interactive map of assets and dependencies across products — trace what an asset relies on and what relies on it, then click through to its documents.
- **Find the detail:** search document bodies and technical identifiers, then narrow by asset, type, status, area, or date.
- **Read comfortably:** full Markdown documents with tables, code, task lists, section links, and related content alongside.
- **Follow the evidence:** see authors, edit times, spec revisions, and capability receipts without confusing planned work with shipped versions.
Expand Down
41 changes: 35 additions & 6 deletions app/(wiki)/wiki/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Link from 'next/link'
import { notFound, redirect } from 'next/navigation'
import { authAdapter } from '@/lib/auth'
import { getProducts } from '@/lib/db/queries'
import { getAssetInventory, getProducts } from '@/lib/db/queries'
import { getWikiProduct } from '@/lib/db/wiki'
import { buildWikiMap } from '@/lib/wiki/map'
import {
awaitsReview,
kindLabels,
Expand All @@ -18,6 +19,7 @@ import {
DocumentList,
ActivityList,
} from '@/components/wiki/views'
import { ArchitectureMap } from '@/components/wiki/architecture-map'
import { ThemeToggle } from '@/components/theme-toggle'
import { WikiTime } from '@/components/wiki/time'
export const dynamic = 'force-dynamic'
Expand Down Expand Up @@ -68,17 +70,23 @@ export default async function WikiProduct({ params, searchParams }: Props) {
getProducts(user.id),
])
if (!data) notFound()
// The map spans every product the reader can see; the same visibility rules apply.
const map =
view === 'map' && !docKey
? buildWikiMap(data, await getAssetInventory(user.id))
: null
const asset = data.assets.find((a) => a.id === assetId),
doc = data.documents.find((d) => d.key === docKey)
if ((assetId && !asset) || (docKey && !doc)) notFound()
const listing =
view === 'documents' ||
!map &&
(view === 'documents' ||
view === 'review' ||
!!q ||
!!kind ||
!!status ||
!!since ||
!!area
!!area)
const filters = {
q,
asset: assetId,
Expand Down Expand Up @@ -191,6 +199,12 @@ export default async function WikiProduct({ params, searchParams }: Props) {
>
Product overview
</Link>
<Link
className={map ? 'selected' : ''}
href={wikiHref(slug, { view: 'map' })}
>
Architecture map
</Link>
<Link
className={view === 'documents' && !asset ? 'selected' : ''}
href={wikiHref(slug, { view: 'documents' })}
Expand Down Expand Up @@ -243,6 +257,7 @@ export default async function WikiProduct({ params, searchParams }: Props) {
<span>/</span>
<span>
{doc?.title ??
(map ? 'Architecture map' : undefined) ??
asset?.name ??
(view === 'review'
? 'Awaiting review'
Expand All @@ -255,6 +270,17 @@ export default async function WikiProduct({ params, searchParams }: Props) {
</div>
{doc ? (
<DocumentReader data={data} doc={doc} />
) : map ? (
<>
<p className="wiki-eyebrow">Architecture</p>
<h1>Architecture map</h1>
<p className="wiki-lead">
Assets and their recorded dependencies, for this product or
across every product you can see. Select an asset to trace its
reach and follow its documents.
</p>
<ArchitectureMap map={map} />
</>
) : listing ? (
<>
<p className="wiki-eyebrow">
Expand Down Expand Up @@ -518,10 +544,13 @@ export default async function WikiProduct({ params, searchParams }: Props) {
<section className="wiki-section">
<div className="wiki-section-title">
<h2>Explore the architecture</h2>
<span className="wiki-caption">
Select an asset to read its story
</span>
<Link href={wikiHref(slug, { view: 'map' })}>
Open the architecture map →
</Link>
</div>
<p className="wiki-caption">
Select an asset to read its story
</p>
<div className="wiki-cards">
{data.assets.map((a) => (
<Link
Expand Down
Loading
Loading