FamTown is a family home dashboard. It helps households organize shared calendars, files, notes, photos, and a collaborative townsquare.
Note: For now, registration is disabled; users must be added added manually.
make init
make setup-dev
make run-devIf you are not using make, run:
docker network inspect "${DOCKER_NETWORK_NAME:-breathnet}" >/dev/null 2>&1 || \
docker network create "${DOCKER_NETWORK_NAME:-breathnet}"
docker compose -p famtown --profile dev build
docker compose -p famtown --profile dev upAvailable at: Frontend http://localhost:3000, Backend API http://localhost:8000, API Docs http://localhost:8000/docs.
make init
make setup
make runIf you are not using make, run:
docker network inspect "${DOCKER_NETWORK_NAME:-breathnet}" >/dev/null 2>&1 || \
docker network create "${DOCKER_NETWORK_NAME:-breathnet}"
docker compose -p famtown --profile prod build
docker compose -p famtown --profile prod up -dProduction ports (from docker-compose.yml): Frontend http://localhost:8069, Backend API http://localhost:8001.
python scripts/create_user.py susan susan@example.com password123 Susan
python scripts/create_user.py sam sam@example.com password456 SamOpen http://localhost:3000 and log in with the credentials above. In production, use http://localhost:8069.
Set variables in your shell before running make or docker compose. The Docker Compose file maps
FAMTOWN_* variables into the backend and frontend containers.
Required for local/dev:
FAMTOWN_DATABASE_URL- PostgreSQL connection string used by backendFAMTOWN_JWT_SECRET_KEY- Min 32 chars (required in production)
Optional:
GEMINI_API_KEY- Enables AI image generation widgetFAMTOWN_FRONTEND_URL- CORS origin (defaults tohttp://localhost:3000)FAMTOWN_API_URL- Frontend API base (defaults to dev backend)FAMTOWN_WS_URL- Frontend WebSocket base (defaults to dev backend)FAMTOWN_UI_THEME,FAMTOWN_APP_NAME,FAMTOWN_APP_SHORT_NAME,FAMTOWN_APP_DESCRIPTION,FAMTOWN_AUTH_TOKEN_KEYDOCKER_NETWORK_NAME- External network name (defaultbreathnet)
AI image generation is disabled when GEMINI_API_KEY is not set.
- Townsquare (landing page): A fullscreen blackboard where we pin objects (events, pictures, files, texts). Every logged-in user sees the same townsquare and can modify it. We assume only one user edits at a time; live concurrent editing is not required initially.
- Navigation: Each object type has a dedicated view connected to the townsquare in four directions.
- Left: Calendar (events)
- Right: Photos (pictures)
- Down: Desk (files)
- Up: Sky (texts)
- Desktop: Navigate via subtle arrows on edges; Mobile: double-tap on corners.
- Object Relationships: Some objects (e.g., texts, pictures, events) can relate to each other, enabling aggregation and filtering in their views.
- Access Model: All objects are visible to all users; no ACLs/roles/permissions for now — an anarchistic space.
- Backend: FastAPI with async SQLAlchemy, PostgreSQL, JWT auth, WebSocket
- Frontend: React 18, Tailwind CSS, React Router, Zustand, Axios, WebSocket client
The system consists of a FastAPI backend and a React frontend. The backend serves REST APIs, handles file uploads, issues JWTs for authentication, and manages a WebSocket for real-time updates. The frontend renders the townsquare and related views, manages global state with Zustand, and keeps the UI in sync via WebSocket events.
┌─────────────────────────────────────────────────────────┐
│ Frontend │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Calendar │ │Townsquare│ │ Photos │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴─────────────┴─────────────┴─────┐ │
│ │ Navigation │ │
│ └────┬───────────────────────────────┬──┘ │
│ │ │ │
│ ┌────┴────┐ ┌─────┴─────┐ │
│ │ Zustand│ │ WebSocket │ │
│ │ Stores │ │ Client │ │
│ └────┬────┘ └─────┬─────┘ │
│ │ │ │
│ ┌────┴───────────────────────────────┴─────┐ │
│ │ API Services (Axios) │ │
│ └───────────────────┬───────────────────────┘ │
└────────────────────────┼───────────────────────────────┘
│
│ HTTP / WebSocket
│
┌────────────────────────┼───────────────────────────────┐
│ │ Backend │
│ ┌─────────────────────┴─────────────────────┐ │
│ │ FastAPI App │ │
│ └─────┬───────────────────────────┬──────────┘ │
│ │ │ │
│ ┌─────┴─────┐ ┌─────┴──────┐ │
│ │ API │ │ WebSocket │ │
│ │ Routers │ │ Manager │ │
│ └─────┬─────┘ └─────┬──────┘ │
│ │ │ │
│ ┌─────┴───────────────────────────┴──────┐ │
│ │ Services Layer │ │
│ │ (Auth, File, WebSocket) │ │
│ └─────────────────┬────────────────────────┘ │
│ │ │
│ ┌─────────────────┴────────────────────────┐ │
│ │ Database (PostgreSQL) │ │
│ │ Users, Events, Pictures, Files, Texts │ │
│ │ TownsquareItems │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
famtown/
├── backend/
│ ├── app/
│ │ ├── api/ # API routers
│ │ └── services/ # Business logic
│ ├── config.py # Configuration
│ ├── database.py # Database models
│ ├── main.py # FastAPI app
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ ├── services/ # API clients
│ │ ├── stores/ # Zustand stores
│ │ ├── hooks/ # Custom hooks
│ │ └── contexts/ # React contexts
│ └── package.json
├── scripts/
│ └── create_user.py # CLI tools
├── docker-compose.yml
├── README.md
├── SETUP.md
└── IMPLEMENTATION.md
- Database Models: User, Event, Picture, File, Text, TownsquareItem (with x, y, width, height, zIndex, rotation)
- API Routers:
auth.py,events.py,pictures.py,files.py,texts.py,townsquare.py,websocket.py - Services:
auth_service.py(JWT, password hashing),file_service.py(uploads, storage),websocket_service.py(connections, broadcast) - Features: JWT auth, static file serving, WebSocket broadcasting, automatic table creation
- Pages: Home, Townsquare, Calendar, Photos, Desk, Sky, Profile
- Components: EventCard, PictureCard, FileCard, TextCard, TownsquareObject, TownsquareCanvas, ObjectPicker, Navigation, Profile components
- Services:
api.js(Axios with auth),objectsAPI.js,townsquareAPI.js,websocket.js - State (Zustand):
useObjectsStore.js,useTownsquareStore.js,useProfileStore.js,useViewConfigStore.js - Hooks:
useWebSocket.js - Features: Real-time sync, drag-and-drop, resize, z-index control, selection, navigation, uploads with progress/preview
scripts/create_user.py: Create users from the command line
- Docker Compose setup
- Environment variables for backend and frontend
- CORS configured for local development
- Upload directory auto-creation
- Docker and Docker Compose
- Python 3.11+ (for CLI scripts)
- Node.js 18+ and npm (for local frontend development)
cd backend
pip install -r requirements.txt
python main.pycd frontend
npm install
npm startTables are auto-created on startup. For custom migrations, use backend/migrations/.
POST /api/auth/login— LoginGET /api/auth/profile— Get current userPOST /api/auth/logout— Logout
GET /api/events— List all eventsPOST /api/events— Create eventPUT /api/events/{id}— Update eventDELETE /api/events/{id}— Delete event
GET /api/pictures— List all picturesPOST /api/pictures— Upload picturePUT /api/pictures/{id}— Update captionDELETE /api/pictures/{id}— Delete picture
GET /api/files— List all filesPOST /api/files— Upload fileGET /api/files/{id}/download— Download fileDELETE /api/files/{id}— Delete file
GET /api/texts— List all textsPOST /api/texts— Create textPUT /api/texts/{id}— Update textDELETE /api/texts/{id}— Delete text
GET /api/townsquare— Get all itemsPOST /api/townsquare— Add item to townsquarePUT /api/townsquare/{id}— Update item position/sizeDELETE /api/townsquare/{id}— Remove item
WS /ws— Real-time updates connection
WebSocket events include:
object_created— New object addedobject_updated— Object modifiedobject_deleted— Object removedtownsquare_updated— Canvas item changed
- Database connection errors: Ensure PostgreSQL is running and
DATABASE_URLis correct. - WebSocket not connecting: Confirm
VITE_WS_URLmatches backend URL. - File uploads failing: Ensure the uploads directory exists and has proper permissions.
- Set
DEBUG=falsevia environment variables - Generate a secure JWT secret:
python -c 'import secrets; print(secrets.token_urlsafe(32))' - Configure proper CORS origins
- Use a production-ready database
- Configure file storage (local or cloud)
SSL/TLS is assumed to be terminated by host nginx. If you want to implement ssl inside the stack (e.g. by added a certbot docker container), feel free to fork and/or file a PR.
- Canvas fixed size may not work on very small screens
- Native drag/resize can be improved with a library
- WebSocket lacks reconnection with state recovery
- No file size limits configured
- No user permissions or ACLs
- Basic validation only
- Object relationships across views
- User registration page
- Object editing modals
- Search functionality
- Undo/redo for townsquare
- Image thumbnails
- PDF preview
- Map view
- Mobile-optimized townsquare
- Collaborative editing indicators
- Object versioning
- Export/import functionality
- Never commit environment files or API keys.
- Document secret usage and configuration in deployment notes.
- Keep CORS origins and JWT secrets configured appropriately for each environment.