···455455- `settings.go` - User settings management
456456- `api.go` - JSON API endpoints
457457458458-**Static Assets** (`pkg/appview/public/`, `pkg/appview/templates/`):
458458+**Public Assets & Templates** (`pkg/appview/public/`, `pkg/appview/templates/`):
459459+- `pkg/appview/public/` is served at the web root `/` (e.g., `public/favicon.svg` → `/favicon.svg`)
459460- Templates use Go html/template
460461- JavaScript in `public/js/app.js`
461462- Minimal CSS for clean UI
+10-11
cmd/appview/serve.go
···465465 TangledRepo: cfg.CredentialHelper.TangledRepo,
466466 })
467467468468- // Create listener with SO_REUSEADDR for hot-reload support
469469- lc := net.ListenConfig{
470470- Control: func(network, address string, c syscall.RawConn) error {
471471- return c.Control(func(fd uintptr) {
472472- _ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
473473- })
474474- },
475475- }
476476- listener, err := lc.Listen(context.Background(), "tcp", cfg.Server.Addr)
468468+ // Create listener (closed immediately on shutdown in dev mode for hot-reload)
469469+ listener, err := net.Listen("tcp", cfg.Server.Addr)
477470 if err != nil {
478471 return fmt.Errorf("failed to create listener: %w", err)
479472 }
···501494 case <-stop:
502495 slog.Info("Shutting down registry server")
503496504504- // Stop health worker first
497497+ // In dev mode (TEST_MODE), close listener immediately to release port for hot-reload
498498+ // In production, let graceful shutdown handle it properly
499499+ if cfg.Server.TestMode {
500500+ listener.Close()
501501+ }
502502+503503+ // Stop health worker
505504 slog.Info("Stopping hold health worker")
506505 healthWorker.Stop()
507506508507 shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
509508 defer cancel()
510509511511- if err := server.Shutdown(shutdownCtx); err != nil {
510510+ if err := server.Shutdown(shutdownCtx); err != nil && err != http.ErrServerClosed {
512511 logging.Shutdown() // Flush remaining logs
513512 return fmt.Errorf("server shutdown error: %w", err)
514513 }
···88<body>
99 {{ template "nav" . }}
10101111- <main class="container">
1212- <div class="install-page">
1313- <h1>Install ATCR Credential Helper</h1>
1414- <p>The ATCR credential helper enables Docker to authenticate with ATCR registries using your ATProto identity.</p>
1111+ <main class="container mx-auto px-4 py-8 max-w-4xl">
1212+ <h1 class="text-3xl font-bold mb-2">Install ATCR Credential Helper</h1>
1313+ <p class="text-base-content/70 mb-8">The ATCR credential helper enables Docker to authenticate with ATCR registries using your ATProto identity.</p>
15141616- <div class="install-section">
1717- <h2>Quick Install</h2>
1515+ <div class="space-y-12">
1616+ <section>
1717+ <h2 class="text-xl font-semibold mb-4">Quick Install</h2>
18181919- <div class="platform-tabs">
2020- <button class="platform-tab active" onclick="showPlatform('linux')">Linux / macOS</button>
2121- <button class="platform-tab" onclick="showPlatform('windows')">Windows</button>
1919+ <div class="flex gap-2 mb-4">
2020+ <button class="btn btn-sm btn-primary platform-tab" onclick="showPlatform('linux')">Linux / macOS</button>
2121+ <button class="btn btn-sm btn-ghost platform-tab" onclick="showPlatform('windows')">Windows</button>
2222 </div>
23232424- <div class="platform-content active" id="linux-content">
2525- <h3>Using install script</h3>
2626- <div class="code-block"><code>curl -fsSL {{ .RegistryURL }}/static/install.sh | bash</code></div>
2424+ <div class="platform-content" id="linux-content">
2525+ <h3 class="text-lg font-medium mb-3">Using install script</h3>
2626+ <div class="mockup-code bg-base-300 text-base-content mb-6">
2727+ <pre data-prefix="$"><code>curl -fsSL {{ .RegistryURL }}/static/install.sh | bash</code></pre>
2828+ </div>
27292828- <h3>Manual download</h3>
2929- <div class="code-block"><code>curl -fsSLO {{ .RegistryURL }}/static/install.sh
3030-chmod +x install.sh
3131-./install.sh</code></div>
3030+ <h3 class="text-lg font-medium mb-3">Manual download</h3>
3131+ <div class="mockup-code bg-base-300 text-base-content">
3232+ <pre data-prefix="$"><code>curl -fsSLO {{ .RegistryURL }}/static/install.sh</code></pre>
3333+ <pre data-prefix="$"><code>chmod +x install.sh</code></pre>
3434+ <pre data-prefix="$"><code>./install.sh</code></pre>
3535+ </div>
3236 </div>
33373434- <div class="platform-content" id="windows-content">
3535- <h3>Using PowerShell (Run as Administrator)</h3>
3636- <div class="code-block"><code>iwr -useb {{ .RegistryURL }}/static/install.ps1 | iex</code></div>
3838+ <div class="platform-content hidden" id="windows-content">
3939+ <h3 class="text-lg font-medium mb-3">Using PowerShell (Run as Administrator)</h3>
4040+ <div class="mockup-code bg-base-300 text-base-content mb-6">
4141+ <pre data-prefix="PS"><code>iwr -useb {{ .RegistryURL }}/static/install.ps1 | iex</code></pre>
4242+ </div>
37433838- <h3>Manual download</h3>
3939- <div class="code-block"><code>Invoke-WebRequest -Uri {{ .RegistryURL }}/static/install.ps1 -OutFile install.ps1
4040-.\install.ps1</code></div>
4444+ <h3 class="text-lg font-medium mb-3">Manual download</h3>
4545+ <div class="mockup-code bg-base-300 text-base-content">
4646+ <pre data-prefix="PS"><code>Invoke-WebRequest -Uri {{ .RegistryURL }}/static/install.ps1 -OutFile install.ps1</code></pre>
4747+ <pre data-prefix="PS"><code>.\install.ps1</code></pre>
4848+ </div>
4149 </div>
4242- </div>
5050+ </section>
43514444- <div class="install-section">
4545- <h2>Configure Docker</h2>
4646- <p>After installation, configure Docker to use the credential helper:</p>
5252+ <section>
5353+ <h2 class="text-xl font-semibold mb-4">Configure Docker</h2>
5454+ <p class="mb-4">After installation, configure Docker to use the credential helper:</p>
47554848- <h3>Create or edit <code>~/.docker/config.json</code></h3>
4949- <div class="code-block"><code>{
5050- "credHelpers": {
5151- "{{ .RegistryURL }}": "atcr"
5252- }
5353-}</code></div>
5656+ <h3 class="text-lg font-medium mb-3">Create or edit <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">~/.docker/config.json</code></h3>
5757+ <div class="mockup-code bg-base-300 text-base-content mb-4">
5858+ <pre><code>{</code></pre>
5959+ <pre><code> "credHelpers": {</code></pre>
6060+ <pre><code> "{{ .RegistryURL }}": "atcr"</code></pre>
6161+ <pre><code> }</code></pre>
6262+ <pre><code>}</code></pre>
6363+ </div>
54645555- <div class="note">
5656- <strong>Note:</strong> If you have an existing <code>config.json</code>, add the <code>credHelpers</code> entry to your existing configuration.
6565+ <div class="alert alert-info">
6666+ <i data-lucide="info" class="size-5"></i>
6767+ <span>If you have an existing <code class="bg-black/10 dark:bg-white/10 px-1 py-0.5 rounded text-sm font-mono">config.json</code>, add the <code class="bg-black/10 dark:bg-white/10 px-1 py-0.5 rounded text-sm font-mono">credHelpers</code> entry to your existing configuration.</span>
5768 </div>
5858- </div>
6969+ </section>
59706060- <div class="install-section">
6161- <h2>Authentication</h2>
6262- <p>The credential helper will automatically prompt for authentication when you push or pull:</p>
7171+ <section>
7272+ <h2 class="text-xl font-semibold mb-4">Authentication</h2>
7373+ <p class="mb-4">The credential helper will automatically prompt for authentication when you push or pull:</p>
63746464- <div class="code-block"><code>docker push {{ .RegistryURL }}/yourhandle/myapp:latest</code></div>
7575+ <div class="mockup-code bg-base-300 text-base-content mb-4">
7676+ <pre data-prefix="$"><code>docker push {{ .RegistryURL }}/yourhandle/myapp:latest</code></pre>
7777+ </div>
65786666- <p>This will:</p>
6767- <ol>
7979+ <p class="mb-4">This will:</p>
8080+ <ol class="list-decimal list-inside space-y-2 ml-4 mb-6">
6881 <li>Open your browser for device authorization</li>
6982 <li>Display a code to confirm</li>
7083 <li>Store credentials securely</li>
7184 <li>Proceed with your push/pull operation</li>
7285 </ol>
73867474- <div class="success">
7575- <strong>Success!</strong> Once authenticated, Docker commands work normally without any additional steps.
8787+ <div class="alert alert-success">
8888+ <i data-lucide="check-circle" class="size-5"></i>
8989+ <span>Once authenticated, Docker commands work normally without any additional steps.</span>
7690 </div>
7777- </div>
9191+ </section>
78927979- <div class="install-section">
8080- <h2>Alternative: Use docker login</h2>
8181- <p>You can also use <code>docker login</code> with your ATProto app password:</p>
9393+ <section>
9494+ <h2 class="text-xl font-semibold mb-4">Alternative: Use docker login</h2>
9595+ <p class="mb-4">You can also use <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">docker login</code> with your ATProto app password:</p>
82968383- <ol>
8484- <li>Generate an app password at <a href="https://bsky.app/settings/app-passwords" target="_blank">bsky.app/settings/app-passwords</a></li>
8585- <li>Run: <code>docker login {{ .RegistryURL }}</code></li>
9797+ <ol class="list-decimal list-inside space-y-2 ml-4 mb-6">
9898+ <li>Generate an app password at <a href="https://bsky.app/settings/app-passwords" target="_blank" class="link link-primary">bsky.app/settings/app-passwords</a></li>
9999+ <li>Run: <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">docker login {{ .RegistryURL }}</code></li>
86100 <li>Enter your handle as username</li>
87101 <li>Enter your app password</li>
88102 </ol>
891039090- <div class="note">
9191- <strong>Note:</strong> Create an app password at <a href="https://bsky.app/settings/app-passwords" target="_blank">bsky.app/settings/app-passwords</a>.
104104+ <div class="alert alert-info">
105105+ <i data-lucide="info" class="size-5"></i>
106106+ <span>Create an app password at <a href="https://bsky.app/settings/app-passwords" target="_blank" class="underline font-medium hover:no-underline">bsky.app/settings/app-passwords</a>.</span>
92107 </div>
9393- </div>
108108+ </section>
941099595- <div class="install-section">
9696- <h2>Troubleshooting</h2>
110110+ <section>
111111+ <h2 class="text-xl font-semibold mb-4">Troubleshooting</h2>
971129898- <h3>Command not found</h3>
9999- <p>Ensure the credential helper is in your PATH:</p>
100100- <div class="code-block"><code># Check if installed
101101-which docker-credential-atcr
113113+ <h3 class="text-lg font-medium mb-3">Command not found</h3>
114114+ <p class="mb-4">Ensure the credential helper is in your PATH:</p>
115115+ <div class="mockup-code bg-base-300 text-base-content mb-6">
116116+ <pre data-prefix="#" class="text-base-content/50"><code>Check if installed</code></pre>
117117+ <pre data-prefix="$"><code>which docker-credential-atcr</code></pre>
118118+ <pre></pre>
119119+ <pre data-prefix="#" class="text-base-content/50"><code>Add to PATH if needed</code></pre>
120120+ <pre data-prefix="$"><code>export PATH="/usr/local/bin:$PATH"</code></pre>
121121+ </div>
102122103103-# Add to PATH if needed
104104-export PATH="/usr/local/bin:$PATH"</code></div>
123123+ <h3 class="text-lg font-medium mb-3">Still having issues?</h3>
124124+ <p>Check the <a href="https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/INSTALLATION.md" class="link link-primary">full documentation</a> or <a href="https://tangled.org/@evan.jarrett.net/at-container-registry/issues" class="link link-primary">open an issue</a>.</p>
125125+ </section>
105126106106- <h3>Still having issues?</h3>
107107- <p>Check the <a href="https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/INSTALLATION.md">full documentation</a> or <a href="https://tangled.org/@evan.jarrett.net/at-container-registry/issues">open an issue</a>.</p>
108108- </div>
109109-110110- <div class="install-section">
111111- <h2>Security</h2>
112112- <ul>
113113- <li>Credentials are stored in <code>~/.atcr/device.json</code> with secure permissions (0600)</li>
127127+ <section>
128128+ <h2 class="text-xl font-semibold mb-4">Security</h2>
129129+ <ul class="list-disc list-inside space-y-2 ml-4">
130130+ <li>Credentials are stored in <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">~/.atcr/device.json</code> with secure permissions (0600)</li>
114131 <li>Device secrets are issued per-device and can be revoked anytime</li>
115132 <li>No passwords are stored locally</li>
116133 <li>Uses ATProto OAuth with device authorization flow</li>
117134 </ul>
118118- </div>
135135+ </section>
119136 </div>
120137 </main>
121138···123140 function showPlatform(platform) {
124141 // Update tabs
125142 document.querySelectorAll('.platform-tab').forEach(tab => {
126126- tab.classList.remove('active');
143143+ tab.classList.remove('btn-primary');
144144+ tab.classList.add('btn-ghost');
127145 });
128128- event.target.classList.add('active');
146146+ event.target.classList.remove('btn-ghost');
147147+ event.target.classList.add('btn-primary');
129148130149 // Update content
131150 document.querySelectorAll('.platform-content').forEach(content => {
132132- content.classList.remove('active');
151151+ content.classList.add('hidden');
133152 });
134134- document.getElementById(platform + '-content').classList.add('active');
153153+ document.getElementById(platform + '-content').classList.remove('hidden');
135154 }
136155 </script>
137156
+169-165
pkg/appview/templates/pages/privacy.html
···88<body>
99 {{ template "nav" . }}
10101111- <main class="container">
1212- <div class="legal-page">
1313- <h1>Privacy Policy - AT Container Registry (atcr.io)</h1>
1414- <p class="legal-updated"><em>Last updated: January 2025</em></p>
1111+ <main class="container mx-auto px-4 py-8 max-w-4xl">
1212+ <h1 class="text-3xl font-bold mb-2">Privacy Policy - AT Container Registry (atcr.io)</h1>
1313+ <p class="text-base-content/60 mb-8"><em>Last updated: January 2025</em></p>
15141616- <div class="legal-section">
1717- <h2>Data We Collect and Store</h2>
1515+ <div class="prose prose-sm max-w-none space-y-8">
1616+ <section>
1717+ <h2 class="text-xl font-semibold text-primary">Data We Collect and Store</h2>
18181919- <h3>Data Stored on Your PDS (Controlled by You)</h3>
2020- <p>When you use AT Container Registry, records are written to your Personal Data Server (PDS) under the <code>io.atcr.*</code> namespace. This data is stored on infrastructure you or your PDS hosting provider controls. We do not control this data, and its retention and deletion is governed by your PDS provider's policies.</p>
1919+ <h3 class="text-lg font-medium mt-4">Data Stored on Your PDS (Controlled by You)</h3>
2020+ <p>When you use AT Container Registry, records are written to your Personal Data Server (PDS) under the <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">io.atcr.*</code> namespace. This data is stored on infrastructure you or your PDS hosting provider controls. We do not control this data, and its retention and deletion is governed by your PDS provider's policies.</p>
21212222- <h3>Data Stored on Our Infrastructure</h3>
2222+ <h3 class="text-lg font-medium mt-6">Data Stored on Our Infrastructure</h3>
23232424- <p><strong>Layer Records:</strong> Our hold services (e.g., <code>hold01.atcr.io</code>) maintain records in their embedded PDS that reference container image layers you publish. These records are public and link your AT Protocol identity (DID) to content-addressed SHA identifiers.</p>
2424+ <p><strong>Layer Records:</strong> Our hold services (e.g., <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">hold01.atcr.io</code>) maintain records in their embedded PDS that reference container image layers you publish. These records are public and link your AT Protocol identity (DID) to content-addressed SHA identifiers.</p>
25252626 <p><strong>OCI Blobs:</strong> Container image layers are stored in our object storage (S3). These blobs are content-addressed and deduplicated—meaning identical layers uploaded by different users are stored only once.</p>
27272828 <p><strong>Authentication Data:</strong></p>
2929- <ul>
2929+ <ul class="list-disc list-inside space-y-1 ml-4">
3030 <li>OAuth tokens obtained during sign-in</li>
3131 <li>Web UI session tokens</li>
3232 <li>Docker credential helper device tokens, including:
3333- <ul>
3333+ <ul class="list-disc list-inside ml-6 mt-1 space-y-1">
3434 <li>IP address</li>
3535 <li>Device name</li>
3636 <li>Token creation and last-used timestamps</li>
···3838 </li>
3939 </ul>
40404141- <p><strong>Cached PDS Data:</strong> We may cache data from your PDS in our database to improve performance and reduce load on your PDS. This cached data mirrors public information already stored on your PDS.</p>
4141+ <p class="mt-4"><strong>Cached PDS Data:</strong> We may cache data from your PDS in our database to improve performance and reduce load on your PDS. This cached data mirrors public information already stored on your PDS.</p>
42424343 <p><strong>Server Logs:</strong> Our logs may include your handle, DID, IP address, timestamps, and actions performed. Logs are currently ephemeral but may be retained in the future for security and debugging purposes.</p>
4444- </div>
4444+ </section>
45454646- <div class="legal-section">
4747- <h2>Our Services and Their Data</h2>
4646+ <section>
4747+ <h2 class="text-xl font-semibold text-primary">Our Services and Their Data</h2>
48484949 <p>AT Container Registry consists of multiple services, each with distinct data responsibilities:</p>
50505151- <h3>AppView (atcr.io)</h3>
5151+ <h3 class="text-lg font-medium mt-4">AppView (atcr.io)</h3>
5252 <p>The registry frontend you interact with directly. Stores:</p>
5353- <ul>
5353+ <ul class="list-disc list-inside space-y-1 ml-4">
5454 <li>OAuth sessions and tokens for authentication</li>
5555 <li>Device tokens for the Docker credential helper</li>
5656 <li>Web UI sessions</li>
5757 <li>Cached metadata from your PDS (indexes for search and display)</li>
5858 </ul>
59596060- <h3>ATCR-Hosted Hold Services</h3>
6161- <p>Storage backends we operate (e.g., <code>hold01.atcr.io</code>). Each hold has an embedded PDS and stores:</p>
6262- <ul>
6060+ <h3 class="text-lg font-medium mt-6">ATCR-Hosted Hold Services</h3>
6161+ <p>Storage backends we operate (e.g., <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">hold01.atcr.io</code>). Each hold has an embedded PDS and stores:</p>
6262+ <ul class="list-disc list-inside space-y-1 ml-4">
6363 <li>OCI blobs (container image layers) in object storage</li>
6464 <li>Layer records in the hold's embedded PDS linking your DID to blob references</li>
6565 <li>Crew membership records for access control</li>
6666 </ul>
6767- <p>Hold services on <code>*.atcr.io</code> domains are operated by us and covered by this policy.</p>
6767+ <p class="mt-2">Hold services on <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">*.atcr.io</code> domains are operated by us and covered by this policy.</p>
68686969- <h3>User-Deployed Hold Services (BYOS)</h3>
6969+ <h3 class="text-lg font-medium mt-6">User-Deployed Hold Services (BYOS)</h3>
7070 <p>You may use "Bring Your Own Storage" by deploying your own hold service. Data on user-deployed holds is governed by that operator's privacy policy, not ours. We can request deletion on your behalf but cannot guarantee it for services we do not control.</p>
7171- </div>
7171+ </section>
72727373- <div class="legal-section">
7474- <h2>Data Sharing and Deduplication</h2>
7373+ <section>
7474+ <h2 class="text-xl font-semibold text-primary">Data Sharing and Deduplication</h2>
75757676 <p>OCI container images use content-addressable storage. When you push an image layer, it is identified by its cryptographic hash (SHA256). If another user pushes an identical layer, both users reference the same underlying blob. This is standard practice for container registries and enables efficient storage and distribution.</p>
77777878 <p><strong>What this means for your data:</strong></p>
7979- <ul>
7979+ <ul class="list-disc list-inside space-y-1 ml-4">
8080 <li>Layer content is not uniquely "yours" if other users have pushed identical content</li>
8181 <li>Public SHA references may be associated with your AT Protocol identity</li>
8282 <li>Deleting your records does not delete blob data that other users also reference</li>
8383 </ul>
8484- </div>
8484+ </section>
85858686- <div class="legal-section">
8787- <h2>Your Rights Under GDPR</h2>
8686+ <section>
8787+ <h2 class="text-xl font-semibold text-primary">Your Rights Under GDPR</h2>
88888989 <p>If you are located in the European Economic Area (EEA), you have the following rights:</p>
90909191- <h3>Right to Access</h3>
9191+ <h3 class="text-lg font-medium mt-4">Right to Access</h3>
9292 <p>You may request a copy of all personal data we store about you. This includes:</p>
9393- <ul>
9393+ <ul class="list-disc list-inside space-y-1 ml-4">
9494 <li>Layer records associated with your DID on our PDS</li>
9595 <li>Server logs containing your handle, DID, IP address, or actions (if retained)</li>
9696 <li>OAuth tokens, web UI sessions, and device tokens</li>
9797 <li>Cached PDS data</li>
9898 <li>List of registered devices (credential helper)</li>
9999 </ul>
100100- <p class="note">Note: Data stored on your own PDS is already under your control and accessible to you directly.</p>
100100+ <p class="text-base-content/70 text-sm mt-2">Note: Data stored on your own PDS is already under your control and accessible to you directly.</p>
101101102102- <h3>Right to Erasure ("Right to be Forgotten")</h3>
102102+ <h3 class="text-lg font-medium mt-6">Right to Erasure ("Right to be Forgotten")</h3>
103103 <p>You may request deletion of your data via the account settings page. Due to our technical architecture, deletion works as follows:</p>
104104105105- <p><strong>Immediately deleted from AppView:</strong></p>
106106- <ul>
105105+ <p class="mt-4"><strong>Immediately deleted from AppView:</strong></p>
106106+ <ul class="list-disc list-inside space-y-1 ml-4">
107107 <li>OAuth tokens, web UI sessions, and device tokens</li>
108108 <li>Cached PDS data (manifest and tag indexes)</li>
109109 <li>Server logs containing your identifiers (deleted or anonymized, if retained)</li>
110110 </ul>
111111112112- <p><strong>Immediately deleted from ATCR-hosted holds:</strong></p>
113113- <ul>
112112+ <p class="mt-4"><strong>Immediately deleted from ATCR-hosted holds:</strong></p>
113113+ <ul class="list-disc list-inside space-y-1 ml-4">
114114 <li>Layer records in the hold's embedded PDS that reference your DID</li>
115115 <li>Crew membership records</li>
116116 </ul>
117117118118- <p><strong>Deleted within 30 days from ATCR-hosted holds:</strong></p>
119119- <ul>
118118+ <p class="mt-4"><strong>Deleted within 30 days from ATCR-hosted holds:</strong></p>
119119+ <ul class="list-disc list-inside space-y-1 ml-4">
120120 <li>OCI blobs in object storage that are no longer referenced by any user (via garbage collection)</li>
121121 </ul>
122122123123- <p><strong>User-deployed holds:</strong></p>
124124- <ul>
123123+ <p class="mt-4"><strong>User-deployed holds:</strong></p>
124124+ <ul class="list-disc list-inside space-y-1 ml-4">
125125 <li>We attempt to delete your data via API, but success depends on hold availability</li>
126126 <li>Data on holds we do not operate is governed by that operator's policies</li>
127127 </ul>
128128129129- <p><strong>Cannot be deleted by us:</strong></p>
130130- <ul>
129129+ <p class="mt-4"><strong>Cannot be deleted by us:</strong></p>
130130+ <ul class="list-disc list-inside space-y-1 ml-4">
131131 <li>Records stored on your own PDS (you control these, or your PDS provider does)</li>
132132 <li>Blob data that is also referenced by other users (deduplicated content)</li>
133133 </ul>
134134135135- <p><strong>Optional: Delete AT Protocol Records</strong></p>
136136- <p>When deleting your account, you may optionally authorize us to delete <code>io.atcr.*</code> records from your PDS. This requires an active OAuth session and is optional because:</p>
137137- <ul>
135135+ <p class="mt-4"><strong>Optional: Delete AT Protocol Records</strong></p>
136136+ <p>When deleting your account, you may optionally authorize us to delete <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">io.atcr.*</code> records from your PDS. This requires an active OAuth session and is optional because:</p>
137137+ <ul class="list-disc list-inside space-y-1 ml-4">
138138 <li>Your PDS is controlled by you or your hosting provider, not us</li>
139139 <li>You may delete these records yourself at any time</li>
140140 <li>We have no ongoing obligation to manage data on infrastructure we do not control</li>
141141 </ul>
142142143143- <h3>Right to Rectification</h3>
143143+ <h3 class="text-lg font-medium mt-6">Right to Rectification</h3>
144144 <p>You may update your data through normal use of the service. Data stored on your PDS is under your direct control.</p>
145145146146- <h3>Right to Data Portability</h3>
146146+ <h3 class="text-lg font-medium mt-6">Right to Data Portability</h3>
147147 <p>AT Protocol is designed for data portability. Your records are stored in an open, documented format on your PDS and can be exported or migrated at any time.</p>
148148149149- <h3>Right to Object / Restrict Processing</h3>
149149+ <h3 class="text-lg font-medium mt-6">Right to Object / Restrict Processing</h3>
150150 <p>You may revoke our OAuth access at any time through your PDS provider's settings. This will prevent us from reading or writing records to your PDS.</p>
151151- </div>
151151+ </section>
152152153153- <div class="legal-section">
154154- <h2>Your Rights Under CCPA</h2>
153153+ <section>
154154+ <h2 class="text-xl font-semibold text-primary">Your Rights Under CCPA</h2>
155155156156 <p>If you are a California resident, you have the following rights under the California Consumer Privacy Act:</p>
157157158158- <h3>Right to Know</h3>
158158+ <h3 class="text-lg font-medium mt-4">Right to Know</h3>
159159 <p>You may request disclosure of:</p>
160160- <ul>
160160+ <ul class="list-disc list-inside space-y-1 ml-4">
161161 <li>The categories of personal information we collect</li>
162162 <li>The purposes for which we use your personal information</li>
163163 <li>The categories of third parties with whom we share your personal information</li>
164164 </ul>
165165166166- <h3>Right to Delete</h3>
166166+ <h3 class="text-lg font-medium mt-6">Right to Delete</h3>
167167 <p>You may delete your personal information via the account settings page, subject to the same technical limitations described in the GDPR section above. For data not accessible through self-service, we will respond to requests within 45 days, except where retention is necessary for:</p>
168168- <ul>
168168+ <ul class="list-disc list-inside space-y-1 ml-4">
169169 <li>Completing the transaction for which the data was collected</li>
170170 <li>Security and fraud prevention</li>
171171 <li>Legal compliance</li>
172172 </ul>
173173174174- <h3>Right to Non-Discrimination</h3>
174174+ <h3 class="text-lg font-medium mt-6">Right to Non-Discrimination</h3>
175175 <p>We will not discriminate against you for exercising your CCPA rights.</p>
176176177177- <h3>Categories of Personal Information Collected</h3>
178178- <table>
179179- <thead>
180180- <tr>
181181- <th>Category</th>
182182- <th>Examples</th>
183183- <th>Collected</th>
184184- </tr>
185185- </thead>
186186- <tbody>
187187- <tr>
188188- <td>Identifiers</td>
189189- <td>DID, handle, IP address, device name</td>
190190- <td>Yes</td>
191191- </tr>
192192- <tr>
193193- <td>Internet activity</td>
194194- <td>Access logs, usage data, actions performed</td>
195195- <td>Yes</td>
196196- </tr>
197197- <tr>
198198- <td>Geolocation</td>
199199- <td>Approximate location via IP</td>
200200- <td>Yes</td>
201201- </tr>
202202- </tbody>
203203- </table>
177177+ <h3 class="text-lg font-medium mt-6">Categories of Personal Information Collected</h3>
178178+ <div class="overflow-x-auto mt-4">
179179+ <table class="table table-zebra w-full">
180180+ <thead>
181181+ <tr>
182182+ <th>Category</th>
183183+ <th>Examples</th>
184184+ <th>Collected</th>
185185+ </tr>
186186+ </thead>
187187+ <tbody>
188188+ <tr>
189189+ <td>Identifiers</td>
190190+ <td>DID, handle, IP address, device name</td>
191191+ <td>Yes</td>
192192+ </tr>
193193+ <tr>
194194+ <td>Internet activity</td>
195195+ <td>Access logs, usage data, actions performed</td>
196196+ <td>Yes</td>
197197+ </tr>
198198+ <tr>
199199+ <td>Geolocation</td>
200200+ <td>Approximate location via IP</td>
201201+ <td>Yes</td>
202202+ </tr>
203203+ </tbody>
204204+ </table>
205205+ </div>
204206205205- <p>We do not sell or share your personal information for cross-context behavioral advertising.</p>
206206- </div>
207207+ <p class="mt-4">We do not sell or share your personal information for cross-context behavioral advertising.</p>
208208+ </section>
207209208208- <div class="legal-section">
209209- <h2>Data Retention</h2>
210210+ <section>
211211+ <h2 class="text-xl font-semibold text-primary">Data Retention</h2>
210212211211- <table>
212212- <thead>
213213- <tr>
214214- <th>Data Type</th>
215215- <th>Service</th>
216216- <th>Retention Period</th>
217217- </tr>
218218- </thead>
219219- <tbody>
220220- <tr>
221221- <td>OAuth tokens</td>
222222- <td>AppView</td>
223223- <td>Until revoked or logout</td>
224224- </tr>
225225- <tr>
226226- <td>Web UI session tokens</td>
227227- <td>AppView</td>
228228- <td>Until logout or expiration</td>
229229- </tr>
230230- <tr>
231231- <td>Device tokens (credential helper)</td>
232232- <td>AppView</td>
233233- <td>Until revoked by user</td>
234234- </tr>
235235- <tr>
236236- <td>Cached PDS data</td>
237237- <td>AppView</td>
238238- <td>Refreshed periodically; deleted on account deletion</td>
239239- </tr>
240240- <tr>
241241- <td>Server logs</td>
242242- <td>AppView</td>
243243- <td>Currently ephemeral; this policy will be updated if log retention is implemented</td>
244244- </tr>
245245- <tr>
246246- <td>Layer records</td>
247247- <td>Hold PDS</td>
248248- <td>Until you request deletion</td>
249249- </tr>
250250- <tr>
251251- <td>OCI blobs</td>
252252- <td>Hold Storage</td>
253253- <td>Until no longer referenced (pruned within 30 days)</td>
254254- </tr>
255255- </tbody>
256256- </table>
257257- </div>
213213+ <div class="overflow-x-auto mt-4">
214214+ <table class="table table-zebra w-full">
215215+ <thead>
216216+ <tr>
217217+ <th>Data Type</th>
218218+ <th>Service</th>
219219+ <th>Retention Period</th>
220220+ </tr>
221221+ </thead>
222222+ <tbody>
223223+ <tr>
224224+ <td>OAuth tokens</td>
225225+ <td>AppView</td>
226226+ <td>Until revoked or logout</td>
227227+ </tr>
228228+ <tr>
229229+ <td>Web UI session tokens</td>
230230+ <td>AppView</td>
231231+ <td>Until logout or expiration</td>
232232+ </tr>
233233+ <tr>
234234+ <td>Device tokens (credential helper)</td>
235235+ <td>AppView</td>
236236+ <td>Until revoked by user</td>
237237+ </tr>
238238+ <tr>
239239+ <td>Cached PDS data</td>
240240+ <td>AppView</td>
241241+ <td>Refreshed periodically; deleted on account deletion</td>
242242+ </tr>
243243+ <tr>
244244+ <td>Server logs</td>
245245+ <td>AppView</td>
246246+ <td>Currently ephemeral; this policy will be updated if log retention is implemented</td>
247247+ </tr>
248248+ <tr>
249249+ <td>Layer records</td>
250250+ <td>Hold PDS</td>
251251+ <td>Until you request deletion</td>
252252+ </tr>
253253+ <tr>
254254+ <td>OCI blobs</td>
255255+ <td>Hold Storage</td>
256256+ <td>Until no longer referenced (pruned within 30 days)</td>
257257+ </tr>
258258+ </tbody>
259259+ </table>
260260+ </div>
261261+ </section>
258262259259- <div class="legal-section">
260260- <h2>Important Notes on AT Protocol Architecture</h2>
263263+ <section>
264264+ <h2 class="text-xl font-semibold text-primary">Important Notes on AT Protocol Architecture</h2>
261265262266 <p>AT Container Registry is built on the AT Protocol, which has a unique data architecture:</p>
263267264264- <ol>
268268+ <ol class="list-decimal list-inside space-y-2 ml-4 mt-4">
265269 <li><strong>You control your data.</strong> Most data associated with your use of AT Container Registry is stored on your Personal Data Server (PDS), which you or your chosen provider controls.</li>
266270 <li><strong>Public by design.</strong> AT Protocol data is designed to be public and distributed. Records you create, including container image references, are publicly visible and may be replicated across the network.</li>
267271 <li><strong>Content-addressed storage.</strong> OCI blobs are identified by their cryptographic hash. This means blob data is inherently pseudonymous—it cannot be attributed to you without the corresponding records that reference it.</li>
268272 <li><strong>Deletion limitations.</strong> Because AT Protocol is distributed, we cannot guarantee that copies of public records have not been made by other participants in the network. We can only delete data on infrastructure we control.</li>
269273 </ol>
270270- </div>
274274+ </section>
271275272272- <div class="legal-section">
273273- <h2>Bring Your Own Storage (BYOS)</h2>
276276+ <section>
277277+ <h2 class="text-xl font-semibold text-primary">Bring Your Own Storage (BYOS)</h2>
274278275279 <p>AT Container Registry supports "Bring Your Own Storage" where users can deploy their own hold services to store container image blobs. This section explains how BYOS affects your privacy rights.</p>
276280277277- <h3>ATCR-Hosted Holds</h3>
278278- <p>Hold services on <code>*.atcr.io</code> domains (e.g., <code>hold01.atcr.io</code>) are operated by us and fully covered by this privacy policy. We can fulfill all data access, export, and deletion requests for these services.</p>
281281+ <h3 class="text-lg font-medium mt-4">ATCR-Hosted Holds</h3>
282282+ <p>Hold services on <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">*.atcr.io</code> domains (e.g., <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">hold01.atcr.io</code>) are operated by us and fully covered by this privacy policy. We can fulfill all data access, export, and deletion requests for these services.</p>
279283280280- <h3>User-Deployed Holds</h3>
284284+ <h3 class="text-lg font-medium mt-6">User-Deployed Holds</h3>
281285 <p>If you use a hold service not operated by us:</p>
282282- <ul>
286286+ <ul class="list-disc list-inside space-y-1 ml-4">
283287 <li>That hold's data practices are governed by its operator's privacy policy, not ours</li>
284288 <li>When you request account deletion, we attempt to delete your data from all holds via API</li>
285289 <li>We cannot guarantee deletion for holds that are offline or refuse the request</li>
286290 <li>You should contact that hold's operator directly for data requests we cannot fulfill</li>
287291 </ul>
288292289289- <h3>If You Operate a Hold</h3>
293293+ <h3 class="text-lg font-medium mt-6">If You Operate a Hold</h3>
290294 <p>If you deploy your own hold service and allow other users to store data on it, you become a data controller for that data under GDPR/CCPA. You are responsible for:</p>
291291- <ul>
295295+ <ul class="list-disc list-inside space-y-1 ml-4">
292296 <li>Responding to deletion requests from users of your hold</li>
293297 <li>Implementing appropriate data retention policies</li>
294298 <li>Publishing your own privacy policy if required by law</li>
295299 </ul>
296296- </div>
300300+ </section>
297301298298- <div class="legal-section">
299299- <h2>How to Exercise Your Rights</h2>
302302+ <section>
303303+ <h2 class="text-xl font-semibold text-primary">How to Exercise Your Rights</h2>
300304301301- <h3>Self-Service (via Settings)</h3>
305305+ <h3 class="text-lg font-medium mt-4">Self-Service (via Settings)</h3>
302306 <p>Most data management can be done directly through your account settings at atcr.io:</p>
303303- <ul>
304304- <li><strong>Delete your data:</strong> Use the "Delete Account" button in settings. This will remove your layer records, cached data, and authentication tokens. You may also choose to have us delete <code>io.atcr.*</code> records from your PDS (requires active OAuth session).</li>
307307+ <ul class="list-disc list-inside space-y-1 ml-4">
308308+ <li><strong>Delete your data:</strong> Use the "Delete Account" button in settings. This will remove your layer records, cached data, and authentication tokens. You may also choose to have us delete <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">io.atcr.*</code> records from your PDS (requires active OAuth session).</li>
305309 <li><strong>Revoke device tokens:</strong> Manage and revoke credential helper devices in settings.</li>
306310 <li><strong>Update your data:</strong> Corrections happen through normal use of the service.</li>
307311 </ul>
308312309309- <h3>Contact Us</h3>
313313+ <h3 class="text-lg font-medium mt-6">Contact Us</h3>
310314 <p>For requests we cannot fulfill through self-service, such as:</p>
311311- <ul>
315315+ <ul class="list-disc list-inside space-y-1 ml-4">
312316 <li>Copies of server logs containing your data</li>
313317 <li>Database records not exposed in the UI</li>
314318 <li>Questions about this policy</li>
315319 </ul>
316320317317- <p><strong>Email:</strong> <a href="mailto:privacy@atcr.io">privacy@atcr.io</a></p>
321321+ <p class="mt-4"><strong>Email:</strong> <a href="mailto:privacy@atcr.io" class="link link-primary">privacy@atcr.io</a></p>
318322319319- <p>Please include your AT Protocol DID or handle so we can verify your identity.</p>
323323+ <p class="mt-2">Please include your AT Protocol DID or handle so we can verify your identity.</p>
320324321321- <p>We will respond to requests within 30 days (GDPR) or 45 days (CCPA).</p>
322322- </div>
325325+ <p class="mt-2">We will respond to requests within 30 days (GDPR) or 45 days (CCPA).</p>
326326+ </section>
323327324324- <div class="legal-section">
325325- <h2>Contact</h2>
328328+ <section>
329329+ <h2 class="text-xl font-semibold text-primary">Contact</h2>
326330327331 <p>For questions about this privacy policy or to exercise your data rights, contact:</p>
328332329329- <p><strong>Email:</strong> <a href="mailto:privacy@atcr.io">privacy@atcr.io</a></p>
330330- <p><strong>Website:</strong> <a href="https://atcr.io">https://atcr.io</a></p>
331331- </div>
333333+ <p class="mt-4"><strong>Email:</strong> <a href="mailto:privacy@atcr.io" class="link link-primary">privacy@atcr.io</a></p>
334334+ <p><strong>Website:</strong> <a href="https://atcr.io" class="link link-primary">https://atcr.io</a></p>
335335+ </section>
332336 </div>
333337 </main>
334338
+9-6
pkg/appview/templates/pages/search.html
···88<body>
99 {{ template "nav" . }}
10101111- <main class="container">
1212- <div class="home-page">
1111+ <main class="container mx-auto px-4">
1212+ <div class="max-w-4xl mx-auto py-8">
1313 {{ if .SearchQuery }}
1414- <h1>Search Results for "{{ .SearchQuery }}"</h1>
1414+ <h1 class="text-3xl font-bold mb-6">Search Results for "{{ .SearchQuery }}"</h1>
1515 {{ else }}
1616- <h1>Search</h1>
1717- <p>Enter a search term to find images.</p>
1616+ <h1 class="text-3xl font-bold mb-2">Search</h1>
1717+ <p class="text-base-content/60 mb-6">Enter a search term to find images.</p>
1818 {{ end }}
19192020 <div id="push-list" hx-get="/api/search-results?q={{ .SearchQuery }}" hx-trigger="load" hx-swap="innerHTML">
2121 <!-- Initial loading state -->
2222 {{ if .SearchQuery }}
2323- <div class="loading">Searching...</div>
2323+ <div class="flex items-center gap-2 text-base-content/60">
2424+ <span class="loading loading-spinner loading-sm"></span>
2525+ <span>Searching...</span>
2626+ </div>
2427 {{ end }}
2528 </div>
2629 </div>
+88-88
pkg/appview/templates/pages/terms.html
···88<body>
99 {{ template "nav" . }}
10101111- <main class="container">
1212- <div class="legal-page">
1313- <h1>Terms of Service - AT Container Registry (atcr.io)</h1>
1414- <p class="legal-updated"><em>Last updated: January 2025</em></p>
1111+ <main class="container mx-auto px-4 py-8 max-w-4xl">
1212+ <h1 class="text-3xl font-bold mb-2">Terms of Service - AT Container Registry (atcr.io)</h1>
1313+ <p class="text-base-content/60 mb-8"><em>Last updated: January 2025</em></p>
15141616- <p>These Terms of Service ("Terms") govern your use of AT Container Registry ("atcr.io", "the Service", "we", "us", "our"). By using the Service, you agree to these Terms. If you do not agree, do not use the Service.</p>
1515+ <p class="mb-8">These Terms of Service ("Terms") govern your use of AT Container Registry ("atcr.io", "the Service", "we", "us", "our"). By using the Service, you agree to these Terms. If you do not agree, do not use the Service.</p>
17161818- <div class="legal-section">
1919- <h2>1. Description of Service</h2>
1717+ <div class="prose prose-sm max-w-none space-y-8">
1818+ <section>
1919+ <h2 class="text-xl font-semibold text-primary">1. Description of Service</h2>
2020 <p>AT Container Registry is an OCI-compatible container registry built on the AT Protocol. The Service allows you to store, distribute, and manage container images using your AT Protocol identity.</p>
2121- </div>
2121+ </section>
22222323- <div class="legal-section">
2424- <h2>2. Accounts and Access</h2>
2323+ <section>
2424+ <h2 class="text-xl font-semibold text-primary">2. Accounts and Access</h2>
25252626- <h3>2.1 AT Protocol Identity</h3>
2626+ <h3 class="text-lg font-medium mt-4">2.1 AT Protocol Identity</h3>
2727 <p>Access to the Service requires an AT Protocol identity (DID). You are responsible for maintaining the security of your PDS credentials and any device tokens issued by the Service.</p>
28282929- <h3>2.2 Account Responsibility</h3>
2929+ <h3 class="text-lg font-medium mt-6">2.2 Account Responsibility</h3>
3030 <p>You are responsible for all activity under your account, whether authorized by you or not. Notify us immediately if you suspect unauthorized access.</p>
31313232- <h3>2.3 Age Requirement</h3>
3232+ <h3 class="text-lg font-medium mt-6">2.3 Age Requirement</h3>
3333 <p>You must be at least 13 years old to use the Service. If you are under 18, you must have permission from a parent or legal guardian.</p>
3434- </div>
3434+ </section>
35353636- <div class="legal-section">
3737- <h2>3. Acceptable Use</h2>
3636+ <section>
3737+ <h2 class="text-xl font-semibold text-primary">3. Acceptable Use</h2>
38383939 <p>You agree NOT to use the Service to:</p>
4040- <ul>
4040+ <ul class="list-disc list-inside space-y-1 ml-4">
4141 <li>Store or distribute malware, viruses, or malicious code</li>
4242 <li>Store or distribute illegal content under applicable law</li>
4343 <li>Infringe on intellectual property rights of others</li>
···4848 <li>Impersonate others or misrepresent your affiliation with any person or entity</li>
4949 </ul>
50505151- <p>We reserve the right to determine what constitutes a violation of these terms.</p>
5252- </div>
5151+ <p class="mt-4">We reserve the right to determine what constitutes a violation of these terms.</p>
5252+ </section>
53535454- <div class="legal-section">
5555- <h2>4. Content and Intellectual Property</h2>
5454+ <section>
5555+ <h2 class="text-xl font-semibold text-primary">4. Content and Intellectual Property</h2>
56565757- <h3>4.1 Your Content</h3>
5757+ <h3 class="text-lg font-medium mt-4">4.1 Your Content</h3>
5858 <p>You retain ownership of container images and other content you upload to the Service. By uploading content, you grant us a license to store, cache, and distribute that content as necessary to operate the Service.</p>
59596060- <h3>4.2 Content-Addressed Storage</h3>
6060+ <h3 class="text-lg font-medium mt-6">4.2 Content-Addressed Storage</h3>
6161 <p>The Service uses content-addressed, deduplicated storage. Identical image layers uploaded by different users are stored once and shared. This means:</p>
6262- <ul>
6262+ <ul class="list-disc list-inside space-y-1 ml-4">
6363 <li>You cannot delete blob data that is also referenced by other users</li>
6464 <li>Blob data alone cannot identify you; only the associated records link content to your identity</li>
6565 </ul>
66666767- <h3>4.3 Public Data</h3>
6767+ <h3 class="text-lg font-medium mt-6">4.3 Public Data</h3>
6868 <p>AT Protocol records are public by design. Container image references, tags, and metadata associated with your identity are publicly visible. Do not store sensitive information in image tags, labels, or other public metadata.</p>
69697070- <h3>4.4 Content Removal</h3>
7070+ <h3 class="text-lg font-medium mt-6">4.4 Content Removal</h3>
7171 <p>We may remove content that violates these Terms or applicable law. We may also remove content in response to valid legal requests.</p>
7272- </div>
7272+ </section>
73737474- <div class="legal-section">
7575- <h2>5. Usage Quotas and Limits</h2>
7474+ <section>
7575+ <h2 class="text-xl font-semibold text-primary">5. Usage Quotas and Limits</h2>
76767777- <h3>5.1 Free Tier</h3>
7777+ <h3 class="text-lg font-medium mt-4">5.1 Free Tier</h3>
7878 <p>The Service offers a free tier subject to usage quotas. These quotas may include limits on storage, bandwidth, or number of repositories. Current quotas are published in your account settings.</p>
79798080- <h3>5.2 Quota Changes</h3>
8080+ <h3 class="text-lg font-medium mt-6">5.2 Quota Changes</h3>
8181 <p>We may adjust free tier quotas at any time. We will make reasonable efforts to notify users of significant changes, but continued use after changes constitutes acceptance.</p>
82828383- <h3>5.3 Paid Tiers</h3>
8383+ <h3 class="text-lg font-medium mt-6">5.3 Paid Tiers</h3>
8484 <p>Paid tiers with higher quotas may be offered in the future. Paid tier terms will be provided at the time of purchase.</p>
8585- </div>
8585+ </section>
86868787- <div class="legal-section">
8888- <h2>6. Service Availability</h2>
8787+ <section>
8888+ <h2 class="text-xl font-semibold text-primary">6. Service Availability</h2>
89899090- <h3>6.1 No SLA for Free Tier</h3>
9090+ <h3 class="text-lg font-medium mt-4">6.1 No SLA for Free Tier</h3>
9191 <p>The free tier is provided on a best-effort basis. We make no guarantees regarding uptime, availability, or performance. The Service may be unavailable due to maintenance, infrastructure issues, or resource constraints.</p>
92929393- <h3>6.2 Service Changes</h3>
9393+ <h3 class="text-lg font-medium mt-6">6.2 Service Changes</h3>
9494 <p>We may modify, suspend, or discontinue the Service (or any part of it) at any time, with or without notice. We are not liable to you or any third party for any modification, suspension, or discontinuation.</p>
95959696- <h3>6.3 Data Durability</h3>
9696+ <h3 class="text-lg font-medium mt-6">6.3 Data Durability</h3>
9797 <p>While we take reasonable measures to protect your data, we do not guarantee data durability. You are responsible for maintaining backups of your container images.</p>
9898- </div>
9898+ </section>
9999100100- <div class="legal-section">
101101- <h2>7. AT Protocol Considerations</h2>
100100+ <section>
101101+ <h2 class="text-xl font-semibold text-primary">7. AT Protocol Considerations</h2>
102102103103- <h3>7.1 Distributed Architecture</h3>
103103+ <h3 class="text-lg font-medium mt-4">7.1 Distributed Architecture</h3>
104104 <p>The Service operates on the AT Protocol, a distributed network. Data written to your PDS is controlled by you or your PDS hosting provider, not by us.</p>
105105106106- <h3>7.2 Records on Your PDS</h3>
107107- <p>When you use the Service, records are written to your PDS under the <code>io.atcr.*</code> namespace. We can create, update, and delete these records only while you have granted us OAuth access. Revoking access does not automatically delete existing records.</p>
106106+ <h3 class="text-lg font-medium mt-6">7.2 Records on Your PDS</h3>
107107+ <p>When you use the Service, records are written to your PDS under the <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">io.atcr.*</code> namespace. We can create, update, and delete these records only while you have granted us OAuth access. Revoking access does not automatically delete existing records.</p>
108108109109- <h3>7.3 No Control Over Your PDS</h3>
109109+ <h3 class="text-lg font-medium mt-6">7.3 No Control Over Your PDS</h3>
110110 <p>We do not control your PDS. If your PDS is offline or your PDS provider terminates your account, we cannot restore your AT Protocol records.</p>
111111- </div>
111111+ </section>
112112113113- <div class="legal-section">
114114- <h2>8. Termination</h2>
113113+ <section>
114114+ <h2 class="text-xl font-semibold text-primary">8. Termination</h2>
115115116116- <h3>8.1 By You</h3>
116116+ <h3 class="text-lg font-medium mt-4">8.1 By You</h3>
117117 <p>You may stop using the Service at any time. To delete your data, use the account deletion option in settings or contact us.</p>
118118119119- <h3>8.2 By Us</h3>
119119+ <h3 class="text-lg font-medium mt-6">8.2 By Us</h3>
120120 <p>We may suspend or terminate your access to the Service at any time, for any reason, including but not limited to:</p>
121121- <ul>
121121+ <ul class="list-disc list-inside space-y-1 ml-4">
122122 <li>Violation of these Terms</li>
123123 <li>Abuse of the Service or its infrastructure</li>
124124 <li>Extended inactivity</li>
125125 <li>Legal requirements</li>
126126 </ul>
127127128128- <h3>8.3 Effect of Termination</h3>
128128+ <h3 class="text-lg font-medium mt-6">8.3 Effect of Termination</h3>
129129 <p>Upon termination, we will delete your data in accordance with our Privacy Policy. Deduplicated blob data referenced by other users will not be deleted.</p>
130130- </div>
130130+ </section>
131131132132- <div class="legal-section">
133133- <h2>9. Disclaimer of Warranties</h2>
132132+ <section>
133133+ <h2 class="text-xl font-semibold text-primary">9. Disclaimer of Warranties</h2>
134134135135- <p class="legal-disclaimer">THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.</p>
135135+ <p class="font-semibold uppercase text-sm">THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.</p>
136136137137- <p class="legal-disclaimer">WE DO NOT WARRANT THAT THE SERVICE WILL BE UNINTERRUPTED, ERROR-FREE, OR SECURE. WE DO NOT WARRANT THAT ANY DEFECTS WILL BE CORRECTED.</p>
138138- </div>
137137+ <p class="font-semibold uppercase text-sm mt-4">WE DO NOT WARRANT THAT THE SERVICE WILL BE UNINTERRUPTED, ERROR-FREE, OR SECURE. WE DO NOT WARRANT THAT ANY DEFECTS WILL BE CORRECTED.</p>
138138+ </section>
139139140140- <div class="legal-section">
141141- <h2>10. Limitation of Liability</h2>
140140+ <section>
141141+ <h2 class="text-xl font-semibold text-primary">10. Limitation of Liability</h2>
142142143143- <p class="legal-disclaimer">TO THE MAXIMUM EXTENT PERMITTED BY LAW, WE SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR GOODWILL, ARISING OUT OF OR RELATED TO YOUR USE OF THE SERVICE.</p>
143143+ <p class="font-semibold uppercase text-sm">TO THE MAXIMUM EXTENT PERMITTED BY LAW, WE SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR GOODWILL, ARISING OUT OF OR RELATED TO YOUR USE OF THE SERVICE.</p>
144144145145- <p class="legal-disclaimer">OUR TOTAL LIABILITY FOR ANY CLAIM ARISING OUT OF OR RELATED TO THESE TERMS OR THE SERVICE SHALL NOT EXCEED THE AMOUNT YOU PAID US IN THE TWELVE (12) MONTHS PRECEDING THE CLAIM, OR $50 USD, WHICHEVER IS GREATER.</p>
146146- </div>
145145+ <p class="font-semibold uppercase text-sm mt-4">OUR TOTAL LIABILITY FOR ANY CLAIM ARISING OUT OF OR RELATED TO THESE TERMS OR THE SERVICE SHALL NOT EXCEED THE AMOUNT YOU PAID US IN THE TWELVE (12) MONTHS PRECEDING THE CLAIM, OR $50 USD, WHICHEVER IS GREATER.</p>
146146+ </section>
147147148148- <div class="legal-section">
149149- <h2>11. Indemnification</h2>
148148+ <section>
149149+ <h2 class="text-xl font-semibold text-primary">11. Indemnification</h2>
150150151151 <p>You agree to indemnify and hold harmless AT Container Registry, its operators, and affiliates from any claims, damages, losses, or expenses (including reasonable legal fees) arising out of:</p>
152152- <ul>
152152+ <ul class="list-disc list-inside space-y-1 ml-4">
153153 <li>Your use of the Service</li>
154154 <li>Your violation of these Terms</li>
155155 <li>Your violation of any third-party rights</li>
156156 <li>Content you upload to the Service</li>
157157 </ul>
158158- </div>
158158+ </section>
159159160160- <div class="legal-section">
161161- <h2>12. Changes to Terms</h2>
160160+ <section>
161161+ <h2 class="text-xl font-semibold text-primary">12. Changes to Terms</h2>
162162163163 <p>We may update these Terms from time to time. If we make material changes, we will notify you by posting the updated Terms and updating the "Last updated" date. Your continued use of the Service after changes constitutes acceptance of the new Terms.</p>
164164- </div>
164164+ </section>
165165166166- <div class="legal-section">
167167- <h2>13. Governing Law</h2>
166166+ <section>
167167+ <h2 class="text-xl font-semibold text-primary">13. Governing Law</h2>
168168169169 <p>These Terms shall be governed by and construed in accordance with the laws of the State of Texas, United States, without regard to conflict of law principles.</p>
170170- </div>
170170+ </section>
171171172172- <div class="legal-section">
173173- <h2>14. Dispute Resolution</h2>
172172+ <section>
173173+ <h2 class="text-xl font-semibold text-primary">14. Dispute Resolution</h2>
174174175175 <p>Any disputes arising out of or relating to these Terms or the Service shall first be attempted to be resolved through good-faith negotiation. If negotiation fails, disputes shall be resolved through binding arbitration or in the courts of Texas, at our discretion.</p>
176176- </div>
176176+ </section>
177177178178- <div class="legal-section">
179179- <h2>15. Severability</h2>
178178+ <section>
179179+ <h2 class="text-xl font-semibold text-primary">15. Severability</h2>
180180181181 <p>If any provision of these Terms is found to be unenforceable, the remaining provisions shall remain in full force and effect.</p>
182182- </div>
182182+ </section>
183183184184- <div class="legal-section">
185185- <h2>16. Entire Agreement</h2>
184184+ <section>
185185+ <h2 class="text-xl font-semibold text-primary">16. Entire Agreement</h2>
186186187187- <p>These Terms, together with our <a href="/privacy">Privacy Policy</a>, constitute the entire agreement between you and AT Container Registry regarding your use of the Service.</p>
188188- </div>
187187+ <p>These Terms, together with our <a href="/privacy" class="link link-primary">Privacy Policy</a>, constitute the entire agreement between you and AT Container Registry regarding your use of the Service.</p>
188188+ </section>
189189190190- <div class="legal-section">
191191- <h2>Contact</h2>
190190+ <section>
191191+ <h2 class="text-xl font-semibold text-primary">Contact</h2>
192192193193 <p>For questions about these Terms, contact us at:</p>
194194195195- <p><strong>Email:</strong> <a href="mailto:legal@atcr.io">legal@atcr.io</a></p>
196196- <p><strong>Website:</strong> <a href="https://atcr.io">https://atcr.io</a></p>
197197- </div>
195195+ <p class="mt-4"><strong>Email:</strong> <a href="mailto:legal@atcr.io" class="link link-primary">legal@atcr.io</a></p>
196196+ <p><strong>Website:</strong> <a href="https://atcr.io" class="link link-primary">https://atcr.io</a></p>
197197+ </section>
198198 </div>
199199 </main>
200200