Skip to content

Commit be7faa3

Browse files
heysamtexasclaude
andcommitted
refactor: migrate from Bootstrap to Tailwind CSS
Complete rewrite of all UI components from Bootstrap 5 to Tailwind CSS. This modernizes the frontend stack and removes ~600KB of dependencies. Changes: - Replace Bootstrap CDN with Tailwind Play CDN in base templates - Remove django-bootstrap5 dependency from pyproject.toml - Delete Bootstrap vendor files (CSS, JS, and Bootstrap Icons) - Convert all 21 templates to Tailwind utility classes - Replace Bootstrap JavaScript with vanilla JS for navigation/dropdowns - Implement Tailwind dark mode with class strategy - Add Heroicons SVG icons replacing Bootstrap Icons - Update site.js for Tailwind-compatible dark mode toggle - Update CLAUDE.md documentation Templates converted: - Core: base.html, _header.html, _footer.html, _alerts.html, home.html - Auth: allauth layouts and all element components (buttons, forms, fields, etc.) - Data room: upload_page.html with Uppy integration, status pages Technical details: - Using Tailwind Play CDN (no build process required) - Dark mode configured with 'class' strategy - All navigation/dropdown functionality preserved without Bootstrap JS - Responsive design maintained across all breakpoints - Form validation states and error handling converted 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent c49efdd commit be7faa3

30 files changed

+446
-6623
lines changed

CLAUDE.md

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,43 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
This is a Django Reference Implementation - a production-ready Django SaaS template with organizations, invitations, and authentication. It follows a pragmatic approach to building multi-tenant applications with minimal dependencies.
7+
This is a **Data Room Application** - a secure file upload and management system for collecting customer data files for proof-of-concept development. Built on Django with django-allauth (2FA + SSO support), it enables internal teams to provision UUID-based upload endpoints for customers while maintaining complete privacy and audit trails.
88

99
## Architecture
1010

1111
### Core Apps Structure
1212
- **config/**: Django project configuration (settings, URLs, WSGI/ASGI)
13-
- **myapp/**: Base application with site configuration models, templates, and management commands
14-
- **organizations/**: Complete multi-tenant organization system with invitations and user management
13+
- **myapp/**: Base application with site configuration models and templates
14+
- **dataroom/**: File upload system with customers, endpoints, and audit logging
15+
- **require2fa/**: Two-factor authentication enforcement middleware
1516

1617
### Key Components
17-
- **Authentication**: Uses django-allauth with 2FA support
18-
- **Async Processing**: Custom worker pattern using Django management commands with PostgreSQL as task queue
19-
- **Multi-tenancy**: Organization-based tenancy with invitation system
20-
- **Templates**: Bootstrap 5 UI with dark mode support
18+
- **Authentication**: Uses django-allauth with 2FA support and SSO-ready (Okta)
19+
- **File Management**: Local filesystem storage with UUID-based endpoint privacy
20+
- **Admin Interface**: Django admin for internal team management of customers and endpoints
21+
- **Audit Logging**: Complete tracking of file uploads, deletions, and staff downloads
22+
- **UI Framework**: Tailwind CSS via Play CDN with dark mode support and Heroicons
23+
- **Templates**: Minimal, professional upload interface with responsive design
24+
25+
## Data Room Features
26+
27+
### Customer & Endpoint Management
28+
- **Customers**: Internal tracking of companies/projects receiving upload endpoints
29+
- **Data Endpoints**: UUID-based upload URLs that don't expose customer information
30+
- **Multiple Endpoints**: Each customer can have multiple endpoints for different POCs
31+
- **Status Control**: Endpoints can be active, disabled, or archived
32+
33+
### File Upload System
34+
- **Anonymous Upload**: Customers upload via UUID URL (no authentication required)
35+
- **Security**: Filename sanitization, path traversal prevention, duplicate handling
36+
- **Soft Delete**: Customers can request deletion (immediate with audit trail)
37+
- **File Listing**: Customers can view all files uploaded to their endpoint
38+
39+
### Staff Features (Django Admin)
40+
- **Customer Management**: Create customers with freeform notes
41+
- **Endpoint Creation**: Generate new upload endpoints with one-click URL copying
42+
- **File Downloads**: Secure download with automatic audit logging
43+
- **Audit Dashboard**: View all file downloads and deletion activity
2144

2245
## Git Workflow for Claude Code
2346

@@ -87,9 +110,7 @@ uv run src/manage.py <command>
87110
# Key management commands:
88111
uv run src/manage.py migrate
89112
uv run src/manage.py createsuperuser
90-
uv run src/manage.py simple_async_worker
91-
uv run src/manage.py send_email_confirmation
92-
uv run src/manage.py send_email_invite
113+
uv run src/manage.py test
93114
```
94115

95116
### Code Quality
@@ -116,43 +137,48 @@ uv run vulture src/ --min-confidence 80 # Find unused code (high confidence)
116137
uv run vulture src/ --min-confidence 60 # Find unused code (medium confidence)
117138

118139
# Type checking
119-
cd src && DJANGO_SETTINGS_MODULE=config.settings uv run mypy organizations/ myapp/ config/ --ignore-missing-imports --disable-error-code=var-annotated
140+
cd src && DJANGO_SETTINGS_MODULE=config.settings uv run mypy dataroom/ myapp/ config/ --ignore-missing-imports --disable-error-code=var-annotated
120141
```
121142

122143
## Development Workflow
123144

124145
### Local Development
125-
- Uses Docker Compose for services (PostgreSQL, Mailpit, S3Proxy)
126-
- Django can run locally or in Docker
146+
- Uses Docker Compose for PostgreSQL and Mailpit
147+
- Django runs locally or in Docker
127148
- Environment variables configured in `env` file (copy from `env.sample`)
149+
- File uploads stored in `src/media/uploads/{endpoint-uuid}/`
128150

129151
### Testing
130-
- Tests located in `*/tests/` directories
152+
- Tests located in `*/tests.py` or `*/tests/` directories
131153
- Run with `uv run src/manage.py test`
132-
- Covers models, views, and forms
154+
- Covers models, views, upload/download functionality, and security
133155

134-
### Worker System
135-
- Custom async worker pattern using Django management commands
136-
- Workers defined in `*/management/commands/`
137-
- Uses PostgreSQL for task queue (no Redis/Celery required)
138-
- Configure workers in `docker-compose.yml`
156+
### URL Structure
157+
- **Public (No Auth)**: `/upload/{uuid}/` - Customer upload page
158+
- **Admin Only**: `/admin/` - Django admin interface
159+
- **Staff Downloads**: Via Django admin actions (with audit logging)
139160

140161
## Important Files
141162

142163
### Configuration
143164
- `src/config/settings.py`: Main Django settings
144165
- `pyproject.toml`: Project metadata and tool configuration (ruff, bandit)
145-
- `docker-compose.yml`: Development services
166+
- `docker-compose.yml`: Development services (PostgreSQL, Mailpit)
146167
- `Makefile`: Development automation commands
168+
- `env`: Environment variables (copy from `env.sample`)
147169

148170
### Models
149-
- `myapp/models/`: Site configuration and worker models
150-
- `organizations/models.py`: Organization and invitation models
171+
- `dataroom/models.py`: Customer, DataEndpoint, UploadedFile, FileDownload
172+
- `myapp/models/`: Site configuration model
173+
- `require2fa/models.py`: Two-factor configuration model
174+
175+
### Views & Templates
176+
- `dataroom/views.py`: Upload page, file upload handler, delete handler
177+
- `dataroom/templates/dataroom/`: Upload page, disabled/archived templates
178+
- `dataroom/admin.py`: Complete admin configuration with download actions
151179

152-
### Templates
153-
- `templates/`: Global templates (base, auth, pages)
154-
- `myapp/templates/`: App-specific templates
155-
- `organizations/templates/`: Organization management templates
180+
### Tests
181+
- `dataroom/tests.py`: Comprehensive model and view tests
156182

157183
## Code Standards
158184

@@ -163,10 +189,17 @@ cd src && DJANGO_SETTINGS_MODULE=config.settings uv run mypy organizations/ myap
163189

164190
### File Organization
165191
- Apps follow Django conventions
166-
- Models in `models/` directory (may be split into multiple files)
167-
- Views in `views/` directory
168-
- Management commands in `management/commands/`
192+
- Models in `models.py` or `models/` directory
193+
- Views in `views.py` or `views/` directory
169194
- Templates in `templates/` with app namespacing
195+
- Admin configurations in `admin.py`
196+
197+
### Security
198+
- **Filename Sanitization**: `sanitize_filename()` prevents path traversal
199+
- **UUID Endpoints**: No customer information exposed in URLs
200+
- **IP Tracking**: All uploads, deletes, and downloads log IP addresses
201+
- **Soft Deletes**: Files marked deleted but retained for audit
202+
- **Staff-Only Downloads**: File downloads only via authenticated admin
170203

171204
## Dependencies
172205

@@ -177,30 +210,63 @@ cd src && DJANGO_SETTINGS_MODULE=config.settings uv run mypy organizations/ myap
177210
- Install with `uv sync` or `uv sync --extra dev`
178211

179212
### Core Dependencies
180-
- Django 5.2.3
213+
- Django 5.2.5
181214
- Python 3.12
182215
- PostgreSQL 16
183-
- django-allauth (authentication)
184-
- django-bootstrap5 (UI)
185-
- django-storages (S3 support)
216+
- django-allauth (authentication with MFA and SSO support)
217+
- django-allauth-require2fa (2FA enforcement)
218+
- django-solo (singleton models)
219+
- Tailwind CSS (via Play CDN - no build process required)
220+
- Heroicons (SVG icon library)
186221

187222
### Development Dependencies
188223
- ruff (linting/formatting)
189224
- pre-commit (hooks)
225+
- mypy + django-stubs (type checking)
226+
- bandit (security scanning)
227+
- radon (complexity analysis)
228+
- vulture (dead code detection)
190229

191230
## Environment Variables
192231

193232
Key environment variables (defined in `env` file):
194233
- `DEBUG`: Development mode flag
195234
- `SECRET_KEY`: Django secret key
196-
- `BASE_URL`: Application base URL
197-
- `DATABASE_URL`: PostgreSQL connection
198-
- `AWS_*`: S3 configuration
199-
- Email settings for django-allauth
235+
- `BASE_URL`: Application base URL (used for upload URL generation)
236+
- `DATABASE_URL`: PostgreSQL connection string
237+
- `EMAIL_URL`: Email backend configuration (console, SMTP, etc.)
238+
239+
## File Storage
240+
241+
### Structure
242+
```
243+
src/media/
244+
uploads/
245+
{endpoint-uuid}/
246+
filename.ext
247+
filename-20250117143022-1.ext # Duplicate with timestamp
248+
```
249+
250+
### Handling
251+
- Files stored in MEDIA_ROOT (`src/media/`)
252+
- Organized by endpoint UUID for isolation
253+
- Duplicate filenames auto-renamed with timestamp
254+
- Soft deletes keep files on disk for audit/recovery
200255

201256
## Deployment
202257

203-
- Docker-based deployment
204-
- Heroku/Dokku ready with `Procfile`
205-
- Static files served by Django or S3
206-
- Uses environment variables for configuration
258+
- Docker-based deployment ready
259+
- Heroku/Dokku compatible with `Procfile`
260+
- Static files served via WhiteNoise
261+
- File uploads served securely via Django (for staff only)
262+
- Uses environment variables for all configuration
263+
- Database migrations handled via release phase
264+
265+
## Future Enhancements
266+
267+
- SSO integration with Okta (django-allauth is already SSO-ready)
268+
- File size limits and validation
269+
- Virus scanning integration
270+
- Automated file expiration/archival
271+
- Email notifications for uploads
272+
- Download links for customers (with expiration)

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ dependencies = [
1717
"charset-normalizer==3.4.3",
1818
"django-environ==0.12.0",
1919
"Django==5.2.5",
20-
"django-bootstrap5==25.2",
2120
"django-solo==2.4.0",
2221
"gunicorn==23.0.0",
2322
"idna==3.10",

src/config/settings.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@
2525

2626
CSRF_TRUSTED_ORIGINS = [BASE_URL]
2727

28-
# CONFIGURATION for django-storages
29-
AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID")
30-
AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY")
31-
AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME")
32-
AWS_S3_REGION_NAME = env("AWS_S3_REGION_NAME")
33-
AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL")
34-
AWS_S3_USE_SSL = env("AWS_S3_USE_SSL")
35-
3628
ALLOWED_HOSTS = ["*"]
3729

3830
INSTALLED_APPS = [
@@ -43,8 +35,7 @@
4335
"django.contrib.messages",
4436
"django.contrib.staticfiles",
4537
"django.contrib.sites",
46-
"django_bootstrap5",
47-
"organizations",
38+
"dataroom",
4839
"myapp",
4940
"require2fa",
5041
"allauth",

src/dataroom/templates/dataroom/upload_archived.html

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,15 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Upload Archived</title>
7-
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
8-
<style>
9-
body {
10-
background-color: #f8f9fa;
11-
display: flex;
12-
align-items: center;
13-
justify-content: center;
14-
min-height: 100vh;
15-
}
16-
.message-box {
17-
max-width: 600px;
18-
background: white;
19-
border-radius: 8px;
20-
padding: 40px;
21-
text-align: center;
22-
}
23-
</style>
7+
<script src="https://cdn.tailwindcss.com"></script>
248
</head>
25-
<body>
26-
<div class="message-box">
27-
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="currentColor" class="bi bi-archive text-secondary mb-3" viewBox="0 0 16 16">
28-
<path d="M0 2a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1v7.5a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 1 12.5V5a1 1 0 0 1-1-1zm2 3v7.5A1.5 1.5 0 0 0 3.5 14h9a1.5 1.5 0 0 0 1.5-1.5V5zm13-3H1v2h14zM5 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5"/>
9+
<body class="bg-gray-100 dark:bg-gray-900 flex items-center justify-center min-h-screen">
10+
<div class="max-w-2xl bg-white dark:bg-gray-800 rounded-lg shadow-lg p-12 text-center">
11+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-16 h-16 mx-auto text-gray-500 dark:text-gray-400 mb-6">
12+
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" />
2913
</svg>
30-
<h2 class="mb-3">Upload Archived</h2>
31-
<p class="text-muted">This upload endpoint has been archived and is no longer accepting files. Please contact your administrator if you need assistance.</p>
14+
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-4">Upload Archived</h2>
15+
<p class="text-gray-600 dark:text-gray-300">This upload endpoint has been archived and is no longer accepting files. Please contact your administrator if you need assistance.</p>
3216
</div>
3317
</body>
3418
</html>

src/dataroom/templates/dataroom/upload_disabled.html

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,15 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Upload Disabled</title>
7-
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
8-
<style>
9-
body {
10-
background-color: #f8f9fa;
11-
display: flex;
12-
align-items: center;
13-
justify-content: center;
14-
min-height: 100vh;
15-
}
16-
.message-box {
17-
max-width: 600px;
18-
background: white;
19-
border-radius: 8px;
20-
padding: 40px;
21-
text-align: center;
22-
}
23-
</style>
7+
<script src="https://cdn.tailwindcss.com"></script>
248
</head>
25-
<body>
26-
<div class="message-box">
27-
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="currentColor" class="bi bi-x-circle text-warning mb-3" viewBox="0 0 16 16">
28-
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
29-
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
9+
<body class="bg-gray-100 dark:bg-gray-900 flex items-center justify-center min-h-screen">
10+
<div class="max-w-2xl bg-white dark:bg-gray-800 rounded-lg shadow-lg p-12 text-center">
11+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-16 h-16 mx-auto text-yellow-500 mb-6">
12+
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
3013
</svg>
31-
<h2 class="mb-3">Upload Disabled</h2>
32-
<p class="text-muted">This upload endpoint has been temporarily disabled. Please contact your administrator for more information.</p>
14+
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-4">Upload Disabled</h2>
15+
<p class="text-gray-600 dark:text-gray-300">This upload endpoint has been temporarily disabled. Please contact your administrator for more information.</p>
3316
</div>
3417
</body>
3518
</html>

0 commit comments

Comments
 (0)